github.com/afumu/libc@v0.0.6/musl/src/ipc/semctl.c (about)

     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  
    11  union semun {
    12  	int val;
    13  	struct semid_ds *buf;
    14  	unsigned short *array;
    15  };
    16  
    17  int 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  }