]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/unix/sysv/linux/semctl.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / semctl.c
CommitLineData
d614a753 1/* Copyright (C) 1995-2020 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/sem.h>
40c0a780 20#include <stdarg.h>
973209d8 21#include <ipc_priv.h>
e9dcb080 22#include <sysdep.h>
b5567b2a 23#include <shlib-compat.h>
40c0a780 24#include <errno.h>
973209d8 25
8be1539f
UD
26/* Define a `union semun' suitable for Linux here. */
27union semun
28{
29 int val; /* value for SETVAL */
30 struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
31 unsigned short int *array; /* array for GETALL & SETALL */
32 struct seminfo *__buf; /* buffer for IPC_INFO */
33};
34
40c0a780 35#ifndef DEFAULT_VERSION
2f959dfe
AZ
36# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T
37# define DEFAULT_VERSION GLIBC_2_2
38# else
39# define DEFAULT_VERSION GLIBC_2_31
40# endif
b5567b2a 41#endif
28f540f4 42
2f959dfe
AZ
43static int
44semctl_syscall (int semid, int semnum, int cmd, union semun arg)
45{
46#ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
47 return INLINE_SYSCALL_CALL (semctl, semid, semnum, cmd | __IPC_64,
48 arg.array);
49#else
50 return INLINE_SYSCALL_CALL (ipc, IPCOP_semctl, semid, semnum, cmd | __IPC_64,
51 SEMCTL_ARG_ADDRESS (arg));
52#endif
53}
54
d2f5be2a 55int
40c0a780 56__new_semctl (int semid, int semnum, int cmd, ...)
d2f5be2a 57{
2f959dfe
AZ
58 /* POSIX states ipc_perm mode should have type of mode_t. */
59 _Static_assert (sizeof ((struct semid_ds){0}.sem_perm.mode)
60 == sizeof (mode_t),
61 "sizeof (msqid_ds.msg_perm.mode) != sizeof (mode_t)");
62
40c0a780 63 union semun arg = { 0 };
8be1539f
UD
64 va_list ap;
65
faaa6f62 66 /* Get the argument only if required. */
faaa6f62
UD
67 switch (cmd)
68 {
69 case SETVAL: /* arg.val */
70 case GETALL: /* arg.array */
71 case SETALL:
72 case IPC_STAT: /* arg.buf */
73 case IPC_SET:
74 case SEM_STAT:
75 case IPC_INFO: /* arg.__buf */
76 case SEM_INFO:
77 va_start (ap, cmd);
78 arg = va_arg (ap, union semun);
79 va_end (ap);
80 break;
81 }
8be1539f 82
2f959dfe
AZ
83#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
84 struct semid_ds tmpds;
85 if (cmd == IPC_SET)
86 {
87 tmpds = *arg.buf;
88 tmpds.sem_perm.mode *= 0x10000U;
89 arg.buf = &tmpds;
90 }
b5567b2a 91#endif
2f959dfe
AZ
92
93 int ret = semctl_syscall (semid, semnum, cmd, arg);
94
95#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
96 if (ret >= 0)
97 {
98 switch (cmd)
99 {
100 case IPC_STAT:
101 case SEM_STAT:
102 case SEM_STAT_ANY:
103 arg.buf->sem_perm.mode >>= 16;
104 }
105 }
106#endif
107
108 return ret;
40c0a780
AZ
109}
110versioned_symbol (libc, __new_semctl, semctl, DEFAULT_VERSION);
111
2f959dfe
AZ
112#if defined __ASSUME_SYSVIPC_BROKEN_MODE_T \
113 && SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_31)
114int
115attribute_compat_text_section
116__semctl_mode16 (int semid, int semnum, int cmd, ...)
117{
118 union semun arg = { 0 };
119 va_list ap;
120
121 /* Get the argument only if required. */
122 switch (cmd)
123 {
124 case SETVAL: /* arg.val */
125 case GETALL: /* arg.array */
126 case SETALL:
127 case IPC_STAT: /* arg.buf */
128 case IPC_SET:
129 case SEM_STAT:
130 case IPC_INFO: /* arg.__buf */
131 case SEM_INFO:
132 va_start (ap, cmd);
133 arg = va_arg (ap, union semun);
134 va_end (ap);
135 break;
136 }
137
138 return semctl_syscall (semid, semnum, cmd, arg);
139}
140compat_symbol (libc, __semctl_mode16, semctl, GLIBC_2_2);
141#endif
0482576e 142
40c0a780
AZ
143#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
144/* Since semctl use a variadic argument for semid_ds there is not need to
145 define and tie the compatibility symbol to the old 'union semun'
146 definition. */
0482576e 147int
40c0a780
AZ
148attribute_compat_text_section
149__old_semctl (int semid, int semnum, int cmd, ...)
0482576e 150{
40c0a780 151 union semun arg = { 0 };
0482576e
UD
152 va_list ap;
153
faaa6f62 154 /* Get the argument only if required. */
faaa6f62
UD
155 switch (cmd)
156 {
157 case SETVAL: /* arg.val */
158 case GETALL: /* arg.array */
159 case SETALL:
160 case IPC_STAT: /* arg.buf */
161 case IPC_SET:
162 case SEM_STAT:
163 case IPC_INFO: /* arg.__buf */
164 case SEM_INFO:
165 va_start (ap, cmd);
166 arg = va_arg (ap, union semun);
167 va_end (ap);
168 break;
169 }
0482576e 170
720e9541
AZ
171#if defined __ASSUME_DIRECT_SYSVIPC_SYSCALLS \
172 && !defined __ASSUME_SYSVIPC_DEFAULT_IPC_64
173 /* For architectures that have wire-up semctl but also have __IPC_64 to a
174 value different than default (0x0) it means the compat symbol used the
175 __NR_ipc syscall. */
40c0a780
AZ
176 return INLINE_SYSCALL_CALL (semctl, semid, semnum, cmd, arg.array);
177# else
178 return INLINE_SYSCALL_CALL (ipc, IPCOP_semctl, semid, semnum, cmd,
179 SEMCTL_ARG_ADDRESS (arg));
180# endif
0482576e 181}
40c0a780
AZ
182compat_symbol (libc, __old_semctl, semctl, GLIBC_2_0);
183#endif