Back to index

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