]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/unix/sysv/linux/shmctl.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / shmctl.c
CommitLineData
2b778ceb 1/* Copyright (C) 1995-2021 Free Software Foundation, Inc.
3e5f5557
UD
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995.
28f540f4 4
3e5f5557 5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
28f540f4 9
3e5f5557
UD
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
41bdb6e2 13 Lesser General Public License for more details.
28f540f4 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
28f540f4 18
d2f5be2a 19#include <sys/shm.h>
e01f79e4 20#include <stdarg.h>
973209d8 21#include <ipc_priv.h>
e9dcb080 22#include <sysdep.h>
b5567b2a 23#include <shlib-compat.h>
e01f79e4 24#include <errno.h>
60f071f4 25#include <linux/posix_types.h> /* For __kernel_mode_t. */
e01f79e4 26
ffd178c6
AZ
27/* POSIX states ipc_perm mode should have type of mode_t. */
28_Static_assert (sizeof ((struct shmid_ds){0}.shm_perm.mode)
29 == sizeof (mode_t),
30 "sizeof (shmid_ds.shm_perm.mode) != sizeof (mode_t)");
31
32#if __IPC_TIME64 == 0
33typedef struct shmid_ds shmctl_arg_t;
34#else
35# include <struct_kernel_shmid64_ds.h>
36
37static void
38shmid64_to_kshmid64 (const struct __shmid64_ds *shmid64,
39 struct kernel_shmid64_ds *kshmid)
40{
41 kshmid->shm_perm = shmid64->shm_perm;
42 kshmid->shm_segsz = shmid64->shm_segsz;
43 kshmid->shm_atime = shmid64->shm_atime;
44 kshmid->shm_atime_high = shmid64->shm_atime >> 32;
45 kshmid->shm_dtime = shmid64->shm_dtime;
46 kshmid->shm_dtime_high = shmid64->shm_dtime >> 32;
47 kshmid->shm_ctime = shmid64->shm_ctime;
48 kshmid->shm_ctime_high = shmid64->shm_ctime >> 32;
49 kshmid->shm_cpid = shmid64->shm_cpid;
50 kshmid->shm_lpid = shmid64->shm_lpid;
51 kshmid->shm_nattch = shmid64->shm_nattch;
52}
53
54static void
55kshmid64_to_shmid64 (const struct kernel_shmid64_ds *kshmid,
56 struct __shmid64_ds *shmid64)
57{
58 shmid64->shm_perm = kshmid->shm_perm;
59 shmid64->shm_segsz = kshmid->shm_segsz;
60 shmid64->shm_atime = kshmid->shm_atime
61 | ((__time64_t) kshmid->shm_atime_high << 32);
62 shmid64->shm_dtime = kshmid->shm_dtime
63 | ((__time64_t) kshmid->shm_dtime_high << 32);
64 shmid64->shm_ctime = kshmid->shm_ctime
65 | ((__time64_t) kshmid->shm_ctime_high << 32);
66 shmid64->shm_cpid = kshmid->shm_cpid;
67 shmid64->shm_lpid = kshmid->shm_lpid;
68 shmid64->shm_nattch = kshmid->shm_nattch;
69}
70
71typedef struct kernel_shmid64_ds shmctl_arg_t;
e01f79e4 72#endif
0482576e 73
2f959dfe 74static int
ffd178c6 75shmctl_syscall (int shmid, int cmd, shmctl_arg_t *buf)
e01f79e4
AZ
76{
77#ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
78 return INLINE_SYSCALL_CALL (shmctl, shmid, cmd | __IPC_64, buf);
79#else
80 return INLINE_SYSCALL_CALL (ipc, IPCOP_shmctl, shmid, cmd | __IPC_64, 0,
81 buf);
82#endif
83}
2f959dfe
AZ
84
85/* Provide operations to control over shared memory segments. */
86int
ffd178c6 87__shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf)
2f959dfe 88{
ffd178c6
AZ
89#if __IPC_TIME64
90 struct kernel_shmid64_ds kshmid, *arg = NULL;
9ebaabea
AZ
91#else
92 shmctl_arg_t *arg;
93#endif
94
95 switch (cmd)
2f959dfe 96 {
9ebaabea
AZ
97 case IPC_RMID:
98 case SHM_LOCK:
99 case SHM_UNLOCK:
100 arg = NULL;
101 break;
102
103 case IPC_SET:
104 case IPC_STAT:
105 case SHM_STAT:
106 case SHM_STAT_ANY:
107#if __IPC_TIME64
108 if (buf != NULL)
a49d7fd4
AZ
109 {
110 shmid64_to_kshmid64 (buf, &kshmid);
111 arg = &kshmid;
112 }
ffd178c6 113# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
9ebaabea
AZ
114 if (cmd == IPC_SET)
115 arg->shm_perm.mode *= 0x10000U;
ffd178c6
AZ
116# endif
117#else
9ebaabea 118 arg = buf;
2f959dfe 119#endif
9ebaabea
AZ
120 break;
121
122 case IPC_INFO:
123 case SHM_INFO:
124 /* This is a Linux extension where kernel expects either a
125 'struct shminfo' (IPC_INFO) or 'struct shm_info' (SHM_INFO). */
126 arg = (__typeof__ (arg)) buf;
127 break;
128
129 default:
130 __set_errno (EINVAL);
131 return -1;
132 }
133
2f959dfe 134
ffd178c6
AZ
135 int ret = shmctl_syscall (shmid, cmd, arg);
136 if (ret < 0)
137 return ret;
2f959dfe 138
ffd178c6 139 switch (cmd)
2f959dfe 140 {
ffd178c6
AZ
141 case IPC_STAT:
142 case SHM_STAT:
143 case SHM_STAT_ANY:
24fdebe7 144#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
ffd178c6 145 arg->shm_perm.mode >>= 16;
24fdebe7 146#else
ffd178c6
AZ
147 /* Old Linux kernel versions might not clear the mode padding. */
148 if (sizeof ((struct shmid_ds){0}.shm_perm.mode)
149 != sizeof (__kernel_mode_t))
150 arg->shm_perm.mode &= 0xFFFF;
151#endif
152
153#if __IPC_TIME64
154 kshmid64_to_shmid64 (arg, buf);
24fdebe7 155#endif
2f959dfe 156 }
2f959dfe
AZ
157
158 return ret;
159}
ffd178c6
AZ
160#if __TIMESIZE != 64
161libc_hidden_def (__shmctl64)
162
163static void
164shmid_to_shmid64 (struct __shmid64_ds *shm64, const struct shmid_ds *shm)
165{
166 shm64->shm_perm = shm->shm_perm;
167 shm64->shm_segsz = shm->shm_segsz;
168 shm64->shm_atime = shm->shm_atime
169 | ((__time64_t) shm->__shm_atime_high << 32);
170 shm64->shm_dtime = shm->shm_dtime
171 | ((__time64_t) shm->__shm_dtime_high << 32);
172 shm64->shm_ctime = shm->shm_ctime
173 | ((__time64_t) shm->__shm_ctime_high << 32);
174 shm64->shm_cpid = shm->shm_cpid;
175 shm64->shm_lpid = shm->shm_lpid;
176 shm64->shm_nattch = shm->shm_nattch;
177}
178
179static void
180shmid64_to_shmid (struct shmid_ds *shm, const struct __shmid64_ds *shm64)
181{
182 shm->shm_perm = shm64->shm_perm;
183 shm->shm_segsz = shm64->shm_segsz;
184 shm->shm_atime = shm64->shm_atime;
185 shm->__shm_atime_high = 0;
186 shm->shm_dtime = shm64->shm_dtime;
187 shm->__shm_dtime_high = 0;
188 shm->shm_ctime = shm64->shm_ctime;
189 shm->__shm_ctime_high = 0;
190 shm->shm_cpid = shm64->shm_cpid;
191 shm->shm_lpid = shm64->shm_lpid;
192 shm->shm_nattch = shm64->shm_nattch;
193}
194
195int
196__shmctl (int shmid, int cmd, struct shmid_ds *buf)
197{
198 struct __shmid64_ds shmid64, *buf64 = NULL;
199 if (buf != NULL)
200 {
a49d7fd4
AZ
201 /* This is a Linux extension where kernel expects either a
202 'struct shminfo' (IPC_INFO) or 'struct shm_info' (SHM_INFO). */
203 if (cmd == IPC_INFO || cmd == SHM_INFO)
204 buf64 = (struct __shmid64_ds *) buf;
205 else
206 {
207 shmid_to_shmid64 (&shmid64, buf);
208 buf64 = &shmid64;
209 }
ffd178c6
AZ
210 }
211
212 int ret = __shmctl64 (shmid, cmd, buf64);
213 if (ret < 0)
214 return ret;
215
216 switch (cmd)
217 {
ffd178c6
AZ
218 case IPC_STAT:
219 case SHM_STAT:
220 case SHM_STAT_ANY:
221 shmid64_to_shmid (buf, buf64);
222 }
223
224 return ret;
225}
226#endif
227
228#ifndef DEFAULT_VERSION
229# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T
230# define DEFAULT_VERSION GLIBC_2_2
231# else
232# define DEFAULT_VERSION GLIBC_2_31
233# endif
234#endif
235
236versioned_symbol (libc, __shmctl, shmctl, DEFAULT_VERSION);
e01f79e4 237
2f959dfe
AZ
238#if defined __ASSUME_SYSVIPC_BROKEN_MODE_T \
239 && SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_31)
240int
241attribute_compat_text_section
242__shmctl_mode16 (int shmid, int cmd, struct shmid_ds *buf)
243{
ffd178c6 244 return shmctl_syscall (shmid, cmd, (shmctl_arg_t *) buf);
2f959dfe
AZ
245}
246compat_symbol (libc, __shmctl_mode16, shmctl, GLIBC_2_2);
247#endif
e01f79e4
AZ
248
249#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
973209d8
UD
250struct __old_shmid_ds
251{
252 struct __old_ipc_perm shm_perm; /* operation permission struct */
253 int shm_segsz; /* size of segment in bytes */
254 __time_t shm_atime; /* time of last shmat() */
255 __time_t shm_dtime; /* time of last shmdt() */
256 __time_t shm_ctime; /* time of last change by shmctl() */
257 __ipc_pid_t shm_cpid; /* pid of creator */
258 __ipc_pid_t shm_lpid; /* pid of last shmop */
259 unsigned short int shm_nattch; /* number of current attaches */
260 unsigned short int __shm_npages; /* size of segment (pages) */
70d9946a
JM
261 unsigned long int *__shm_pages; /* array of ptrs to frames -> SHMMAX */
262 struct vm_area_struct *__attaches; /* descriptors for attaches */
973209d8
UD
263};
264
d2f5be2a 265int
d3a4a571 266attribute_compat_text_section
0482576e 267__old_shmctl (int shmid, int cmd, struct __old_shmid_ds *buf)
d2f5be2a 268{
720e9541
AZ
269#if defined __ASSUME_DIRECT_SYSVIPC_SYSCALLS \
270 && !defined __ASSUME_SYSVIPC_DEFAULT_IPC_64
271 /* For architecture that have wire-up shmctl but also have __IPC_64 to a
272 value different than default (0x0), it means the compat symbol used the
273 __NR_ipc syscall. */
e01f79e4
AZ
274 return INLINE_SYSCALL_CALL (shmctl, shmid, cmd, buf);
275#else
276 return INLINE_SYSCALL_CALL (ipc, IPCOP_shmctl, shmid, cmd, 0, buf);
277#endif
d2f5be2a 278}
b5567b2a
UD
279compat_symbol (libc, __old_shmctl, shmctl, GLIBC_2_0);
280#endif