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 
00030 #include <kernel-features.h>
00031 #include <shlib-compat.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 *__sembase;           /* ptr to first semaphore in array */
00039   struct sem_queue *__sem_pending; /* pending operations */
00040   struct sem_queue *__sem_pending_last; /* last pending operation */
00041   struct sem_undo *__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 #ifdef __NR_getuid32
00059 # if __ASSUME_32BITUIDS == 0
00060 /* This variable is shared with all files that need to check for 32bit
00061    uids.  */
00062 extern int __libc_missing_32bit_uids;
00063 # endif
00064 #endif
00065 
00066 /* Return identifier for array of NSEMS semaphores associated with
00067    KEY.  */
00068 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
00069 int __old_semctl (int semid, int semnum, int cmd, ...);
00070 #endif
00071 int __new_semctl (int semid, int semnum, int cmd, ...);
00072 
00073 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
00074 int
00075 attribute_compat_text_section
00076 __old_semctl (int semid, int semnum, int cmd, ...)
00077 {
00078   union semun arg;
00079   va_list ap;
00080 
00081   va_start (ap, cmd);
00082 
00083   /* Get the argument.  */
00084   arg = va_arg (ap, union semun);
00085 
00086   va_end (ap);
00087 
00088   return INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd,
00089                       CHECK_SEMCTL (&arg, semid, cmd));
00090 }
00091 compat_symbol (libc, __old_semctl, semctl, GLIBC_2_0);
00092 #endif
00093 
00094 int
00095 __new_semctl (int semid, int semnum, int cmd, ...)
00096 {
00097   union semun arg;
00098   va_list ap;
00099 
00100   va_start (ap, cmd);
00101 
00102   /* Get the argument.  */
00103   arg = va_arg (ap, union semun);
00104 
00105   va_end (ap);
00106 
00107 #if __ASSUME_32BITUIDS > 0
00108   return INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd | __IPC_64,
00109                       CHECK_SEMCTL (&arg, semid, cmd | __IPC_64));
00110 #else
00111   switch (cmd) {
00112     case SEM_STAT:
00113     case IPC_STAT:
00114     case IPC_SET:
00115       break;
00116     default:
00117       return INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd,
00118                           CHECK_SEMCTL (&arg, semid, cmd));
00119   }
00120 
00121   {
00122     int result;
00123     struct __old_semid_ds old;
00124     struct semid_ds *buf;
00125 
00126 #ifdef __NR_getuid32
00127     if (__libc_missing_32bit_uids <= 0)
00128       {
00129        if (__libc_missing_32bit_uids < 0)
00130          {
00131            int save_errno = errno;
00132 
00133            /* Test presence of new IPC by testing for getuid32 syscall.  */
00134            result = INLINE_SYSCALL (getuid32, 0);
00135            if (result == -1 && errno == ENOSYS)
00136              __libc_missing_32bit_uids = 1;
00137            else
00138              __libc_missing_32bit_uids = 0;
00139            __set_errno(save_errno);
00140          }
00141        if (__libc_missing_32bit_uids <= 0)
00142          {
00143            result = INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd | __IPC_64,
00144                                  CHECK_SEMCTL (&arg, semid, cmd | __IPC_64));
00145            return result;
00146          }
00147       }
00148 #endif
00149 
00150     buf = arg.buf;
00151     arg.__old_buf = &old;
00152     if (cmd == IPC_SET)
00153       {
00154        old.sem_perm.uid = buf->sem_perm.uid;
00155        old.sem_perm.gid = buf->sem_perm.gid;
00156        old.sem_perm.mode = buf->sem_perm.mode;
00157        if (old.sem_perm.uid != buf->sem_perm.uid ||
00158            old.sem_perm.gid != buf->sem_perm.gid)
00159          {
00160            __set_errno (EINVAL);
00161            return -1;
00162          }
00163       }
00164     result = INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd,
00165                           CHECK_SEMCTL (&arg, semid, cmd));
00166     if (result != -1 && cmd != IPC_SET)
00167       {
00168        memset(buf, 0, sizeof(*buf));
00169        buf->sem_perm.__key = old.sem_perm.__key;
00170        buf->sem_perm.uid = old.sem_perm.uid;
00171        buf->sem_perm.gid = old.sem_perm.gid;
00172        buf->sem_perm.cuid = old.sem_perm.cuid;
00173        buf->sem_perm.cgid = old.sem_perm.cgid;
00174        buf->sem_perm.mode = old.sem_perm.mode;
00175        buf->sem_perm.__seq = old.sem_perm.__seq;
00176        buf->sem_otime = old.sem_otime;
00177        buf->sem_ctime = old.sem_ctime;
00178        buf->sem_nsems = old.sem_nsems;
00179       }
00180     return result;
00181   }
00182 #endif
00183 }
00184 
00185 versioned_symbol (libc, __new_semctl, semctl, GLIBC_2_2);