From: Stacey Son <[email protected]> Add implementation of __semctl(2) syscall for System V semaphore control operations. Handles command translation, endianness conversion for GETVAL/ SETVAL, and array/structure conversions for GETALL/SETALL/IPC_STAT/IPC_SET.
Signed-off-by: Stacey Son <[email protected]> Signed-off-by: Warner Losh <[email protected]> --- bsd-user/bsd-misc.h | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/bsd-user/bsd-misc.h b/bsd-user/bsd-misc.h index cba0b2ec92..d3ce01a2a3 100644 --- a/bsd-user/bsd-misc.h +++ b/bsd-user/bsd-misc.h @@ -106,6 +106,121 @@ static inline abi_long do_bsd_semop(int semid, abi_long ptr, unsigned nsops) return semop(semid, sops, nsops); } +/* __semctl(2) */ +static inline abi_long do_bsd___semctl(int semid, int semnum, int target_cmd, + abi_ptr un_ptr) +{ + void *target_un; + union semun arg; + struct semid_ds dsarg; + unsigned short *array = NULL; + int host_cmd; + abi_long ret = 0; + abi_long err; + abi_ulong target_array, target_buffer; + + switch (target_cmd) { + case TARGET_GETVAL: + host_cmd = GETVAL; + break; + + case TARGET_SETVAL: + host_cmd = SETVAL; + break; + + case TARGET_GETALL: + host_cmd = GETALL; + break; + + case TARGET_SETALL: + host_cmd = SETALL; + break; + + case TARGET_IPC_STAT: + host_cmd = IPC_STAT; + break; + + case TARGET_IPC_SET: + host_cmd = IPC_SET; + break; + + case TARGET_IPC_RMID: + host_cmd = IPC_RMID; + break; + + case TARGET_GETPID: + host_cmd = GETPID; + break; + + case TARGET_GETNCNT: + host_cmd = GETNCNT; + break; + + case TARGET_GETZCNT: + host_cmd = GETZCNT; + break; + + default: + return -TARGET_EINVAL; + } + + /* + * Unlike Linux and the semctl system call, we take a pointer + * to the union arg here. + */ + target_un = lock_user(VERIFY_READ, un_ptr, sizeof(union target_semun), 0); + + switch (host_cmd) { + case GETVAL: + case SETVAL: + __get_user(arg.val, (abi_int *)target_un); + ret = get_errno(semctl(semid, semnum, host_cmd, arg)); + break; + + case GETALL: + case SETALL: + __get_user(target_array, (abi_ulong *)target_un); + err = target_to_host_semarray(semid, &array, target_array); + if (is_error(err)) { + return err; + } + arg.array = array; + ret = get_errno(semctl(semid, semnum, host_cmd, arg)); + err = host_to_target_semarray(semid, target_array, &array); + if (is_error(err)) { + return err; + } + break; + + case IPC_STAT: + case IPC_SET: + __get_user(target_buffer, (abi_ulong *)target_un); + err = target_to_host_semid_ds(&dsarg, target_buffer); + if (is_error(err)) { + return err; + } + arg.buf = &dsarg; + ret = get_errno(semctl(semid, semnum, host_cmd, arg)); + err = host_to_target_semid_ds(target_buffer, &dsarg); + if (is_error(err)) { + return err; + } + break; + + case IPC_RMID: + case GETPID: + case GETNCNT: + case GETZCNT: + ret = get_errno(semctl(semid, semnum, host_cmd, NULL)); + break; + + default: + ret = -TARGET_EINVAL; + break; + } + return ret; +} + /* getdtablesize(2) */ static inline abi_long do_bsd_getdtablesize(void) { -- 2.52.0
