Back to index

glibc  2.9
semctl.c
Go to the documentation of this file.
00001 /* Copyright (C) 1995,1997,1998,2000,2003,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 
00032 struct __old_semid_ds
00033 {
00034   struct __old_ipc_perm sem_perm;  /* operation permission struct */
00035   __time_t sem_otime;                     /* last semop() time */
00036   __time_t sem_ctime;                     /* last time changed by semctl() */
00037   struct sem *__sembase;           /* ptr to first semaphore in array */
00038   struct sem_queue *__sem_pending; /* pending operations */
00039   struct sem_queue *__sem_pending_last; /* last pending operation */
00040   struct sem_undo *__undo;         /* ondo requests on this array */
00041   unsigned short int sem_nsems;           /* number of semaphores in set */
00042 };
00043 
00044 /* Define a `union semun' suitable for Linux here.  */
00045 union semun
00046 {
00047   int val;                  /* value for SETVAL */
00048   struct semid_ds *buf;            /* buffer for IPC_STAT & IPC_SET */
00049   unsigned short int *array;       /* array for GETALL & SETALL */
00050   struct seminfo *__buf;    /* buffer for IPC_INFO */
00051 };
00052 
00053 #include <bp-checks.h>
00054 #include <bp-semctl.h>             /* definition of CHECK_SEMCTL needs union semum */
00055 
00056 /* Return identifier for array of NSEMS semaphores associated with
00057    KEY.  */
00058 int __new_semctl (int semid, int semnum, int cmd, ...);
00059 
00060 int
00061 __new_semctl (int semid, int semnum, int cmd, ...)
00062 {
00063   union semun arg;
00064   va_list ap;
00065 
00066   va_start (ap, cmd);
00067 
00068   /* Get the argument.  */
00069   arg = va_arg (ap, union semun);
00070 
00071   va_end (ap);
00072 
00073 #if __ASSUME_32BITUIDS > 0
00074   return INLINE_SYSCALL (semctl, 4, semid, semnum, cmd | __IPC_64,
00075                       CHECK_SEMCTL (&arg, semid, cmd | __IPC_64)->array);
00076 #else
00077   switch (cmd) {
00078     case SEM_STAT:
00079     case IPC_STAT:
00080     case IPC_SET:
00081       break;
00082     default:
00083       return INLINE_SYSCALL (semctl, 4, semid, semnum, cmd,
00084                           CHECK_SEMCTL (&arg, semid, cmd)->array);
00085   }
00086 
00087   {
00088     int save_errno = errno, result;
00089     struct __old_semid_ds old;
00090     struct semid_ds *buf;
00091 
00092     /* Unfortunately there is no way how to find out for sure whether
00093        we should use old or new semctl.  */
00094     result = INLINE_SYSCALL (semctl, 4, semid, semnum, cmd | __IPC_64,
00095                           CHECK_SEMCTL (&arg, semid, cmd | __IPC_64)->array);
00096     if (result != -1 || errno != EINVAL)
00097       return result;
00098 
00099     __set_errno(save_errno);
00100     buf = arg.buf;
00101     arg.buf = (void *)&old;
00102     if (cmd == IPC_SET)
00103       {
00104        old.sem_perm.uid = buf->sem_perm.uid;
00105        old.sem_perm.gid = buf->sem_perm.gid;
00106        old.sem_perm.mode = buf->sem_perm.mode;
00107        if (old.sem_perm.uid != buf->sem_perm.uid ||
00108            old.sem_perm.gid != buf->sem_perm.gid)
00109          {
00110            __set_errno (EINVAL);
00111            return -1;
00112          }
00113       }
00114     result = INLINE_SYSCALL (semctl, 4, semid, semnum, cmd,
00115                           CHECK_SEMCTL (&arg, semid, cmd)->array);
00116     if (result != -1 && cmd != IPC_SET)
00117       {
00118        memset(buf, 0, sizeof(*buf));
00119        buf->sem_perm.__key = old.sem_perm.__key;
00120        buf->sem_perm.uid = old.sem_perm.uid;
00121        buf->sem_perm.gid = old.sem_perm.gid;
00122        buf->sem_perm.cuid = old.sem_perm.cuid;
00123        buf->sem_perm.cgid = old.sem_perm.cgid;
00124        buf->sem_perm.mode = old.sem_perm.mode;
00125        buf->sem_perm.__seq = old.sem_perm.__seq;
00126        buf->sem_otime = old.sem_otime;
00127        buf->sem_ctime = old.sem_ctime;
00128        buf->sem_nsems = old.sem_nsems;
00129       }
00130     return result;
00131   }
00132 #endif
00133 }
00134 
00135 #include <shlib-compat.h>
00136 versioned_symbol (libc, __new_semctl, semctl, GLIBC_2_2);