/*===========================================================================* * do_semget * *===========================================================================*/ PUBLIC int do_semget(message *m) { key_t key; int nsems, flag, id; struct sem_struct *sem; key = m->SEMGET_KEY; nsems = m->SEMGET_NR; flag = m->SEMGET_FLAG; if ((sem = sem_find_key(key))) { if ((flag & IPC_CREAT) && (flag & IPC_EXCL)) return EEXIST; if (!check_perm(&sem->semid_ds.sem_perm, who_e, flag)) return EACCES; if (nsems > sem->semid_ds.sem_nsems) return EINVAL; id = sem->id; } else { if (!(flag & IPC_CREAT)) return ENOENT; if (nsems < 0 || nsems >= SEMMSL) return EINVAL; if (sem_list_nr == SEMMNI) return ENOSPC; /* create a new semaphore set */ sem = &sem_list[sem_list_nr]; memset(sem, 0, sizeof(struct sem_struct)); sem->semid_ds.sem_perm.cuid = sem->semid_ds.sem_perm.uid = getnuid(who_e); sem->semid_ds.sem_perm.cgid = sem->semid_ds.sem_perm.gid = getngid(who_e); sem->semid_ds.sem_perm.mode = flag & 0777; sem->semid_ds.sem_nsems = nsems; sem->semid_ds.sem_otime = 0; sem->semid_ds.sem_ctime = time(NULL); sem->id = id = identifier++; sem->key = key; sem_list_nr++; } m->SEMGET_RETID = id; return OK; }
int main(int argc, char *argv[]) { int r, i; struct tm t; endpoint_t user, caller; message m; int ipc_status, reply_status; env_setargs(argc, argv); r = i2cdriver_env_parse(&bus, &addresses[0], valid_addrs); if (r < 0) { log_warn(&log, "Expecting -args 'bus=X address=0xYY'\n"); log_warn(&log, "Example -args 'bus=1 address=0x48'\n"); return EXIT_FAILURE; } else if (r > 0) { log_warn(&log, "Invalid slave address for device, expecting 0x48\n"); return EXIT_FAILURE; } sef_local_startup(); while (TRUE) { /* Receive Message */ r = sef_receive_status(ANY, &m, &ipc_status); if (r != OK) { log_warn(&log, "sef_receive_status() failed\n"); continue; } if (is_ipc_notify(ipc_status)) { if (m.m_source == DS_PROC_NR) { for (i = 0; i < NADDRESSES; i++) { /* changed state, update endpoint */ i2cdriver_handle_bus_update (&bus_endpoint, bus, addresses[i]); } } /* Do not reply to notifications. */ continue; } caller = m.m_source; log_debug(&log, "Got message 0x%x from 0x%x\n", m.m_type, caller); switch (m.m_type) { case RTCDEV_GET_TIME_G: /* Any user can read the time */ reply_status = rtc_get_time(&t, m.RTCDEV_FLAGS); if (reply_status != OK) { break; } /* write results back to calling process */ reply_status = store_t(caller, (cp_grant_id_t) m.RTCDEV_GRANT, &t); break; case RTCDEV_SET_TIME_G: /* Only super user is allowed to set the time */ if (getnuid(caller) == SUPER_USER) { /* read time from calling process */ reply_status = fetch_t(caller, (cp_grant_id_t) m.RTCDEV_GRANT, &t); if (reply_status != OK) { break; } reply_status = rtc_set_time(&t, m.RTCDEV_FLAGS); } else { reply_status = EPERM; } break; case RTCDEV_PWR_OFF: reply_status = ENOSYS; break; default: /* Unrecognized call */ reply_status = EINVAL; break; } /* Send Reply */ m.m_type = RTCDEV_REPLY; m.RTCDEV_STATUS = reply_status; log_debug(&log, "Sending Reply"); r = sendnb(caller, &m); if (r != OK) { log_warn(&log, "sendnb() failed\n"); continue; } } rtc_exit(); return 0; }
/*===========================================================================* * do_shmget * *===========================================================================*/ PUBLIC int do_shmget(message *m) { struct shm_struct *shm; long key, size, old_size; int flag; int id; key = m->SHMGET_KEY; old_size = size = m->SHMGET_SIZE; flag = m->SHMGET_FLAG; if ((shm = shm_find_key(key))) { if (!check_perm(&shm->shmid_ds.shm_perm, who_e, flag)) return EACCES; if ((flag & IPC_CREAT) && (flag & IPC_EXCL)) return EEXIST; if (size && shm->shmid_ds.shm_segsz < size) return EINVAL; id = shm->id; } else { /* no key found */ if (!(flag & IPC_CREAT)) return ENOENT; if (size <= 0) return EINVAL; /* round up to a multiple of PAGE_SIZE */ if (size % I386_PAGE_SIZE) size += I386_PAGE_SIZE - size % I386_PAGE_SIZE; if (size <= 0) return EINVAL; if (shm_list_nr == MAX_SHM_NR) return ENOMEM; /* TODO: shmmni should be changed... */ if (identifier == SHMMNI) return ENOSPC; shm = &shm_list[shm_list_nr]; memset(shm, 0, sizeof(struct shm_struct)); shm->page = (vir_bytes) mmap(0, size, PROT_READ|PROT_WRITE, MAP_CONTIG|MAP_PREALLOC|MAP_ANON|MAP_SHARED, -1, 0); if (shm->page == (vir_bytes) MAP_FAILED) return ENOMEM; shm->phys = vm_getphys(SELF_E, (void *) shm->page); memset((void *)shm->page, 0, size); shm->shmid_ds.shm_perm.cuid = shm->shmid_ds.shm_perm.uid = getnuid(who_e); shm->shmid_ds.shm_perm.cgid = shm->shmid_ds.shm_perm.gid = getngid(who_e); shm->shmid_ds.shm_perm.mode = flag & 0777; shm->shmid_ds.shm_segsz = old_size; shm->shmid_ds.shm_atime = 0; shm->shmid_ds.shm_dtime = 0; shm->shmid_ds.shm_ctime = time(NULL); shm->shmid_ds.shm_cpid = getnpid(who_e); shm->shmid_ds.shm_lpid = 0; shm->shmid_ds.shm_nattch = 0; shm->id = id = identifier++; shm->key = key; shm_list_nr++; } m->SHMGET_RETID = id; 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; }
/*===========================================================================* * do_semctl * *===========================================================================*/ PUBLIC int do_semctl(message *m) { int r, i; long opt; uid_t uid; int id, num, cmd, val; unsigned short *buf; struct semid_ds *ds, tmp_ds; struct sem_struct *sem; id = m->SEMCTL_ID; num = m->SEMCTL_NUM; cmd = m->SEMCTL_CMD; if (cmd == IPC_STAT || cmd == IPC_SET || cmd == IPC_INFO || cmd == SEM_INFO || cmd == SEM_STAT || cmd == GETALL || cmd == SETALL || cmd == SETVAL) opt = m->SEMCTL_OPT; if (!(sem = sem_find_id(id))) { return EINVAL; } /* IPC_SET and IPC_RMID as its own permission check */ if (cmd != IPC_SET && cmd != IPC_RMID) { /* check read permission */ if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0444)) return EACCES; } switch (cmd) { case IPC_STAT: ds = (struct semid_ds *) opt; if (!ds) return EFAULT; r = sys_datacopy(SELF_E, (vir_bytes) &sem->semid_ds, who_e, (vir_bytes) ds, sizeof(struct semid_ds)); if (r != OK) return EINVAL; break; case IPC_SET: uid = getnuid(who_e); if (uid != sem->semid_ds.sem_perm.cuid && uid != sem->semid_ds.sem_perm.uid && uid != 0) return EPERM; ds = (struct semid_ds *) opt; r = sys_datacopy(who_e, (vir_bytes) ds, SELF_E, (vir_bytes) &tmp_ds, sizeof(struct semid_ds)); if (r != OK) return EINVAL; sem->semid_ds.sem_perm.uid = tmp_ds.sem_perm.uid; sem->semid_ds.sem_perm.gid = tmp_ds.sem_perm.gid; sem->semid_ds.sem_perm.mode &= ~0777; sem->semid_ds.sem_perm.mode |= tmp_ds.sem_perm.mode & 0666; sem->semid_ds.sem_ctime = time(NULL); break; case IPC_RMID: uid = getnuid(who_e); if (uid != sem->semid_ds.sem_perm.cuid && uid != sem->semid_ds.sem_perm.uid && uid != 0) return EPERM; /* awaken all processes block in semop * and remove the semaphore set. */ update_one_semaphore(sem, 1); break; case IPC_INFO: break; case SEM_INFO: break; case SEM_STAT: break; case GETALL: buf = malloc(sizeof(unsigned short) * sem->semid_ds.sem_nsems); if (!buf) return ENOMEM; for (i = 0; i < sem->semid_ds.sem_nsems; i++) buf[i] = sem->sems[i].semval; r = sys_datacopy(SELF_E, (vir_bytes) buf, who_e, (vir_bytes) opt, sizeof(unsigned short) * sem->semid_ds.sem_nsems); if (r != OK) return EINVAL; free(buf); break; case GETNCNT: if (num < 0 || num >= sem->semid_ds.sem_nsems) return EINVAL; m->SHMCTL_RET = sem->sems[num].semncnt; break; case GETPID: if (num < 0 || num >= sem->semid_ds.sem_nsems) return EINVAL; m->SHMCTL_RET = sem->sems[num].sempid; break; case GETVAL: if (num < 0 || num >= sem->semid_ds.sem_nsems) return EINVAL; m->SHMCTL_RET = sem->sems[num].semval; break; case GETZCNT: if (num < 0 || num >= sem->semid_ds.sem_nsems) return EINVAL; m->SHMCTL_RET = sem->sems[num].semzcnt; break; case SETALL: buf = malloc(sizeof(unsigned short) * sem->semid_ds.sem_nsems); if (!buf) return ENOMEM; r = sys_datacopy(who_e, (vir_bytes) opt, SELF_E, (vir_bytes) buf, sizeof(unsigned short) * sem->semid_ds.sem_nsems); if (r != OK) return EINVAL; #ifdef DEBUG_SEM printf("SEMCTL: SETALL: opt: %p\n"); for (i = 0; i < sem->semid_ds.sem_nsems; i++) printf("SEMCTL: SETALL val: [%d] %d\n", i, buf[i]); #endif for (i = 0; i < sem->semid_ds.sem_nsems; i++) { if (buf[i] < 0 || buf[i] > SEMVMX) { free(buf); update_semaphores(); return ERANGE; } sem->sems[i].semval = buf[i]; } free(buf); /* awaken if possible */ update_semaphores(); break; case SETVAL: val = (int) opt; /* check write permission */ if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0222)) return EACCES; if (num < 0 || num >= sem->semid_ds.sem_nsems) return EINVAL; if (val < 0 || val > SEMVMX) return ERANGE; sem->sems[num].semval = val; #ifdef DEBUG_SEM printf("SEMCTL: SETVAL: %d %d\n", num, val); #endif sem->semid_ds.sem_ctime = time(NULL); /* awaken if possible */ update_semaphores(); break; default: return EINVAL; } return OK; }
int main(int argc, char **argv) { int r; endpoint_t caller; struct tm t; message m; int ipc_status, reply_status; env_setargs(argc, argv); sef_local_startup(); while (TRUE) { /* Receive Message */ r = sef_receive_status(ANY, &m, &ipc_status); if (r != OK) { log_warn(&log, "sef_receive_status() failed\n"); continue; } if (is_ipc_notify(ipc_status)) { /* Do not reply to notifications. */ continue; } caller = m.m_source; log_debug(&log, "Got message 0x%x from 0x%x\n", m.m_type, caller); switch (m.m_type) { case RTCDEV_GET_TIME: /* Any user can read the time */ reply_status = rtc.get_time(&t, m.m_lc_readclock_rtcdev.flags); if (reply_status != OK) { break; } /* write results back to calling process */ reply_status = store_t(caller, m.m_lc_readclock_rtcdev.tm, &t); break; case RTCDEV_SET_TIME: /* Only super user is allowed to set the time */ if (getnuid(caller) == SUPER_USER) { /* read time from calling process */ reply_status = fetch_t(caller, m.m_lc_readclock_rtcdev.tm, &t); if (reply_status != OK) { break; } reply_status = rtc.set_time(&t, m.m_lc_readclock_rtcdev.flags); } else { reply_status = EPERM; } break; case RTCDEV_PWR_OFF: /* Only PM is allowed to set the power off time */ if (caller == PM_PROC_NR) { reply_status = rtc.pwr_off(); } else { reply_status = EPERM; } break; default: /* Unrecognized call */ reply_status = EINVAL; break; } /* Send Reply */ m.m_type = RTCDEV_REPLY; m.m_readclock_lc_rtcdev.status = reply_status; log_debug(&log, "Sending Reply"); r = ipc_sendnb(caller, &m); if (r != OK) { log_warn(&log, "ipc_sendnb() failed\n"); continue; } } rtc.exit(); return 0; }