mirror of
https://sourceware.org/git/glibc.git
synced 2025-05-30 04:04:54 +03:00
This patch sets the mode field in ipc_perm as mode_t for all architectures, as POSIX specification [1]. The changes required are as follow: 1. It moves the ipc_perm definition out of ipc.h to its own header ipc_perm.h. It also allows consolidate the IPC_* definition on only one header. 2. The generic implementation follow the kernel ipc64_perm size so the syscall can be made directly without temporary buffer copy. However, since glibc defines the MODE field as mode_t, it omits the __PAD1 field (since glibc does not export mode_t as 16-bit for any architecture). It is a two-fold improvement: 2.1. New implementation which follow Linux UAPI will not need to provide an arch-specific ipc-perm.h header neither wrongly use the wrong 16-bit definition from previous default ipc.h (as csky did). 2.1. It allows consolidate ipc_perm definition for architectures that already provide mode_t as 32-bit. 3. All kernel ABIs for the supported architectures already provides the expected padding for mode type extension to 32-bit. However, some architectures the padding has the wrong placement, so it requires the ipc control routines (msgctl, semctl, and shmctl) to adjust the mode field accordingly. Currently they are armeb, microblaze, m68k, s390, and sheb. A new assume is added, __ASSUME_SYSVIPC_BROKEN_MODE_T, which the required ABIs define. 4. For the ABIs that define __ASSUME_SYSVIPC_BROKEN_MODE_T, it also require compat symbols that do not adjust the mode field. Checked on arm-linux-gnueabihf, aarch64-linux-gnu, powerpc64le-linux-gnu, and x86_64-linux-gnu. I also checked the sysvipc tests on hppa-linux-gnu, sh4-linux-gnu, s390x-linux-gnu, and s390-linux-gnu. I also did a sanity test against armeb qemu usermode for the sysvipc tests. [BZ #18231] * sysdeps/unix/sysv/linux/Makefile (sysdep_headers): Add bits/ipc-perm.h. * sysdeps/unix/sysv/linux/aarch64/bits/ipc.h: Remove file. * sysdeps/unix/sysv/linux/alpha/bits/ipc.h: Likewise. * sysdeps/unix/sysv/linux/hppa/bits/ipc.h: Likewise. * sysdeps/unix/sysv/linux/ia64/bits/ipc.h: Likewise. * sysdeps/unix/sysv/linux/mips/bits/ipc.h: Likewise. * sysdeps/unix/sysv/linux/powerpc/bits/ipc.h: Likewise. * sysdeps/unix/sysv/linux/s390/bits/ipc.h: Likewise. * sysdeps/unix/sysv/linux/sparc/bits/ipc.h: Likewise. * sysdeps/unix/sysv/linux/arm/kernel-features.h [__BYTE_ORDER == __BIG_ENDIAN] (__ASSUME_SYSVIPC_BROKEN_MODE_T): Define. * sysdeps/sysv/linux/microblaze/kernel-features.h: Likewise. * sysdeps/unix/sysv/linux/s390/kernel-features.h [!__s390x__] (__ASSUME_SYSVIPC_BROKEN_MODE_T): Define. * sysdeps/unix/sysv/linux/sh/kernel-features.h (__ASSUME_SYSVIPC_BROKEN_MODE_T): Define. * sysdeps/unix/sysv/linux/m68k/kernel-features.h: Likewise. * sysdeps/unix/sysv/linux/bits/ipc-perm.h: New file. * sysdeps/unix/sysv/linux/powerpc/bits/ipc-perm.h: Likewise. * sysdeps/unix/sysv/linux/sparc/bits/ipc-perm.h: Likewise. * sysdeps/unix/sysv/linux/bits/ipc.h (ipc_perm): Move to bits/ipc-perm.h. * sysdeps/unix/sysv/linux/hppa/bits/ipc-perm.h: New file. * sysdeps/unix/sysv/linux/kernel-features.h: Add comment about __ASSUME_SYSVIPC_BROKEN_MODE_T semantic. * sysdeps/unix/sysv/linux/msgctl.c (DEFAULT_VERSION): Define as 2.31 if __ASSUME_SYSVIPC_BROKEN_MODE_T is defined. (msgctl_syscall, __msgctl_mode16): New symbol. (__new_msgctl): Add bits for __ASSUME_SYSVIPC_BROKEN_MODE_T. * sysdeps/unix/sysv/linux/semctl.c: Likewise. * sysdeps/unix/sysv/linux/shmctl.c: Likewise. * sysdeps/unix/sysv/linux/arm/be/libc.abilist (GLIBC_2.31): Add msgctl, semctl, and shmctl. * sysdeps/sysv/linux/microblaze/be/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/sh/be/libc.abilist: Likewise. * conform/data/sys/ipc.h-data: Only xfail {struct ipc_perm} mode_t mode for Hurd. * sysdeps/unix/sysv/linux/m68k/Versions (libc) [GLIBC_2.31]: Add msgctl, semctl, and shmctl. * sysdeps/unix/sysv/linux/arm/be/Versions: New file. * sysdeps/unix/sysv/linux/microblaze/be/Versions: Likewise. * sysdeps/unix/sysv/linux/sh/be/Versions: Likewise. [1] http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_ipc.h.html
180 lines
4.7 KiB
C
180 lines
4.7 KiB
C
/* Copyright (C) 1995-2019 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 Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 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
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with the GNU C Library; if not, see
|
|
<https://www.gnu.org/licenses/>. */
|
|
|
|
#include <sys/sem.h>
|
|
#include <stdarg.h>
|
|
#include <ipc_priv.h>
|
|
#include <sysdep.h>
|
|
#include <shlib-compat.h>
|
|
#include <errno.h>
|
|
|
|
/* 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 */
|
|
};
|
|
|
|
#ifndef DEFAULT_VERSION
|
|
# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T
|
|
# define DEFAULT_VERSION GLIBC_2_2
|
|
# else
|
|
# define DEFAULT_VERSION GLIBC_2_31
|
|
# endif
|
|
#endif
|
|
|
|
static int
|
|
semctl_syscall (int semid, int semnum, int cmd, union semun arg)
|
|
{
|
|
#ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
|
|
return INLINE_SYSCALL_CALL (semctl, semid, semnum, cmd | __IPC_64,
|
|
arg.array);
|
|
#else
|
|
return INLINE_SYSCALL_CALL (ipc, IPCOP_semctl, semid, semnum, cmd | __IPC_64,
|
|
SEMCTL_ARG_ADDRESS (arg));
|
|
#endif
|
|
}
|
|
|
|
int
|
|
__new_semctl (int semid, int semnum, int cmd, ...)
|
|
{
|
|
/* POSIX states ipc_perm mode should have type of mode_t. */
|
|
_Static_assert (sizeof ((struct semid_ds){0}.sem_perm.mode)
|
|
== sizeof (mode_t),
|
|
"sizeof (msqid_ds.msg_perm.mode) != sizeof (mode_t)");
|
|
|
|
union semun arg = { 0 };
|
|
va_list ap;
|
|
|
|
/* Get the argument only if required. */
|
|
switch (cmd)
|
|
{
|
|
case SETVAL: /* arg.val */
|
|
case GETALL: /* arg.array */
|
|
case SETALL:
|
|
case IPC_STAT: /* arg.buf */
|
|
case IPC_SET:
|
|
case SEM_STAT:
|
|
case IPC_INFO: /* arg.__buf */
|
|
case SEM_INFO:
|
|
va_start (ap, cmd);
|
|
arg = va_arg (ap, union semun);
|
|
va_end (ap);
|
|
break;
|
|
}
|
|
|
|
#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
|
|
struct semid_ds tmpds;
|
|
if (cmd == IPC_SET)
|
|
{
|
|
tmpds = *arg.buf;
|
|
tmpds.sem_perm.mode *= 0x10000U;
|
|
arg.buf = &tmpds;
|
|
}
|
|
#endif
|
|
|
|
int ret = semctl_syscall (semid, semnum, cmd, arg);
|
|
|
|
#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
|
|
if (ret >= 0)
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case IPC_STAT:
|
|
case SEM_STAT:
|
|
case SEM_STAT_ANY:
|
|
arg.buf->sem_perm.mode >>= 16;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
versioned_symbol (libc, __new_semctl, semctl, DEFAULT_VERSION);
|
|
|
|
#if defined __ASSUME_SYSVIPC_BROKEN_MODE_T \
|
|
&& SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_31)
|
|
int
|
|
attribute_compat_text_section
|
|
__semctl_mode16 (int semid, int semnum, int cmd, ...)
|
|
{
|
|
union semun arg = { 0 };
|
|
va_list ap;
|
|
|
|
/* Get the argument only if required. */
|
|
switch (cmd)
|
|
{
|
|
case SETVAL: /* arg.val */
|
|
case GETALL: /* arg.array */
|
|
case SETALL:
|
|
case IPC_STAT: /* arg.buf */
|
|
case IPC_SET:
|
|
case SEM_STAT:
|
|
case IPC_INFO: /* arg.__buf */
|
|
case SEM_INFO:
|
|
va_start (ap, cmd);
|
|
arg = va_arg (ap, union semun);
|
|
va_end (ap);
|
|
break;
|
|
}
|
|
|
|
return semctl_syscall (semid, semnum, cmd, arg);
|
|
}
|
|
compat_symbol (libc, __semctl_mode16, semctl, GLIBC_2_2);
|
|
#endif
|
|
|
|
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
|
|
/* Since semctl use a variadic argument for semid_ds there is not need to
|
|
define and tie the compatibility symbol to the old 'union semun'
|
|
definition. */
|
|
int
|
|
attribute_compat_text_section
|
|
__old_semctl (int semid, int semnum, int cmd, ...)
|
|
{
|
|
union semun arg = { 0 };
|
|
va_list ap;
|
|
|
|
/* Get the argument only if required. */
|
|
switch (cmd)
|
|
{
|
|
case SETVAL: /* arg.val */
|
|
case GETALL: /* arg.array */
|
|
case SETALL:
|
|
case IPC_STAT: /* arg.buf */
|
|
case IPC_SET:
|
|
case SEM_STAT:
|
|
case IPC_INFO: /* arg.__buf */
|
|
case SEM_INFO:
|
|
va_start (ap, cmd);
|
|
arg = va_arg (ap, union semun);
|
|
va_end (ap);
|
|
break;
|
|
}
|
|
|
|
# ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
|
|
return INLINE_SYSCALL_CALL (semctl, semid, semnum, cmd, arg.array);
|
|
# else
|
|
return INLINE_SYSCALL_CALL (ipc, IPCOP_semctl, semid, semnum, cmd,
|
|
SEMCTL_ARG_ADDRESS (arg));
|
|
# endif
|
|
}
|
|
compat_symbol (libc, __old_semctl, semctl, GLIBC_2_0);
|
|
#endif
|