]> git.saurik.com Git - apple/libc.git/blobdiff - sys/semctl.c
Libc-498.1.5.tar.gz
[apple/libc.git] / sys / semctl.c
index d6d599b0ace09dd153b1d1ec794f0f4c1adc30f6..77d5ab0f5bbd2075ca188efba7da7a7dbb7784aa 100644 (file)
 #include <unistd.h>
 #include <stdarg.h>
 #include <sys/sem.h>
-#include <sys/syscall.h>
+
+#if !__DARWIN_UNIX03
+#include <errno.h>
+/*
+ * Because KERNEL is defined, including errno.h doesn't define errno, so
+ * we have to do it ourselves.
+ */
+extern int * __error(void);
+#define errno (*__error())
+#endif /* !__DARWIN_UNIX03 */
 
 /*
  * Stub function to account for the differences in the ipc_perm structure,
  * while maintaining binary backward compatibility.
  */
+extern int __semctl(int semid, int semnum, int cmd, void *);
+
 int
 semctl(int semid, int semnum, int cmd, ...)
 {
-#ifdef __DARWIN_UNIX03
        va_list                 ap;
+       int                     rv;
+       int                     val = 0;
+#if __DARWIN_UNIX03
        struct __semid_ds_new   *ds;
 
        va_start(ap, cmd);
-       ds = va_arg(ap, struct __semid_ds_new *);
+       if (cmd == SETVAL) {
+               val = va_arg(ap, int);
+               rv = __semctl(semid, semnum, cmd, (void *)val);
+       } else {
+               ds = va_arg(ap, struct __semid_ds_new *);
+               rv = __semctl(semid, semnum, cmd, (void *)ds);
+       }
        va_end(ap);
 
-       return syscall(SYS_semctl, semid, semnum, cmd, ds);
+       return rv;
 #else  /* !__DARWIN_UNIX03 */
-       va_list                 ap;
-       struct __semid_ds_old   *ds_old;
        struct __semid_ds_new   ds;
        struct __semid_ds_new   *ds_new = &ds;
-       int                     rv;
+       struct __semid_ds_old   *ds_old = NULL;
 
        va_start(ap, cmd);
-       ds_old = va_arg(ap, struct __semid_ds_old *);
+       if (cmd == SETVAL)
+               val = va_arg(ap, int);
+       else
+               ds_old = va_arg(ap, struct __semid_ds_old *);
        va_end(ap);
 
 #define        _UP_CVT(x)      ds_new-> x = ds_old-> x
 #define        _DN_CVT(x)      ds_old-> x = ds_new-> x
 
+       if ((cmd == IPC_SET || cmd == IPC_STAT) && ds_old == NULL) {
+               /* Return EFAULT if ds_old is NULL (like the kernel would do) */
+               errno = EFAULT;
+               return -1;
+       }
        if (cmd == IPC_SET) {
                /* convert before call */
                _UP_CVT(sem_perm.uid);
@@ -75,8 +100,19 @@ semctl(int semid, int semnum, int cmd, ...)
                _UP_CVT(sem_pad3[2]);   /* binary compatibility */
                _UP_CVT(sem_pad3[3]);   /* binary compatibility */
        }
-
-       rv = syscall(SYS_semctl, semid, semnum, cmd, &ds);
+       switch (cmd) {
+       case SETVAL:
+               /* syscall must use LP64 quantities */
+               rv = __semctl(semid, semnum, cmd, (void *)val);
+               break;
+       case IPC_SET:
+       case IPC_STAT:
+               rv = __semctl(semid, semnum, cmd, ds_new);
+               break;
+       default:
+               rv = __semctl(semid, semnum, cmd, ds_old);
+               break;
+       }
 
        if (cmd == IPC_STAT) {
                /* convert after call */
@@ -85,8 +121,8 @@ semctl(int semid, int semnum, int cmd, ...)
                _DN_CVT(sem_perm.cuid); /* warning!  precision loss! */
                _DN_CVT(sem_perm.cgid); /* warning!  precision loss! */
                _DN_CVT(sem_perm.mode);
-               ds_new->sem_perm.seq = ds_old->sem_perm._seq;
-               ds_new->sem_perm.key = ds_old->sem_perm._key;
+               ds_old->sem_perm.seq = ds_new->sem_perm._seq;
+               ds_old->sem_perm.key = ds_new->sem_perm._key;
                _DN_CVT(sem_base);
                _DN_CVT(sem_nsems);
                _DN_CVT(sem_otime);