about summary refs log tree commit diff
path: root/sysdeps/unix/sysv
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/sysv')
-rw-r--r--sysdeps/unix/sysv/linux/arm/getresgid.c1
-rw-r--r--sysdeps/unix/sysv/linux/arm/getresuid.c1
-rw-r--r--sysdeps/unix/sysv/linux/arm/msgctl.c1
-rw-r--r--sysdeps/unix/sysv/linux/arm/semctl.c1
-rw-r--r--sysdeps/unix/sysv/linux/arm/shmctl.c1
-rw-r--r--sysdeps/unix/sysv/linux/i386/chown.c4
-rw-r--r--sysdeps/unix/sysv/linux/i386/fchown.c2
-rw-r--r--sysdeps/unix/sysv/linux/i386/getegid.c2
-rw-r--r--sysdeps/unix/sysv/linux/i386/geteuid.c2
-rw-r--r--sysdeps/unix/sysv/linux/i386/getgid.c2
-rw-r--r--sysdeps/unix/sysv/linux/i386/getgroups.c2
-rw-r--r--sysdeps/unix/sysv/linux/i386/getresgid.c (renamed from sysdeps/unix/sysv/linux/getresgid.c)2
-rw-r--r--sysdeps/unix/sysv/linux/i386/getresuid.c (renamed from sysdeps/unix/sysv/linux/getresuid.c)2
-rw-r--r--sysdeps/unix/sysv/linux/i386/getuid.c9
-rw-r--r--sysdeps/unix/sysv/linux/i386/lchown.c2
-rw-r--r--sysdeps/unix/sysv/linux/i386/msgctl.c151
-rw-r--r--sysdeps/unix/sysv/linux/i386/semctl.c173
-rw-r--r--sysdeps/unix/sysv/linux/i386/setfsgid.c2
-rw-r--r--sysdeps/unix/sysv/linux/i386/setfsuid.c2
-rw-r--r--sysdeps/unix/sysv/linux/i386/setgid.c2
-rw-r--r--sysdeps/unix/sysv/linux/i386/setgroups.c2
-rw-r--r--sysdeps/unix/sysv/linux/i386/setregid.c2
-rw-r--r--sysdeps/unix/sysv/linux/i386/setresgid.c2
-rw-r--r--sysdeps/unix/sysv/linux/i386/setresuid.c2
-rw-r--r--sysdeps/unix/sysv/linux/i386/setreuid.c2
-rw-r--r--sysdeps/unix/sysv/linux/i386/setuid.c2
-rw-r--r--sysdeps/unix/sysv/linux/i386/shmctl.c173
-rw-r--r--sysdeps/unix/sysv/linux/m68k/chown.c2
-rw-r--r--sysdeps/unix/sysv/linux/m68k/getresgid.c1
-rw-r--r--sysdeps/unix/sysv/linux/m68k/getresuid.c1
-rw-r--r--sysdeps/unix/sysv/linux/m68k/msgctl.c1
-rw-r--r--sysdeps/unix/sysv/linux/m68k/semctl.c1
-rw-r--r--sysdeps/unix/sysv/linux/m68k/shmctl.c1
-rw-r--r--sysdeps/unix/sysv/linux/mips/syscalls.list4
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/syscalls.list4
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/msgctl.c1
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/semctl.c1
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/shmctl.c1
38 files changed, 540 insertions, 27 deletions
diff --git a/sysdeps/unix/sysv/linux/arm/getresgid.c b/sysdeps/unix/sysv/linux/arm/getresgid.c
new file mode 100644
index 0000000000..b703a414cc
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/arm/getresgid.c
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/i386/getresgid.c>
diff --git a/sysdeps/unix/sysv/linux/arm/getresuid.c b/sysdeps/unix/sysv/linux/arm/getresuid.c
new file mode 100644
index 0000000000..0b14cefe34
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/arm/getresuid.c
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/i386/getresuid.c>
diff --git a/sysdeps/unix/sysv/linux/arm/msgctl.c b/sysdeps/unix/sysv/linux/arm/msgctl.c
new file mode 100644
index 0000000000..9f9b8431a3
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/arm/msgctl.c
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/i386/msgctl.c>
diff --git a/sysdeps/unix/sysv/linux/arm/semctl.c b/sysdeps/unix/sysv/linux/arm/semctl.c
new file mode 100644
index 0000000000..e9b1a483c9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/arm/semctl.c
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/i386/semctl.c>
diff --git a/sysdeps/unix/sysv/linux/arm/shmctl.c b/sysdeps/unix/sysv/linux/arm/shmctl.c
new file mode 100644
index 0000000000..7eac6380dd
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/arm/shmctl.c
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/i386/shmctl.c>
diff --git a/sysdeps/unix/sysv/linux/i386/chown.c b/sysdeps/unix/sysv/linux/i386/chown.c
index 8652d0f097..f6442a4ab6 100644
--- a/sysdeps/unix/sysv/linux/i386/chown.c
+++ b/sysdeps/unix/sysv/linux/i386/chown.c
@@ -63,7 +63,7 @@ __real_chown (const char *file, uid_t owner, gid_t group)
     {
       int saved_errno = errno;
 #  ifdef __NR_chown32
-      if (!__libc_missing_32bit_uids)
+      if (__libc_missing_32bit_uids <= 0)
 	{
 	  int result;
 	  int saved_errno = errno;
@@ -99,7 +99,7 @@ __real_chown (const char *file, uid_t owner, gid_t group)
 # else
   /* !__ASSUME_32BITUIDS && ASSUME_LCHOWN_SYSCALL  */
 #  ifdef __NR_chown32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/fchown.c b/sysdeps/unix/sysv/linux/i386/fchown.c
index 5a84d4170e..f330bbb279 100644
--- a/sysdeps/unix/sysv/linux/i386/fchown.c
+++ b/sysdeps/unix/sysv/linux/i386/fchown.c
@@ -45,7 +45,7 @@ __fchown (int fd, uid_t owner, gid_t group)
   return INLINE_SYSCALL (fchown32, 3, fd, owner, group);
 #else
 # ifdef __NR_fchown32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/getegid.c b/sysdeps/unix/sysv/linux/i386/getegid.c
index 05dd15d986..3926af37db 100644
--- a/sysdeps/unix/sysv/linux/i386/getegid.c
+++ b/sysdeps/unix/sysv/linux/i386/getegid.c
@@ -41,7 +41,7 @@ __getegid (void)
   return INLINE_SYSCALL (getegid32, 0);
 #else
 # ifdef __NR_getegid32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/geteuid.c b/sysdeps/unix/sysv/linux/i386/geteuid.c
index e2f932a975..f97fd83c7d 100644
--- a/sysdeps/unix/sysv/linux/i386/geteuid.c
+++ b/sysdeps/unix/sysv/linux/i386/geteuid.c
@@ -41,7 +41,7 @@ __geteuid (void)
   return INLINE_SYSCALL (geteuid32, 0);
 #else
 # ifdef __NR_geteuid32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/getgid.c b/sysdeps/unix/sysv/linux/i386/getgid.c
index 19794aac36..643abe29d2 100644
--- a/sysdeps/unix/sysv/linux/i386/getgid.c
+++ b/sysdeps/unix/sysv/linux/i386/getgid.c
@@ -42,7 +42,7 @@ __getgid (void)
   return INLINE_SYSCALL (getgid32, 0);
 #else
 # ifdef __NR_getgid32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/getgroups.c b/sysdeps/unix/sysv/linux/i386/getgroups.c
index 4ada764f0c..071be4f4b7 100644
--- a/sysdeps/unix/sysv/linux/i386/getgroups.c
+++ b/sysdeps/unix/sysv/linux/i386/getgroups.c
@@ -56,7 +56,7 @@ __getgroups (int n, gid_t *groups)
       int i, ngids;
       __kernel_gid_t kernel_groups[n = MIN (n, __sysconf (_SC_NGROUPS_MAX))];
 # ifdef __NR_getgroups32
-      if (!__libc_missing_32bit_uids)
+      if (__libc_missing_32bit_uids <= 0)
 	{
 	  int result;
 	  int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/getresgid.c b/sysdeps/unix/sysv/linux/i386/getresgid.c
index ce7d7aa649..f4bd14da22 100644
--- a/sysdeps/unix/sysv/linux/getresgid.c
+++ b/sysdeps/unix/sysv/linux/i386/getresgid.c
@@ -52,7 +52,7 @@ getresgid (gid_t *rgid, gid_t *egid, gid_t *sgid)
   __kernel_gid_t k_rgid, k_egid, k_sgid;
   int result;
 #  ifdef __NR_getresgid32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int r;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/getresuid.c b/sysdeps/unix/sysv/linux/i386/getresuid.c
index 465db9cc88..27eca40745 100644
--- a/sysdeps/unix/sysv/linux/getresuid.c
+++ b/sysdeps/unix/sysv/linux/i386/getresuid.c
@@ -51,7 +51,7 @@ getresuid (uid_t *ruid, uid_t *euid, uid_t *suid)
   __kernel_uid_t k_ruid, k_euid, k_suid;
   int result;
 #  ifdef __NR_getresuid32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int r;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/getuid.c b/sysdeps/unix/sysv/linux/i386/getuid.c
index d160e4423a..97fd273805 100644
--- a/sysdeps/unix/sysv/linux/i386/getuid.c
+++ b/sysdeps/unix/sysv/linux/i386/getuid.c
@@ -30,8 +30,11 @@ extern int __syscall_getuid (void);
 extern int __syscall_getuid32 (void);
 # if __ASSUME_32BITUIDS == 0
 /* This variable is shared with all files that need to check for 32bit
-   uids.  This is the definition */
-int __libc_missing_32bit_uids;
+   uids.  This is the definition.
+   -1 if libc does not know yet whether kernel has 32bit uids or not.
+   0 if it does have them.
+   1 if it does not have them.  */
+int __libc_missing_32bit_uids = -1;
 # endif
 #endif /* __NR_getuid32 */
 
@@ -42,7 +45,7 @@ __getuid (void)
   return INLINE_SYSCALL (getuid32, 0);
 #else
 # ifdef __NR_getuid32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/lchown.c b/sysdeps/unix/sysv/linux/i386/lchown.c
index 2d8e8fb998..6e2bb9d0b9 100644
--- a/sysdeps/unix/sysv/linux/i386/lchown.c
+++ b/sysdeps/unix/sysv/linux/i386/lchown.c
@@ -46,7 +46,7 @@ __lchown (const char *file, uid_t owner, gid_t group)
   return INLINE_SYSCALL (lchown32, 3, file, owner, group);
 # else
 #  ifdef __NR_lchown32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/msgctl.c b/sysdeps/unix/sysv/linux/i386/msgctl.c
new file mode 100644
index 0000000000..2ff88882c6
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/msgctl.c
@@ -0,0 +1,151 @@
+/* Copyright (C) 1995, 1997, 1998, 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <sys/msg.h>
+#include <ipc_priv.h>
+
+#include <sysdep.h>
+#include <string.h>
+#include <sys/syscall.h>
+
+#include "kernel-features.h"
+
+struct __old_msqid_ds
+{
+  struct __old_ipc_perm msg_perm;	/* structure describing operation permission */
+  struct msg *__msg_first;		/* pointer to first message on queue */
+  struct msg *__msg_last;		/* pointer to last message on queue */
+  __time_t msg_stime;			/* time of last msgsnd command */
+  __time_t msg_rtime;			/* time of last msgrcv command */
+  __time_t msg_ctime;			/* time of last change */
+  struct wait_queue *__wwait;		/* ??? */
+  struct wait_queue *__rwait;		/* ??? */
+  unsigned short int __msg_cbytes;	/* current number of bytes on queue */
+  unsigned short int msg_qnum;		/* number of messages currently on queue */
+  unsigned short int msg_qbytes;	/* max number of bytes allowed on queue */
+  __ipc_pid_t msg_lspid;		/* pid of last msgsnd() */
+  __ipc_pid_t msg_lrpid;		/* pid of last msgrcv() */
+};
+
+/* Allows to control internal state and destruction of message queue
+   objects.  */
+int __old_msgctl (int, int, struct __old_msqid_ds *);
+int __new_msgctl (int, int, struct msqid_ds *);
+
+#ifdef __NR_getuid32
+# if __ASSUME_32BITUIDS == 0
+/* This variable is shared with all files that need to check for 32bit
+   uids.  */
+extern int __libc_missing_32bit_uids;
+# endif
+#endif
+
+int
+__old_msgctl (int msqid, int cmd, struct __old_msqid_ds *buf)
+{
+  return INLINE_SYSCALL (ipc, 5, IPCOP_msgctl, msqid, cmd, 0, buf);
+}
+
+int
+__new_msgctl (int msqid, int cmd, struct msqid_ds *buf)
+{
+#if __ASSUME_32BITUIDS > 0
+  return INLINE_SYSCALL (ipc, 5, IPCOP_msgctl, msqid, cmd | __IPC_64, 0, buf);
+#else
+  switch (cmd) {
+    case MSG_STAT:
+    case IPC_STAT:
+    case IPC_SET:
+      break;
+    default:
+      return INLINE_SYSCALL (ipc, 5, IPCOP_msgctl, msqid, cmd, 0, buf);
+  }
+
+  {
+    int save_errno, result;
+    struct __old_msqid_ds old;
+
+#ifdef __NR_getuid32
+    if (__libc_missing_32bit_uids <= 0)
+      {
+	if (__libc_missing_32bit_uids < 0)
+	  {
+	    save_errno = errno;
+
+	    /* Test presence of new IPC by testing for getuid32 syscall.  */
+	    result = INLINE_SYSCALL (getuid32, 0);
+	    if (result == -1 && errno == ENOSYS)
+	      __libc_missing_32bit_uids = 1;
+	    else
+	      __libc_missing_32bit_uids = 0;
+	    __set_errno(save_errno);
+	  }
+	if (__libc_missing_32bit_uids <= 0)
+	  {
+	    result = INLINE_SYSCALL (ipc, 5, IPCOP_msgctl, msqid, cmd | __IPC_64, 0, buf);
+	    return result;
+	  }
+      }
+#endif
+    if (cmd == IPC_SET)
+      {
+	old.msg_perm.uid = buf->msg_perm.uid;
+	old.msg_perm.gid = buf->msg_perm.gid;
+	old.msg_perm.mode = buf->msg_perm.mode;
+	old.msg_qbytes = buf->msg_qbytes;
+	if (old.msg_perm.uid != buf->msg_perm.uid ||
+	    old.msg_perm.gid != buf->msg_perm.gid ||
+	    old.msg_qbytes != buf->msg_qbytes)
+	  {
+	    __set_errno (EINVAL);
+	    return -1;
+	  }
+      }
+    result = INLINE_SYSCALL (ipc, 5, IPCOP_msgctl, msqid, cmd, 0, &old);
+    if (result != -1 && cmd != IPC_SET)
+      {
+	memset(buf, 0, sizeof(*buf));
+	buf->msg_perm.__key = old.msg_perm.__key;
+	buf->msg_perm.uid = old.msg_perm.uid;
+	buf->msg_perm.gid = old.msg_perm.gid;
+	buf->msg_perm.cuid = old.msg_perm.cuid;
+	buf->msg_perm.cgid = old.msg_perm.cgid;
+	buf->msg_perm.mode = old.msg_perm.mode;
+	buf->msg_perm.__seq = old.msg_perm.__seq;
+	buf->msg_stime = old.msg_stime;
+	buf->msg_rtime = old.msg_rtime;
+	buf->msg_ctime = old.msg_ctime;
+	buf->__msg_cbytes = old.__msg_cbytes;
+	buf->msg_qnum = old.msg_qnum;
+	buf->msg_qbytes = old.msg_qbytes;
+	buf->msg_lspid = old.msg_lspid;
+	buf->msg_lrpid = old.msg_lrpid;
+      }
+    return result;
+  }
+#endif
+}
+
+#if defined PIC && DO_VERSIONING
+default_symbol_version (__new_msgctl, msgctl, GLIBC_2.2);
+symbol_version (__old_msgctl, msgctl, GLIBC_2.0);
+#else
+weak_alias (__new_msgctl, msgctl);
+#endif
diff --git a/sysdeps/unix/sysv/linux/i386/semctl.c b/sysdeps/unix/sysv/linux/i386/semctl.c
new file mode 100644
index 0000000000..7704d2387b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/semctl.c
@@ -0,0 +1,173 @@
+/* Copyright (C) 1995, 1997, 1998, 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <sys/sem.h>
+#include <ipc_priv.h>
+
+#include <sysdep.h>
+#include <string.h>
+#include <sys/syscall.h>
+
+#include "kernel-features.h"
+
+struct __old_semid_ds
+{
+  struct __old_ipc_perm sem_perm;	/* operation permission struct */
+  __time_t sem_otime;			/* last semop() time */
+  __time_t sem_ctime;			/* last time changed by semctl() */
+  struct sem *__sembase;		/* ptr to first semaphore in array */
+  struct sem_queue *__sem_pending;	/* pending operations */
+  struct sem_queue *__sem_pending_last; /* last pending operation */
+  struct sem_undo *__undo;		/* ondo requests on this array */
+  unsigned short int sem_nsems;		/* number of semaphores in set */
+};
+
+/* Define a `union semun' suitable for Linux here.  */
+union semun
+{
+  int val;			/* value for SETVAL */
+  struct semid_ds *buf;		/* buffer for IPC_STAT & IPC_SET */
+  unsigned short int *array;	/* array for GETALL & SETALL */
+  struct seminfo *__buf;	/* buffer for IPC_INFO */
+};
+
+#ifdef __NR_getuid32
+# if __ASSUME_32BITUIDS == 0
+/* This variable is shared with all files that need to check for 32bit
+   uids.  */
+extern int __libc_missing_32bit_uids;
+# endif
+#endif
+
+/* Return identifier for array of NSEMS semaphores associated with
+   KEY.  */
+int __old_semctl (int semid, int semnum, int cmd, ...);
+int __new_semctl (int semid, int semnum, int cmd, ...);
+
+int
+__old_semctl (int semid, int semnum, int cmd, ...)
+{
+  union semun arg;
+  va_list ap;
+
+  va_start (ap, cmd);
+
+  /* Get the argument.  */
+  arg = va_arg (ap, union semun);
+
+  va_end (ap);
+
+  return INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd, &arg);
+}
+
+int
+__new_semctl (int semid, int semnum, int cmd, ...)
+{
+  union semun arg;
+  va_list ap;
+
+  va_start (ap, cmd);
+
+  /* Get the argument.  */
+  arg = va_arg (ap, union semun);
+
+  va_end (ap);
+
+#if __ASSUME_32BITUIDS > 0
+  return INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd | __IPC_64, &arg);
+#else
+  switch (cmd) {
+    case SEM_STAT:
+    case IPC_STAT:
+    case IPC_SET:
+      break;
+    default:
+      return INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd, &arg);
+  }
+
+  {
+    int save_errno, result;
+    struct __old_semid_ds old;
+    struct semid_ds *buf;
+
+#ifdef __NR_getuid32
+    if (__libc_missing_32bit_uids <= 0)
+      {
+	if (__libc_missing_32bit_uids < 0)
+	  {
+	    save_errno = errno;
+
+	    /* Test presence of new IPC by testing for getuid32 syscall.  */
+	    result = INLINE_SYSCALL (getuid32, 0);
+	    if (result == -1 && errno == ENOSYS)
+	      __libc_missing_32bit_uids = 1;
+	    else
+	      __libc_missing_32bit_uids = 0;
+	    __set_errno(save_errno);
+	  }
+	if (__libc_missing_32bit_uids <= 0)
+	  {
+	    result = INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd | __IPC_64, &arg);
+	    return result;
+	  }
+      }
+#endif
+
+    buf = arg.buf;
+    arg.buf = (struct semid_ds *)&old;
+    if (cmd == IPC_SET)
+      {
+	old.sem_perm.uid = buf->sem_perm.uid;
+	old.sem_perm.gid = buf->sem_perm.gid;
+	old.sem_perm.mode = buf->sem_perm.mode;
+	if (old.sem_perm.uid != buf->sem_perm.uid ||
+	    old.sem_perm.gid != buf->sem_perm.gid)
+	  {
+	    __set_errno (EINVAL);
+	    return -1;
+	  }
+      }
+    result = INLINE_SYSCALL (ipc, 5, IPCOP_semctl, semid, semnum, cmd, &arg);
+    if (result != -1 && cmd != IPC_SET)
+      {
+	memset(buf, 0, sizeof(*buf));
+	buf->sem_perm.__key = old.sem_perm.__key;
+	buf->sem_perm.uid = old.sem_perm.uid;
+	buf->sem_perm.gid = old.sem_perm.gid;
+	buf->sem_perm.cuid = old.sem_perm.cuid;
+	buf->sem_perm.cgid = old.sem_perm.cgid;
+	buf->sem_perm.mode = old.sem_perm.mode;
+	buf->sem_perm.__seq = old.sem_perm.__seq;
+	buf->sem_otime = old.sem_otime;
+	buf->sem_ctime = old.sem_ctime;
+	buf->sem_nsems = old.sem_nsems;
+      }
+    return result;
+  }
+#endif
+}
+
+#if defined PIC && DO_VERSIONING
+default_symbol_version (__new_semctl, semctl, GLIBC_2.2);
+symbol_version (__old_semctl, semctl, GLIBC_2.0);
+#else
+weak_alias (__new_semctl, semctl);
+#endif
diff --git a/sysdeps/unix/sysv/linux/i386/setfsgid.c b/sysdeps/unix/sysv/linux/i386/setfsgid.c
index 6fd7e46489..9d4d475b54 100644
--- a/sysdeps/unix/sysv/linux/i386/setfsgid.c
+++ b/sysdeps/unix/sysv/linux/i386/setfsgid.c
@@ -46,7 +46,7 @@ setfsgid (gid_t gid)
   return INLINE_SYSCALL (setfsgid32, 1, gid);
 # else
 #  ifdef __NR_setfsgid32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/setfsuid.c b/sysdeps/unix/sysv/linux/i386/setfsuid.c
