/*===========================================================================* * do_shmat * *===========================================================================*/ PUBLIC int do_shmat(message *m) { int id, flag; vir_bytes addr; void *ret; struct shm_struct *shm; id = m->SHMAT_ID; addr = (vir_bytes) m->SHMAT_ADDR; flag = m->SHMAT_FLAG; if (addr && (addr % I386_PAGE_SIZE)) { if (flag & SHM_RND) addr -= (addr % I386_PAGE_SIZE); else return EINVAL; } if (!(shm = shm_find_id(id))) return EINVAL; if (flag & SHM_RDONLY) flag = 0444; else flag = 0666; if (!check_perm(&shm->shmid_ds.shm_perm, who_e, flag)) return EACCES; ret = vm_remap(who_e, SELF_E, (void *)addr, (void *)shm->page, shm->shmid_ds.shm_segsz); if (ret == MAP_FAILED) return ENOMEM; shm->shmid_ds.shm_atime = time(NULL); shm->shmid_ds.shm_lpid = getnpid(who_e); /* nattach is updated lazily */ m->SHMAT_RETADDR = (long) ret; return OK; }
/*===========================================================================* * do_shmat * *===========================================================================*/ int do_shmat(message *m) { int id, flag; vir_bytes addr; void *ret; struct shm_struct *shm; id = m->m_lc_ipc_shmat.id; addr = (vir_bytes) m->m_lc_ipc_shmat.addr; flag = m->m_lc_ipc_shmat.flag; if (addr && (addr % PAGE_SIZE)) { if (flag & SHM_RND) addr -= (addr % PAGE_SIZE); else return EINVAL; } if (!(shm = shm_find_id(id))) return EINVAL; if (flag & SHM_RDONLY) flag = 0444; else flag = 0666; if (!check_perm(&shm->shmid_ds.shm_perm, who_e, flag)) return EACCES; ret = vm_remap(who_e, sef_self(), (void *)addr, (void *)shm->page, shm->shmid_ds.shm_segsz); if (ret == MAP_FAILED) return ENOMEM; shm->shmid_ds.shm_atime = time(NULL); shm->shmid_ds.shm_lpid = getnpid(who_e); /* nattach is updated lazily */ m->m_lc_ipc_shmat.retaddr = ret; return OK; }
/*===========================================================================* * do_shmctl * *===========================================================================*/ PUBLIC int do_shmctl(message *m) { int id = m->SHMCTL_ID; int cmd = m->SHMCTL_CMD; struct shmid_ds *ds = (struct shmid_ds *)m->SHMCTL_BUF; struct shmid_ds tmp_ds; struct shm_struct *shm; struct shminfo sinfo; struct shm_info s_info; uid_t uid; int r, i; if (cmd == IPC_STAT) update_refcount_and_destroy(); if ((cmd == IPC_STAT || cmd == IPC_SET || cmd == IPC_RMID) && !(shm = shm_find_id(id))) return EINVAL; switch (cmd) { case IPC_STAT: if (!ds) return EFAULT; /* check whether it has read permission */ if (!check_perm(&shm->shmid_ds.shm_perm, who_e, 0444)) return EACCES; r = sys_datacopy(SELF_E, (vir_bytes)&shm->shmid_ds, who_e, (vir_bytes)ds, sizeof(struct shmid_ds)); if (r != OK) return EFAULT; break; case IPC_SET: uid = getnuid(who_e); if (uid != shm->shmid_ds.shm_perm.cuid && uid != shm->shmid_ds.shm_perm.uid && uid != 0) return EPERM; r = sys_datacopy(who_e, (vir_bytes)ds, SELF_E, (vir_bytes)&tmp_ds, sizeof(struct shmid_ds)); if (r != OK) return EFAULT; shm->shmid_ds.shm_perm.uid = tmp_ds.shm_perm.uid; shm->shmid_ds.shm_perm.gid = tmp_ds.shm_perm.gid; shm->shmid_ds.shm_perm.mode &= ~0777; shm->shmid_ds.shm_perm.mode |= tmp_ds.shm_perm.mode & 0666; shm->shmid_ds.shm_ctime = time(NULL); break; case IPC_RMID: uid = getnuid(who_e); if (uid != shm->shmid_ds.shm_perm.cuid && uid != shm->shmid_ds.shm_perm.uid && uid != 0) return EPERM; shm->shmid_ds.shm_perm.mode |= SHM_DEST; /* destroy if possible */ update_refcount_and_destroy(); break; case IPC_INFO: if (!ds) return EFAULT; sinfo.shmmax = (unsigned long) -1; sinfo.shmmin = 1; sinfo.shmmni = MAX_SHM_NR; sinfo.shmseg = (unsigned long) -1; sinfo.shmall = (unsigned long) -1; r = sys_datacopy(SELF_E, (vir_bytes)&sinfo, who_e, (vir_bytes)ds, sizeof(struct shminfo)); if (r != OK) return EFAULT; m->SHMCTL_RET = shm_list_nr - 1; if (m->SHMCTL_RET < 0) m->SHMCTL_RET = 0; break; case SHM_INFO: if (!ds) return EFAULT; s_info.used_ids = shm_list_nr; s_info.shm_tot = 0; for (i = 0; i < shm_list_nr; i++) s_info.shm_tot += shm_list[i].shmid_ds.shm_segsz/I386_PAGE_SIZE; s_info.shm_rss = s_info.shm_tot; s_info.shm_swp = 0; s_info.swap_attempts = 0; s_info.swap_successes = 0; r = sys_datacopy(SELF_E, (vir_bytes)&s_info, who_e, (vir_bytes)ds, sizeof(struct shm_info)); if (r != OK) return EFAULT; m->SHMCTL_RET = shm_list_nr - 1; if (m->SHMCTL_RET < 0) m->SHMCTL_RET = 0; break; case SHM_STAT: if (id < 0 || id >= shm_list_nr) return EINVAL; shm = &shm_list[id]; r = sys_datacopy(SELF_E, (vir_bytes)&shm->shmid_ds, who_e, (vir_bytes)ds, sizeof(struct shmid_ds)); if (r != OK) return EFAULT; m->SHMCTL_RET = shm->id; break; default: return EINVAL; } return OK; }