diff options
Diffstat (limited to 'sysdeps/unix/sysv/linux/shmctl.c')
-rw-r--r-- | sysdeps/unix/sysv/linux/shmctl.c | 181 |
1 files changed, 147 insertions, 34 deletions
diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c index f41b359b8b..76d88441f1 100644 --- a/sysdeps/unix/sysv/linux/shmctl.c +++ b/sysdeps/unix/sysv/linux/shmctl.c @@ -24,16 +24,55 @@ #include <errno.h> #include <linux/posix_types.h> /* For __kernel_mode_t. */ -#ifndef DEFAULT_VERSION -# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T -# define DEFAULT_VERSION GLIBC_2_2 -# else -# define DEFAULT_VERSION GLIBC_2_31 -# endif +/* POSIX states ipc_perm mode should have type of mode_t. */ +_Static_assert (sizeof ((struct shmid_ds){0}.shm_perm.mode) + == sizeof (mode_t), + "sizeof (shmid_ds.shm_perm.mode) != sizeof (mode_t)"); + +#if __IPC_TIME64 == 0 +typedef struct shmid_ds shmctl_arg_t; +#else +# include <struct_kernel_shmid64_ds.h> + +static void +shmid64_to_kshmid64 (const struct __shmid64_ds *shmid64, + struct kernel_shmid64_ds *kshmid) +{ + kshmid->shm_perm = shmid64->shm_perm; + kshmid->shm_segsz = shmid64->shm_segsz; + kshmid->shm_atime = shmid64->shm_atime; + kshmid->shm_atime_high = shmid64->shm_atime >> 32; + kshmid->shm_dtime = shmid64->shm_dtime; + kshmid->shm_dtime_high = shmid64->shm_dtime >> 32; + kshmid->shm_ctime = shmid64->shm_ctime; + kshmid->shm_ctime_high = shmid64->shm_ctime >> 32; + kshmid->shm_cpid = shmid64->shm_cpid; + kshmid->shm_lpid = shmid64->shm_lpid; + kshmid->shm_nattch = shmid64->shm_nattch; +} + +static void +kshmid64_to_shmid64 (const struct kernel_shmid64_ds *kshmid, + struct __shmid64_ds *shmid64) +{ + shmid64->shm_perm = kshmid->shm_perm; + shmid64->shm_segsz = kshmid->shm_segsz; + shmid64->shm_atime = kshmid->shm_atime + | ((__time64_t) kshmid->shm_atime_high << 32); + shmid64->shm_dtime = kshmid->shm_dtime + | ((__time64_t) kshmid->shm_dtime_high << 32); + shmid64->shm_ctime = kshmid->shm_ctime + | ((__time64_t) kshmid->shm_ctime_high << 32); + shmid64->shm_cpid = kshmid->shm_cpid; + shmid64->shm_lpid = kshmid->shm_lpid; + shmid64->shm_nattch = kshmid->shm_nattch; +} + +typedef struct kernel_shmid64_ds shmctl_arg_t; #endif static int -shmctl_syscall (int shmid, int cmd, struct shmid_ds *buf) +shmctl_syscall (int shmid, int cmd, shmctl_arg_t *buf) { #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS return INLINE_SYSCALL_CALL (shmctl, shmid, cmd | __IPC_64, buf); @@ -45,46 +84,120 @@ shmctl_syscall (int shmid, int cmd, struct shmid_ds *buf) /* Provide operations to control over shared memory segments. */ int -__new_shmctl (int shmid, int cmd, struct shmid_ds *buf) +__shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) { - /* POSIX states ipc_perm mode should have type of mode_t. */ - _Static_assert (sizeof ((struct shmid_ds){0}.shm_perm.mode) - == sizeof (mode_t), - "sizeof (msqid_ds.msg_perm.mode) != sizeof (mode_t)"); - -#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T - struct shmid_ds tmpds; - if (cmd == IPC_SET) +#if __IPC_TIME64 + struct kernel_shmid64_ds kshmid, *arg = NULL; + if (buf != NULL) { - tmpds = *buf; - tmpds.shm_perm.mode *= 0x10000U; - buf = &tmpds; + shmid64_to_kshmid64 (buf, &kshmid); + arg = &kshmid; } +# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T + if (cmd == IPC_SET) + arg->shm_perm.mode *= 0x10000U; +# endif +#else + shmctl_arg_t *arg = buf; #endif - int ret = shmctl_syscall (shmid, cmd, buf); + int ret = shmctl_syscall (shmid, cmd, arg); + if (ret < 0) + return ret; - if (ret >= 0) + switch (cmd) { - switch (cmd) - { - case IPC_STAT: - case SHM_STAT: - case SHM_STAT_ANY: + case IPC_INFO: + case IPC_STAT: + case SHM_STAT: + case SHM_STAT_ANY: #ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T - buf->shm_perm.mode >>= 16; + arg->shm_perm.mode >>= 16; #else - /* Old Linux kernel versions might not clear the mode padding. */ - if (sizeof ((struct shmid_ds){0}.shm_perm.mode) - != sizeof (__kernel_mode_t)) - buf->shm_perm.mode &= 0xFFFF; + /* Old Linux kernel versions might not clear the mode padding. */ + if (sizeof ((struct shmid_ds){0}.shm_perm.mode) + != sizeof (__kernel_mode_t)) + arg->shm_perm.mode &= 0xFFFF; +#endif + +#if __IPC_TIME64 + kshmid64_to_shmid64 (arg, buf); #endif - } } return ret; } -versioned_symbol (libc, __new_shmctl, shmctl, DEFAULT_VERSION); +#if __TIMESIZE != 64 +libc_hidden_def (__shmctl64) + +static void +shmid_to_shmid64 (struct __shmid64_ds *shm64, const struct shmid_ds *shm) +{ + shm64->shm_perm = shm->shm_perm; + shm64->shm_segsz = shm->shm_segsz; + shm64->shm_atime = shm->shm_atime + | ((__time64_t) shm->__shm_atime_high << 32); + shm64->shm_dtime = shm->shm_dtime + | ((__time64_t) shm->__shm_dtime_high << 32); + shm64->shm_ctime = shm->shm_ctime + | ((__time64_t) shm->__shm_ctime_high << 32); + shm64->shm_cpid = shm->shm_cpid; + shm64->shm_lpid = shm->shm_lpid; + shm64->shm_nattch = shm->shm_nattch; +} + +static void +shmid64_to_shmid (struct shmid_ds *shm, const struct __shmid64_ds *shm64) +{ + shm->shm_perm = shm64->shm_perm; + shm->shm_segsz = shm64->shm_segsz; + shm->shm_atime = shm64->shm_atime; + shm->__shm_atime_high = 0; + shm->shm_dtime = shm64->shm_dtime; + shm->__shm_dtime_high = 0; + shm->shm_ctime = shm64->shm_ctime; + shm->__shm_ctime_high = 0; + shm->shm_cpid = shm64->shm_cpid; + shm->shm_lpid = shm64->shm_lpid; + shm->shm_nattch = shm64->shm_nattch; +} + +int +__shmctl (int shmid, int cmd, struct shmid_ds *buf) +{ + struct __shmid64_ds shmid64, *buf64 = NULL; + if (buf != NULL) + { + shmid_to_shmid64 (&shmid64, buf); + buf64 = &shmid64; + } + + int ret = __shmctl64 (shmid, cmd, buf64); + if (ret < 0) + return ret; + + switch (cmd) + { + case IPC_INFO: + case IPC_STAT: + case SHM_STAT: + case SHM_STAT_ANY: + shmid64_to_shmid (buf, buf64); + } + + return ret; +} +#endif + +#ifndef DEFAULT_VERSION +# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T +# define DEFAULT_VERSION GLIBC_2_2 +# else +# define DEFAULT_VERSION GLIBC_2_31 +# endif +#endif + +versioned_symbol (libc, __shmctl, shmctl, DEFAULT_VERSION); #if defined __ASSUME_SYSVIPC_BROKEN_MODE_T \ && SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_31) @@ -92,7 +205,7 @@ int attribute_compat_text_section __shmctl_mode16 (int shmid, int cmd, struct shmid_ds *buf) { - return shmctl_syscall (shmid, cmd, buf); + return shmctl_syscall (shmid, cmd, (shmctl_arg_t *) buf); } compat_symbol (libc, __shmctl_mode16, shmctl, GLIBC_2_2); #endif |