1/* Copyright (C) 1995-2020 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19#include <sys/shm.h>
20#include <stdarg.h>
21#include <ipc_priv.h>
22#include <sysdep.h>
23#include <shlib-compat.h>
24#include <errno.h>
25
26#ifndef DEFAULT_VERSION
27# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T
28# define DEFAULT_VERSION GLIBC_2_2
29# else
30# define DEFAULT_VERSION GLIBC_2_31
31# endif
32#endif
33
34static int
35shmctl_syscall (int shmid, int cmd, struct shmid_ds *buf)
36{
37#ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
38 return INLINE_SYSCALL_CALL (shmctl, shmid, cmd | __IPC_64, buf);
39#else
40 return INLINE_SYSCALL_CALL (ipc, IPCOP_shmctl, shmid, cmd | __IPC_64, 0,
41 buf);
42#endif
43}
44
45/* Provide operations to control over shared memory segments. */
46int
47__new_shmctl (int shmid, int cmd, struct shmid_ds *buf)
48{
49 /* POSIX states ipc_perm mode should have type of mode_t. */
50 _Static_assert (sizeof ((struct shmid_ds){0}.shm_perm.mode)
51 == sizeof (mode_t),
52 "sizeof (msqid_ds.msg_perm.mode) != sizeof (mode_t)");
53
54#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
55 struct shmid_ds tmpds;
56 if (cmd == IPC_SET)
57 {
58 tmpds = *buf;
59 tmpds.shm_perm.mode *= 0x10000U;
60 buf = &tmpds;
61 }
62#endif
63
64 int ret = shmctl_syscall (shmid, cmd, buf);
65
66#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
67 if (ret >= 0)
68 {
69 switch (cmd)
70 {
71 case IPC_STAT:
72 case SHM_STAT:
73 case SHM_STAT_ANY:
74 buf->shm_perm.mode >>= 16;
75 }
76 }
77#endif
78
79 return ret;
80}
81versioned_symbol (libc, __new_shmctl, shmctl, DEFAULT_VERSION);
82
83#if defined __ASSUME_SYSVIPC_BROKEN_MODE_T \
84 && SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_31)
85int
86attribute_compat_text_section
87__shmctl_mode16 (int shmid, int cmd, struct shmid_ds *buf)
88{
89 return shmctl_syscall (shmid, cmd, buf);
90}
91compat_symbol (libc, __shmctl_mode16, shmctl, GLIBC_2_2);
92#endif
93
94#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
95struct __old_shmid_ds
96{
97 struct __old_ipc_perm shm_perm; /* operation permission struct */
98 int shm_segsz; /* size of segment in bytes */
99 __time_t shm_atime; /* time of last shmat() */
100 __time_t shm_dtime; /* time of last shmdt() */
101 __time_t shm_ctime; /* time of last change by shmctl() */
102 __ipc_pid_t shm_cpid; /* pid of creator */
103 __ipc_pid_t shm_lpid; /* pid of last shmop */
104 unsigned short int shm_nattch; /* number of current attaches */
105 unsigned short int __shm_npages; /* size of segment (pages) */
106 unsigned long int *__shm_pages; /* array of ptrs to frames -> SHMMAX */
107 struct vm_area_struct *__attaches; /* descriptors for attaches */
108};
109
110int
111attribute_compat_text_section
112__old_shmctl (int shmid, int cmd, struct __old_shmid_ds *buf)
113{
114#if defined __ASSUME_DIRECT_SYSVIPC_SYSCALLS \
115 && !defined __ASSUME_SYSVIPC_DEFAULT_IPC_64
116 /* For architecture that have wire-up shmctl but also have __IPC_64 to a
117 value different than default (0x0), it means the compat symbol used the
118 __NR_ipc syscall. */
119 return INLINE_SYSCALL_CALL (shmctl, shmid, cmd, buf);
120#else
121 return INLINE_SYSCALL_CALL (ipc, IPCOP_shmctl, shmid, cmd, 0, buf);
122#endif
123}
124compat_symbol (libc, __old_shmctl, shmctl, GLIBC_2_0);
125#endif
126