]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/unix/sysv/linux/msgctl.c
htl: Drop ptr_pthread_once from pthread_functions
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / msgctl.c
CommitLineData
26420023 1/* Copyright (C) 1995-2025 Free Software Foundation, Inc.
3e5f5557 2 This file is part of the GNU C Library.
28f540f4 3
3e5f5557 4 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
28f540f4 8
3e5f5557
UD
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 12 Lesser General Public License for more details.
28f540f4 13
41bdb6e2 14 You should have received a copy of the GNU Lesser General Public
59ba27a6 15 License along with the GNU C Library; if not, see
5a82c748 16 <https://www.gnu.org/licenses/>. */
28f540f4 17
d2f5be2a 18#include <sys/msg.h>
973209d8 19#include <ipc_priv.h>
e9dcb080 20#include <sysdep.h>
b5567b2a 21#include <shlib-compat.h>
356c0aab 22#include <errno.h>
60f071f4 23#include <linux/posix_types.h> /* For __kernel_mode_t. */
356c0aab 24
3283f711
AZ
25/* POSIX states ipc_perm mode should have type of mode_t. */
26_Static_assert (sizeof ((struct msqid_ds){0}.msg_perm.mode)
27 == sizeof (mode_t),
28 "sizeof (msqid_ds.msg_perm.mode) != sizeof (mode_t)");
29
30#if __IPC_TIME64 == 0
31typedef struct msqid_ds msgctl_arg_t;
32#else
33# include <struct_kernel_msqid64_ds.h>
34
35static void
36msqid64_to_kmsqid64 (const struct __msqid64_ds *msqid64,
37 struct kernel_msqid64_ds *kmsqid)
38{
39 kmsqid->msg_perm = msqid64->msg_perm;
40 kmsqid->msg_stime = msqid64->msg_stime;
41 kmsqid->msg_stime_high = msqid64->msg_stime >> 32;
42 kmsqid->msg_rtime = msqid64->msg_rtime;
43 kmsqid->msg_rtime_high = msqid64->msg_rtime >> 32;
44 kmsqid->msg_ctime = msqid64->msg_ctime;
45 kmsqid->msg_ctime_high = msqid64->msg_ctime >> 32;
46 kmsqid->msg_cbytes = msqid64->msg_cbytes;
47 kmsqid->msg_qnum = msqid64->msg_qnum;
48 kmsqid->msg_qbytes = msqid64->msg_qbytes;
49 kmsqid->msg_lspid = msqid64->msg_lspid;
50 kmsqid->msg_lrpid = msqid64->msg_lrpid;
51}
52
53static void
54kmsqid64_to_msqid64 (const struct kernel_msqid64_ds *kmsqid,
55 struct __msqid64_ds *msqid64)
56{
57 msqid64->msg_perm = kmsqid->msg_perm;
58 msqid64->msg_stime = kmsqid->msg_stime
59 | ((__time64_t) kmsqid->msg_stime_high << 32);
60 msqid64->msg_rtime = kmsqid->msg_rtime
61 | ((__time64_t) kmsqid->msg_rtime_high << 32);
62 msqid64->msg_ctime = kmsqid->msg_ctime
63 | ((__time64_t) kmsqid->msg_ctime_high << 32);
64 msqid64->msg_cbytes = kmsqid->msg_cbytes;
65 msqid64->msg_qnum = kmsqid->msg_qnum;
66 msqid64->msg_qbytes = kmsqid->msg_qbytes;
67 msqid64->msg_lspid = kmsqid->msg_lspid;
68 msqid64->msg_lrpid = kmsqid->msg_lrpid;
69}
70
71typedef struct kernel_msqid64_ds msgctl_arg_t;
356c0aab
AZ
72#endif
73
2f959dfe 74static int
3283f711 75msgctl_syscall (int msqid, int cmd, msgctl_arg_t *buf)
356c0aab
AZ
76{
77#ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
78 return INLINE_SYSCALL_CALL (msgctl, msqid, cmd | __IPC_64, buf);
79#else
80 return INLINE_SYSCALL_CALL (ipc, IPCOP_msgctl, msqid, cmd | __IPC_64, 0,
81 buf);
82#endif
83}
2f959dfe
AZ
84
85int
3283f711 86__msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf)
2f959dfe 87{
22a46dee
FW
88#if IPC_CTL_NEED_TRANSLATION
89# if __IPC_TIME64
3283f711 90 struct kernel_msqid64_ds ksemid, *arg = NULL;
22a46dee 91# else
be9b0b9a 92 msgctl_arg_t *arg;
22a46dee
FW
93# endif
94
95 /* Some applications pass the __IPC_64 flag in cmd, to invoke
96 previously unsupported commands back when there was no EINVAL
97 error checking in glibc. Mask the flag for the switch statements
98 below. msgctl_syscall adds back the __IPC_64 flag for the actual
99 system call. */
100 cmd &= ~__IPC_64;
be9b0b9a
AZ
101
102 switch (cmd)
2f959dfe 103 {
be9b0b9a
AZ
104 case IPC_RMID:
105 arg = NULL;
106 break;
107
108 case IPC_SET:
109 case IPC_STAT:
110 case MSG_STAT:
111 case MSG_STAT_ANY:
22a46dee 112# if __IPC_TIME64
be9b0b9a 113 if (buf != NULL)
20a00dbe
AZ
114 {
115 msqid64_to_kmsqid64 (buf, &ksemid);
116 arg = &ksemid;
117 }
22a46dee 118# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
be9b0b9a
AZ
119 if (cmd == IPC_SET)
120 arg->msg_perm.mode *= 0x10000U;
22a46dee
FW
121# endif
122# else
be9b0b9a 123 arg = buf;
22a46dee 124# endif
be9b0b9a
AZ
125 break;
126
127 case IPC_INFO:
128 case MSG_INFO:
129 /* This is a Linux extension where kernel returns a 'struct msginfo'
130 instead. */
131 arg = (__typeof__ (arg)) buf;
132 break;
133
134 default:
135 __set_errno (EINVAL);
136 return -1;
137 }
2f959dfe 138
3283f711
AZ
139 int ret = msgctl_syscall (msqid, cmd, arg);
140 if (ret < 0)
141 return ret;
2f959dfe 142
3283f711 143 switch (cmd)
2f959dfe 144 {
3283f711
AZ
145 case IPC_STAT:
146 case MSG_STAT:
147 case MSG_STAT_ANY:
22a46dee 148# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
3283f711 149 arg->msg_perm.mode >>= 16;
22a46dee 150# else
3283f711
AZ
151 /* Old Linux kernel versions might not clear the mode padding. */
152 if (sizeof ((struct msqid_ds){0}.msg_perm.mode)
153 != sizeof (__kernel_mode_t))
154 arg->msg_perm.mode &= 0xFFFF;
22a46dee 155# endif
3283f711 156
22a46dee 157# if __IPC_TIME64
3283f711 158 kmsqid64_to_msqid64 (arg, buf);
22a46dee 159# endif
2f959dfe 160 }
2f959dfe
AZ
161
162 return ret;
22a46dee
FW
163
164#else /* !IPC_CTL_NEED_TRANSLATION */
165 return msgctl_syscall (msqid, cmd, buf);
166#endif
2f959dfe 167}
3283f711
AZ
168#if __TIMESIZE != 64
169libc_hidden_def (__msgctl64)
170
171static void
172msqid_to_msqid64 (struct __msqid64_ds *mq64, const struct msqid_ds *mq)
173{
174 mq64->msg_perm = mq->msg_perm;
175 mq64->msg_stime = mq->msg_stime
176 | ((__time64_t) mq->__msg_stime_high << 32);
177 mq64->msg_rtime = mq->msg_rtime
178 | ((__time64_t) mq->__msg_rtime_high << 32);
179 mq64->msg_ctime = mq->msg_ctime
180 | ((__time64_t) mq->__msg_ctime_high << 32);
181 mq64->msg_cbytes = mq->msg_cbytes;
182 mq64->msg_qnum = mq->msg_qnum;
183 mq64->msg_qbytes = mq->msg_qbytes;
184 mq64->msg_lspid = mq->msg_lspid;
185 mq64->msg_lrpid = mq->msg_lrpid;
186}
187
188static void
189msqid64_to_msqid (struct msqid_ds *mq, const struct __msqid64_ds *mq64)
190{
191 mq->msg_perm = mq64->msg_perm;
192 mq->msg_stime = mq64->msg_stime;
193 mq->__msg_stime_high = 0;
194 mq->msg_rtime = mq64->msg_rtime;
195 mq->__msg_rtime_high = 0;
196 mq->msg_ctime = mq64->msg_ctime;
197 mq->__msg_ctime_high = 0;
198 mq->msg_cbytes = mq64->msg_cbytes;
199 mq->msg_qnum = mq64->msg_qnum;
200 mq->msg_qbytes = mq64->msg_qbytes;
201 mq->msg_lspid = mq64->msg_lspid;
202 mq->msg_lrpid = mq64->msg_lrpid;
203}
204
205int
206__msgctl (int msqid, int cmd, struct msqid_ds *buf)
207{
208 struct __msqid64_ds msqid64, *buf64 = NULL;
209 if (buf != NULL)
210 {
20a00dbe
AZ
211 /* This is a Linux extension where kernel returns a 'struct msginfo'
212 instead. */
213 if (cmd == IPC_INFO || cmd == MSG_INFO)
214 buf64 = (struct __msqid64_ds *) buf;
215 else
216 {
217 msqid_to_msqid64 (&msqid64, buf);
218 buf64 = &msqid64;
219 }
3283f711
AZ
220 }
221
222 int ret = __msgctl64 (msqid, cmd, buf64);
223 if (ret < 0)
224 return ret;
225
226 switch (cmd)
227 {
228 case IPC_STAT:
229 case MSG_STAT:
230 case MSG_STAT_ANY:
231 msqid64_to_msqid (buf, buf64);
232 }
233
234 return ret;
235}
236#endif
237
238#ifndef DEFAULT_VERSION
239# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T
240# define DEFAULT_VERSION GLIBC_2_2
241# else
242# define DEFAULT_VERSION GLIBC_2_31
243# endif
244#endif
245versioned_symbol (libc, __msgctl, msgctl, DEFAULT_VERSION);
e9dcb080 246
2f959dfe
AZ
247#if defined __ASSUME_SYSVIPC_BROKEN_MODE_T \
248 && SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_31)
249int
250attribute_compat_text_section
251__msgctl_mode16 (int msqid, int cmd, struct msqid_ds *buf)
252{
3283f711 253 return msgctl_syscall (msqid, cmd, (msgctl_arg_t *) buf);
2f959dfe
AZ
254}
255compat_symbol (libc, __msgctl_mode16, msgctl, GLIBC_2_2);
256#endif
0482576e 257
356c0aab 258#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
973209d8
UD
259struct __old_msqid_ds
260{
261 struct __old_ipc_perm msg_perm; /* structure describing operation permission */
70d9946a
JM
262 struct msg *__msg_first; /* pointer to first message on queue */
263 struct msg *__msg_last; /* pointer to last message on queue */
973209d8
UD
264 __time_t msg_stime; /* time of last msgsnd command */
265 __time_t msg_rtime; /* time of last msgrcv command */
266 __time_t msg_ctime; /* time of last change */
70d9946a
JM
267 struct wait_queue *__wwait; /* ??? */
268 struct wait_queue *__rwait; /* ??? */
973209d8
UD
269 unsigned short int __msg_cbytes; /* current number of bytes on queue */
270 unsigned short int msg_qnum; /* number of messages currently on queue */
271 unsigned short int msg_qbytes; /* max number of bytes allowed on queue */
272 __ipc_pid_t msg_lspid; /* pid of last msgsnd() */
273 __ipc_pid_t msg_lrpid; /* pid of last msgrcv() */
274};
275
d2f5be2a 276int
d3a4a571 277attribute_compat_text_section
0482576e 278__old_msgctl (int msqid, int cmd, struct __old_msqid_ds *buf)
d2f5be2a 279{
720e9541
AZ
280#if defined __ASSUME_DIRECT_SYSVIPC_SYSCALLS \
281 && !defined __ASSUME_SYSVIPC_DEFAULT_IPC_64
282 /* For architecture that have wire-up msgctl but also have __IPC_64 to a
283 value different than default (0x0) it means the compat symbol used the
284 __NR_ipc syscall. */
dfba907f 285 return INLINE_SYSCALL_CALL (msgctl, msqid, cmd, buf);
356c0aab
AZ
286#else
287 return INLINE_SYSCALL_CALL (ipc, IPCOP_msgctl, msqid, cmd, 0, buf);
288#endif
d2f5be2a 289}
b5567b2a
UD
290compat_symbol (libc, __old_msgctl, msgctl, GLIBC_2_0);
291#endif