Back to index

glibc  2.9
semctl.c
Go to the documentation of this file.
00001 /* Copyright (C) 1995,1997,1998,2000,2003,2004,2006
00002        Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <errno.h>
00022 #include <stdarg.h>
00023 #include <sys/sem.h>
00024 #include <ipc_priv.h>
00025 
00026 #include <sysdep.h>
00027 #include <string.h>
00028 #include <sys/syscall.h>
00029 #include <shlib-compat.h>
00030 
00031 #include <kernel-features.h>
00032 
00033 struct __old_semid_ds
00034 {
00035   struct __old_ipc_perm sem_perm;  /* operation permission struct */
00036   __time_t sem_otime;                     /* last semop() time */
00037   __time_t sem_ctime;                     /* last time changed by semctl() */
00038   struct sem *__unbounded __sembase;      /* ptr to first semaphore in array */
00039   struct sem_queue *__unbounded __sem_pending; /* pending operations */
00040   struct sem_queue *__unbounded __sem_pending_last; /* last pending operation */
00041   struct sem_undo *__unbounded __undo;    /* ondo requests on this array */
00042   unsigned short int sem_nsems;           /* number of semaphores in set */
00043 };
00044 
00045 /* Define a `union semun' suitable for Linux here.  */
00046 union semun
00047 {
00048   int val;                  /* value for SETVAL */
00049   struct semid_ds *buf;            /* buffer for IPC_STAT & IPC_SET */
00050   unsigned short int *array;       /* array for GETALL & SETALL */
00051   struct seminfo *__buf;    /* buffer for IPC_INFO */
00052   struct __old_semid_ds *__old_buf;
00053 };
00054 
00055 #include <bp-checks.h>
00056 #include <bp-semctl.h>             /* definition of CHECK_SEMCTL needs union semum */
00057 
00058 /* Return identifier for array of NSEMS semaphores associated with
00059    KEY.  */
00060 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
00061 int __old_semctl (int semid, int semnum, int cmd, ...);
00062 #endif
00063 int __new_semctl (int semid, int semnum, int cmd, ...);
00064 
00065 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
00066 int
00067 attribute_compat_text_section
00068 __old_semctl (int semid, int semnum, int cmd, ...)
00069 {
00070   union semun arg;
00071   va_list ap;
00072 
00073   va_start (ap, cmd);
00074 
00075   /* Get the argument only if required.  */
00076   arg.buf = NULL;
00077   switch (cmd)
00078     {
00079     case SETVAL:        /* arg.val */
00080     case GETALL:        /* arg.array */
00081     case SETALL:
00082     case IPC_STAT:      /* arg.buf */
00083     case IPC_SET:
00084     case SEM_STAT:
00085     case IPC_INFO:      /* arg.__buf */
00086     case SEM_INFO:
00087       va_start (ap, cmd);
00088       arg = va_arg (ap, union semun);
00089       va_end (ap);
00090       break;
00091     }
00092 
00093   va_end (ap);
00094 
00095   return INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd,
00096                       CHECK_SEMCTL (&arg, semid, cmd));
00097 }
00098 compat_symbol (libc, __old_semctl, semctl, GLIBC_2_0);
00099 #endif
00100 
00101 int
00102 __new_semctl (int semid, int semnum, int cmd, ...)
00103 {
00104   union semun arg;
00105   va_list ap;
00106 
00107   va_start (ap, cmd);
00108 
00109   /* Get the argument only if required.  */
00110   arg.buf = NULL;
00111   switch (cmd)
00112     {
00113     case SETVAL:        /* arg.val */
00114     case GETALL:        /* arg.array */
00115     case SETALL:
00116     case IPC_STAT:      /* arg.buf */
00117     case IPC_SET:
00118     case SEM_STAT:
00119     case IPC_INFO:      /* arg.__buf */
00120     case SEM_INFO:
00121       va_start (ap, cmd);
00122       arg = va_arg (ap, union semun);
00123       va_end (ap);
00124       break;
00125     }
00126 
00127   va_end (ap);
00128 
00129 #if __ASSUME_IPC64 > 0
00130   return INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd | __IPC_64,
00131                       CHECK_SEMCTL (&arg, semid, cmd | __IPC_64));
00132 #else
00133   switch (cmd)
00134     {
00135     case SEM_STAT:
00136     case IPC_STAT:
00137     case IPC_SET:
00138       break;
00139     default:
00140       return INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd,
00141                           CHECK_SEMCTL (&arg, semid, cmd));
00142     }
00143 
00144   {
00145     int save_errno = errno, result;
00146     struct __old_semid_ds old;
00147     struct semid_ds *buf;
00148 
00149     /* Unfortunately there is no way how to find out for sure whether
00150        we should use old or new semctl.  */
00151     result = INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd | __IPC_64,
00152                           CHECK_SEMCTL (&arg, semid, cmd | __IPC_64));
00153     if (result != -1 || errno != EINVAL)
00154       return result;
00155 
00156     __set_errno(save_errno);
00157     buf = arg.buf;
00158     arg.__old_buf = &old;
00159     if (cmd == IPC_SET)
00160       {
00161        old.sem_perm.uid = buf->sem_perm.uid;
00162        old.sem_perm.gid = buf->sem_perm.gid;
00163        old.sem_perm.mode = buf->sem_perm.mode;
00164        if (old.sem_perm.uid != buf->sem_perm.uid ||
00165            old.sem_perm.gid != buf->sem_perm.gid)
00166          {
00167            __set_errno (EINVAL);
00168            return -1;
00169          }
00170       }
00171     result = INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd,
00172                           CHECK_SEMCTL (&arg, semid, cmd));
00173     if (result != -1 && cmd != IPC_SET)
00174       {
00175        memset(buf, 0, sizeof(*buf));
00176        buf->sem_perm.__key = old.sem_perm.__key;
00177        buf->sem_perm.uid = old.sem_perm.uid;
00178        buf->sem_perm.gid = old.sem_perm.gid;
00179        buf->sem_perm.cuid = old.sem_perm.cuid;
00180        buf->sem_perm.cgid = old.sem_perm.cgid;
00181        buf->sem_perm.mode = old.sem_perm.mode;
00182        buf->sem_perm.__seq = old.sem_perm.__seq;
00183        buf->sem_otime = old.sem_otime;
00184        buf->sem_ctime = old.sem_ctime;
00185        buf->sem_nsems = old.sem_nsems;
00186       }
00187     return result;
00188   }
00189 #endif
00190 }
00191 
00192 versioned_symbol (libc, __new_semctl, semctl, GLIBC_2_2);