int linux_semctl(struct thread *td, struct linux_semctl_args *args) { struct l_semid_ds linux_semid; struct l_seminfo linux_seminfo; struct semid_ds semid; union semun semun; register_t rval; int cmd, error; switch (args->cmd & ~LINUX_IPC_64) { case LINUX_IPC_RMID: cmd = IPC_RMID; break; case LINUX_GETNCNT: cmd = GETNCNT; break; case LINUX_GETPID: cmd = GETPID; break; case LINUX_GETVAL: cmd = GETVAL; break; case LINUX_GETZCNT: cmd = GETZCNT; break; case LINUX_SETVAL: cmd = SETVAL; semun.val = args->arg.val; break; case LINUX_IPC_SET: cmd = IPC_SET; error = linux_semid_pullup(args->cmd & LINUX_IPC_64, &linux_semid, PTRIN(args->arg.buf)); if (error) return (error); linux_to_bsd_semid_ds(&linux_semid, &semid); semun.buf = &semid; return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, td->td_retval)); case LINUX_IPC_STAT: case LINUX_SEM_STAT: if ((args->cmd & ~LINUX_IPC_64) == LINUX_IPC_STAT) cmd = IPC_STAT; else cmd = SEM_STAT; semun.buf = &semid; error = kern_semctl(td, args->semid, args->semnum, cmd, &semun, &rval); if (error) return (error); bsd_to_linux_semid_ds(&semid, &linux_semid); error = linux_semid_pushdown(args->cmd & LINUX_IPC_64, &linux_semid, PTRIN(args->arg.buf)); if (error == 0) td->td_retval[0] = (cmd == SEM_STAT) ? rval : 0; return (error); case LINUX_IPC_INFO: case LINUX_SEM_INFO: bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) ); /* XXX BSD equivalent? #define used_semids 10 #define used_sems 10 linux_seminfo.semusz = used_semids; linux_seminfo.semaem = used_sems; */ error = copyout(&linux_seminfo, PTRIN(args->arg.buf), sizeof(linux_seminfo)); if (error) return error; td->td_retval[0] = seminfo.semmni; return 0; /* No need for __semctl call */ case LINUX_GETALL: cmd = GETALL; semun.val = args->arg.val; break; case LINUX_SETALL: cmd = SETALL; semun.val = args->arg.val; break; default: linux_msg(td, "ipc type %d is not implemented", args->cmd & ~LINUX_IPC_64); return EINVAL; } return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, td->td_retval)); }
int linux_semctl(struct thread *td, struct linux_semctl_args *args) { struct l_semid_ds linux_semid; struct l_seminfo linux_seminfo; struct semid_ds semid; union semun semun; register_t rval; int cmd, error; switch (args->cmd & ~LINUX_IPC_64) { case LINUX_IPC_RMID: cmd = IPC_RMID; break; case LINUX_GETNCNT: cmd = GETNCNT; break; case LINUX_GETPID: cmd = GETPID; break; case LINUX_GETVAL: cmd = GETVAL; break; case LINUX_GETZCNT: cmd = GETZCNT; break; case LINUX_SETVAL: cmd = SETVAL; semun.val = args->arg.val; break; case LINUX_IPC_SET: cmd = IPC_SET; error = linux_semid_pullup(args->cmd & LINUX_IPC_64, &linux_semid, PTRIN(args->arg.buf)); if (error) return (error); linux_to_bsd_semid_ds(&linux_semid, &semid); semun.buf = &semid; return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, td->td_retval)); case LINUX_IPC_STAT: case LINUX_SEM_STAT: if ((args->cmd & ~LINUX_IPC_64) == LINUX_IPC_STAT) cmd = IPC_STAT; else cmd = SEM_STAT; semun.buf = &semid; error = kern_semctl(td, args->semid, args->semnum, cmd, &semun, &rval); if (error) return (error); bsd_to_linux_semid_ds(&semid, &linux_semid); error = linux_semid_pushdown(args->cmd & LINUX_IPC_64, &linux_semid, PTRIN(args->arg.buf)); if (error == 0) td->td_retval[0] = (cmd == SEM_STAT) ? rval : 0; return (error); case LINUX_IPC_INFO: case LINUX_SEM_INFO: bcopy(&seminfo, &linux_seminfo.semmni, sizeof(linux_seminfo) - sizeof(linux_seminfo.semmap) ); /* * Linux does not use the semmap field but populates it with * the defined value from SEMMAP, which really is redefined to * SEMMNS, which they define as SEMMNI * SEMMSL. Try to * simulate this returning our dynamic semmns value. */ linux_seminfo.semmap = linux_seminfo.semmns; /* XXX BSD equivalent? #define used_semids 10 #define used_sems 10 linux_seminfo.semusz = used_semids; linux_seminfo.semaem = used_sems; */ error = copyout(&linux_seminfo, PTRIN(args->arg.buf), sizeof(linux_seminfo)); if (error) return (error); td->td_retval[0] = seminfo.semmni; return (0); /* No need for __semctl call */ case LINUX_GETALL: cmd = GETALL; semun.val = args->arg.val; break; case LINUX_SETALL: cmd = SETALL; semun.val = args->arg.val; break; default: linux_msg(td, "ipc type %d is not implemented", args->cmd & ~LINUX_IPC_64); return (EINVAL); } return (kern_semctl(td, args->semid, args->semnum, cmd, &semun, td->td_retval)); }