master
 1#include <sys/sem.h>
 2#include <stdarg.h>
 3#include <endian.h>
 4#include "syscall.h"
 5#include "ipc.h"
 6
 7#if __BYTE_ORDER != __BIG_ENDIAN
 8#undef SYSCALL_IPC_BROKEN_MODE
 9#endif
10
11union semun {
12	int val;
13	struct semid_ds *buf;
14	unsigned short *array;
15};
16
17int semctl(int id, int num, int cmd, ...)
18{
19	union semun arg = {0};
20	va_list ap;
21	switch (cmd & ~IPC_TIME64) {
22	case SETVAL: case GETALL: case SETALL: case IPC_SET:
23	case IPC_INFO: case SEM_INFO:
24	case IPC_STAT & ~IPC_TIME64:
25	case SEM_STAT & ~IPC_TIME64:
26	case SEM_STAT_ANY & ~IPC_TIME64:
27		va_start(ap, cmd);
28		arg = va_arg(ap, union semun);
29		va_end(ap);
30	}
31#if IPC_TIME64
32	struct semid_ds out, *orig;
33	if (cmd&IPC_TIME64) {
34		out = (struct semid_ds){0};
35		orig = arg.buf;
36		arg.buf = &out;
37	}
38#endif
39#ifdef SYSCALL_IPC_BROKEN_MODE
40	struct semid_ds tmp;
41	if (cmd == IPC_SET) {
42		tmp = *arg.buf;
43		tmp.sem_perm.mode *= 0x10000U;
44		arg.buf = &tmp;
45	}
46#endif
47#ifndef SYS_ipc
48	int r = __syscall(SYS_semctl, id, num, IPC_CMD(cmd), arg.buf);
49#else
50	int r = __syscall(SYS_ipc, IPCOP_semctl, id, num, IPC_CMD(cmd), &arg.buf);
51#endif
52#ifdef SYSCALL_IPC_BROKEN_MODE
53	if (r >= 0) switch (cmd | IPC_TIME64) {
54	case IPC_STAT:
55	case SEM_STAT:
56	case SEM_STAT_ANY:
57		arg.buf->sem_perm.mode >>= 16;
58	}
59#endif
60#if IPC_TIME64
61	if (r >= 0 && (cmd&IPC_TIME64)) {
62		arg.buf = orig;
63		*arg.buf = out;
64		IPC_HILO(arg.buf, sem_otime);
65		IPC_HILO(arg.buf, sem_ctime);
66	}
67#endif
68	return __syscall_ret(r);
69}