index cf7bc16476..6491f9e139 100644
--- a/sysdeps/unix/sysv/linux/i386/setfsuid.c
+++ b/sysdeps/unix/sysv/linux/i386/setfsuid.c
@@ -46,7 +46,7 @@ setfsuid (uid_t uid)
   return INLINE_SYSCALL (setfsuid32, 1, uid);
 # else  
 #  ifdef __NR_setfsuid32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/setgid.c b/sysdeps/unix/sysv/linux/i386/setgid.c
index 2a81302527..6d64cc8cbb 100644
--- a/sysdeps/unix/sysv/linux/i386/setgid.c
+++ b/sysdeps/unix/sysv/linux/i386/setgid.c
@@ -45,7 +45,7 @@ __setgid (gid_t gid)
   return INLINE_SYSCALL (setgid32, 1, gid);
 #else
 # ifdef __NR_setgid32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/setgroups.c b/sysdeps/unix/sysv/linux/i386/setgroups.c
index eb02350371..81f938d614 100644
--- a/sysdeps/unix/sysv/linux/i386/setgroups.c
+++ b/sysdeps/unix/sysv/linux/i386/setgroups.c
@@ -57,7 +57,7 @@ setgroups (size_t n, const gid_t *groups)
       size_t i;
       __kernel_gid_t kernel_groups[n];
 # ifdef __NR_setgroups32
-      if (!__libc_missing_32bit_uids)
+      if (__libc_missing_32bit_uids <= 0)
 	{
 	  int result;
 	  int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/setregid.c b/sysdeps/unix/sysv/linux/i386/setregid.c
index b4d0a2a116..1d810cdd33 100644
--- a/sysdeps/unix/sysv/linux/i386/setregid.c
+++ b/sysdeps/unix/sysv/linux/i386/setregid.c
@@ -45,7 +45,7 @@ __setregid (gid_t rgid, gid_t egid)
   return INLINE_SYSCALL (setregid32, 2, rgid, egid);
 #else
 # ifdef __NR_setregid32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/setresgid.c b/sysdeps/unix/sysv/linux/i386/setresgid.c
index 97bb97469c..51ee2141ed 100644
--- a/sysdeps/unix/sysv/linux/i386/setresgid.c
+++ b/sysdeps/unix/sysv/linux/i386/setresgid.c
@@ -48,7 +48,7 @@ setresgid (gid_t rgid, gid_t egid, gid_t sgid)
   return INLINE_SYSCALL (setresgid32, 3, rgid, egid, sgid);
 # else
 #  ifdef __NR_setresgid32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/setresuid.c b/sysdeps/unix/sysv/linux/i386/setresuid.c
index 94fc79ba5c..e5723a0336 100644
--- a/sysdeps/unix/sysv/linux/i386/setresuid.c
+++ b/sysdeps/unix/sysv/linux/i386/setresuid.c
@@ -48,7 +48,7 @@ __setresuid (uid_t ruid, uid_t euid, uid_t suid)
   return INLINE_SYSCALL (setresuid32, 3, ruid, euid, suid);
 # else
 #  ifdef __NR_setresuid32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/setreuid.c b/sysdeps/unix/sysv/linux/i386/setreuid.c
index b660604152..b7ffbe01ab 100644
--- a/sysdeps/unix/sysv/linux/i386/setreuid.c
+++ b/sysdeps/unix/sysv/linux/i386/setreuid.c
@@ -45,7 +45,7 @@ __setreuid (uid_t ruid, uid_t euid)
   return INLINE_SYSCALL (setreuid32, 2, ruid, euid);
 #else
 # ifdef __NR_setreuid32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/setuid.c b/sysdeps/unix/sysv/linux/i386/setuid.c
index ed0d8fa0bd..c93185ada3 100644
--- a/sysdeps/unix/sysv/linux/i386/setuid.c
+++ b/sysdeps/unix/sysv/linux/i386/setuid.c
@@ -44,7 +44,7 @@ __setuid (uid_t uid)
   return INLINE_SYSCALL (setuid32, 1, uid);
 #else
 # ifdef __NR_setuid32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/i386/shmctl.c b/sysdeps/unix/sysv/linux/i386/shmctl.c
new file mode 100644
index 0000000000..2fffc16f1f
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/shmctl.c
@@ -0,0 +1,173 @@
+/* Copyright (C) 1995, 1997, 1998, 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <sys/shm.h>
+#include <ipc_priv.h>
+
+#include <sysdep.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <bits/wordsize.h>
+
+#include "kernel-features.h"
+
+struct __old_shmid_ds
+{
+  struct __old_ipc_perm shm_perm;	/* operation permission struct */
+  int shm_segsz;			/* size of segment in bytes */
+  __time_t shm_atime;			/* time of last shmat() */
+  __time_t shm_dtime;			/* time of last shmdt() */
+  __time_t shm_ctime;			/* time of last change by shmctl() */
+  __ipc_pid_t shm_cpid;			/* pid of creator */
+  __ipc_pid_t shm_lpid;			/* pid of last shmop */
+  unsigned short int shm_nattch;	/* number of current attaches */
+  unsigned short int __shm_npages;	/* size of segment (pages) */
+  unsigned long int *__shm_pages;	/* array of ptrs to frames -> SHMMAX */
+  struct vm_area_struct *__attaches;	/* descriptors for attaches */
+};
+
+struct __old_shminfo
+{
+  int shmmax;
+  int shmmin;
+  int shmmni;
+  int shmseg;
+  int shmall;
+};
+
+#ifdef __NR_getuid32
+# if __ASSUME_32BITUIDS == 0
+/* This variable is shared with all files that need to check for 32bit
+   uids.  */
+extern int __libc_missing_32bit_uids;
+# endif
+#endif
+
+/* Provide operations to control over shared memory segments.  */
+int __old_shmctl (int, int, struct __old_shmid_ds *);
+int __new_shmctl (int, int, struct shmid_ds *);
+
+int
+__old_shmctl (int shmid, int cmd, struct __old_shmid_ds *buf)
+{
+  return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd, 0, buf);
+}
+
+int
+__new_shmctl (int shmid, int cmd, struct shmid_ds *buf)
+{
+#if __ASSUME_32BITUIDS > 0
+  return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd | __IPC_64, 0, buf);
+#else
+  switch (cmd) {
+    case SHM_STAT:
+    case IPC_STAT:
+    case IPC_SET:
+#if __WORDSIZE != 32
+    case IPC_INFO:
+#endif
+      break;
+    default:
+      return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd, 0, buf);
+  }
+
+  {
+    int save_errno = result;
+    struct __old_shmid_ds old;
+
+#ifdef __NR_getuid32
+    if (__libc_missing_32bit_uids <= 0)
+      {
+	if (__libc_missing_32bit_uids < 0)
+	  {
+	    save_errno = errno;
+
+	    /* Test presence of new IPC by testing for getuid32 syscall.  */
+	    result = INLINE_SYSCALL (getuid32, 0);
+	    if (result == -1 && errno == ENOSYS)
+	      __libc_missing_32bit_uids = 1;
+	    else
+	      __libc_missing_32bit_uids = 0;
+	    __set_errno(save_errno);
+	  }
+	if (__libc_missing_32bit_uids <= 0)
+	  {
+	    result = INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd | __IPC_64, 0, buf);
+	    return result;
+	  }
+      }
+#endif
+
+    if (cmd == IPC_SET)
+      {
+	old.shm_perm.uid = buf->shm_perm.uid;
+	old.shm_perm.gid = buf->shm_perm.gid;
+	old.shm_perm.mode = buf->shm_perm.mode;
+	if (old.shm_perm.uid != buf->shm_perm.uid ||
+	    old.shm_perm.gid != buf->shm_perm.gid)
+	  {
+	    __set_errno (EINVAL);
+	    return -1;
+	  }
+      }
+    result = INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd, 0, &old);
+    if (result != -1 && (cmd == SHM_STAT || cmd == IPC_STAT))
+      {
+	memset(buf, 0, sizeof(*buf));
+	buf->shm_perm.__key = old.shm_perm.__key;
+	buf->shm_perm.uid = old.shm_perm.uid;
+	buf->shm_perm.gid = old.shm_perm.gid;
+	buf->shm_perm.cuid = old.shm_perm.cuid;
+	buf->shm_perm.cgid = old.shm_perm.cgid;
+	buf->shm_perm.mode = old.shm_perm.mode;
+	buf->shm_perm.__seq = old.shm_perm.__seq;
+	buf->shm_atime = old.shm_atime;
+	buf->shm_dtime = old.shm_dtime;
+	buf->shm_ctime = old.shm_ctime;
+	buf->shm_segsz = old.shm_segsz;
+	buf->shm_nattch = old.shm_nattch;
+	buf->shm_cpid = old.shm_cpid;
+	buf->shm_lpid = old.shm_lpid;
+      }
+#if __WORDSIZE != 32
+    else if (result != -1 && cmd == IPC_INFO)
+      {
+	struct __old_shminfo *oldi = (struct __old_shminfo *)&old;
+	struct shminfo *i = (struct shminfo *)buf;
+
+	memset(i, 0, sizeof(*i));
+	i->shmmax = oldi->shmmax;
+	i->shmmin = oldi->shmmin;
+	i->shmmni = oldi->shmmni;
+	i->shmseg = oldi->shmseg;
+	i->shmall = oldi->shmall;
+      }
+#endif
+    return result;
+  }
+#endif
+}
+
+#if defined PIC && DO_VERSIONING
+default_symbol_version (__new_shmctl, shmctl, GLIBC_2.2);
+symbol_version (__old_shmctl, shmctl, GLIBC_2.0);
+#else
+weak_alias (__new_shmctl, shmctl);
+#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/chown.c b/sysdeps/unix/sysv/linux/m68k/chown.c
index 4e7625c13e..79701ee6ff 100644
--- a/sysdeps/unix/sysv/linux/m68k/chown.c
+++ b/sysdeps/unix/sysv/linux/m68k/chown.c
@@ -45,7 +45,7 @@ __chown (const char *file, uid_t owner, gid_t group)
   return INLINE_SYSCALL (chown32, 3, file, owner, group);
 #else
 # ifdef __NR_chown32
-  if (!__libc_missing_32bit_uids)
+  if (__libc_missing_32bit_uids <= 0)
     {
       int result;
       int saved_errno = errno;
diff --git a/sysdeps/unix/sysv/linux/m68k/getresgid.c b/sysdeps/unix/sysv/linux/m68k/getresgid.c
new file mode 100644
index 0000000000..b703a414cc
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/getresgid.c
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/i386/getresgid.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/getresuid.c b/sysdeps/unix/sysv/linux/m68k/getresuid.c
new file mode 100644
index 0000000000..0b14cefe34
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/getresuid.c
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/i386/getresuid.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/msgctl.c b/sysdeps/unix/sysv/linux/m68k/msgctl.c
new file mode 100644
index 0000000000..9f9b8431a3
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/msgctl.c
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/i386/msgctl.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/semctl.c b/sysdeps/unix/sysv/linux/m68k/semctl.c
new file mode 100644
index 0000000000..e9b1a483c9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/semctl.c
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/i386/semctl.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/shmctl.c b/sysdeps/unix/sysv/linux/m68k/shmctl.c
new file mode 100644
index 0000000000..7eac6380dd
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/shmctl.c
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/i386/shmctl.c>
diff --git a/sysdeps/unix/sysv/linux/mips/syscalls.list b/sysdeps/unix/sysv/linux/mips/syscalls.list
index 6bb4451ff3..d8c5afa571 100644
--- a/sysdeps/unix/sysv/linux/mips/syscalls.list
+++ b/sysdeps/unix/sysv/linux/mips/syscalls.list
@@ -56,8 +56,8 @@ s_getcwd	getcwd	getcwd		2	__syscall_getcwd
 s_getdents	getdents getdents	3	__syscall_getdents
 s_getpmsg	getpmsg	getpmsg		5	__syscall_getpmsg
 s_getpriority	getpriority getpriority	2	__syscall_getpriority
-s_getresgid	getresgid getresgid	3	__syscall_getresgid
-s_getresuid	getresuid getresuid	3	__syscall_getresuid
+getresgid	-	getresgid	3	getresgid
+getresuid	-	getresuid	3	getresuid
 s_ipc		msgget	ipc		5	__syscall_ipc
 s_lstat64	lxstat64 lstat64	2	__syscall_lstat64
 s_poll		poll	poll		3	__syscall_poll
diff --git a/sysdeps/unix/sysv/linux/powerpc/syscalls.list b/sysdeps/unix/sysv/linux/powerpc/syscalls.list
index d6fdd4cc6c..c5ba61dd12 100644
--- a/sysdeps/unix/sysv/linux/powerpc/syscalls.list
+++ b/sysdeps/unix/sysv/linux/powerpc/syscalls.list
@@ -18,8 +18,8 @@ s_getcwd	getcwd	getcwd		2	__syscall_getcwd
 s_getdents	getdents getdents	3	__syscall_getdents
 s_getpmsg	getpmsg	getpmsg		5	__syscall_getpmsg
 s_getpriority	getpriority getpriority	2	__syscall_getpriority
-s_getresgid	getresgid getresgid	3	__syscall_getresgid
-s_getresuid	getresuid getresuid	3	__syscall_getresuid
+getresgid	-	getresgid	3	getresgid
+getresuid	-	getresuid	3	getresuid
 s_getrlimit	getrlimit getrlimit	2	__syscall_getrlimit
 s_lstat64	lxstat64 lstat64	2	__syscall_lstat64
 s_mmap2		mmap64	mmap2		6	__syscall_mmap2
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/msgctl.c b/sysdeps/unix/sysv/linux/sparc/sparc32/msgctl.c
new file mode 100644
index 0000000000..9f9b8431a3
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/msgctl.c
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/i386/msgctl.c>
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/semctl.c b/sysdeps/unix/sysv/linux/sparc/sparc32/semctl.c
new file mode 100644
index 0000000000..e9b1a483c9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/semctl.c
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/i386/semctl.c>
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/shmctl.c b/sysdeps/unix/sysv/linux/sparc/sparc32/shmctl.c
new file mode 100644
index 0000000000..7eac6380dd
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/shmctl.c
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/i386/shmctl.c>