1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) International Business Machines Corp., 2001
4 */
5 /*\
6 * [Description]
7 *
8 * Test the 13 possible semctl() commands
9 */
10
11 #define _GNU_SOURCE
12 #include <stdlib.h>
13 #include "tst_safe_sysv_ipc.h"
14 #include "tst_test.h"
15 #include "lapi/sem.h"
16 #include "libnewipc.h"
17
18 #define INCVAL 2
19 #define NEWMODE 066
20 #define NCHILD 5
21 #define SEMUN_CAST (union semun)
22
23 static int sem_id = -1;
24 static int sem_index;
25 static struct semid_ds buf;
26 static struct seminfo ipc_buf;
27 static unsigned short array[PSEMS];
28 static struct sembuf sops;
29 static int pid_arr[NCHILD];
30
kill_all_children(void)31 static void kill_all_children(void)
32 {
33 int j;
34
35 for (j = 0; j < NCHILD; j++)
36 SAFE_KILL(pid_arr[j], SIGKILL);
37
38 for (j = 0; j < NCHILD; j++)
39 SAFE_WAIT(NULL);
40 }
41
func_stat(void)42 static void func_stat(void)
43 {
44 if (buf.sem_nsems == PSEMS && buf.sem_perm.mode == (SEM_RA))
45 tst_res(TPASS, "buf.sem_nsems and buf.sem_perm.mode are correct");
46 else
47 tst_res(TFAIL, "semaphore STAT info is incorrect");
48 }
49
set_setup(void)50 static void set_setup(void)
51 {
52 buf.sem_perm.mode = SEM_RA | NEWMODE;
53 }
54
func_set(void)55 static void func_set(void)
56 {
57 SAFE_SEMCTL(sem_id, 0, IPC_STAT, (union semun)&buf);
58
59 if (buf.sem_perm.mode == (SEM_RA | NEWMODE))
60 tst_res(TPASS, "buf.sem_perm.mode is correct");
61 else
62 tst_res(TFAIL, "semaphore mode info is incorrect");
63 }
64
func_gall(void)65 static void func_gall(void)
66 {
67 int i;
68
69 for (i = 0; i < PSEMS; i++) {
70 if (array[i] != 0) {
71 tst_res(TFAIL, "semaphore %d has unexpected value", i);
72 return;
73 }
74 }
75 tst_res(TPASS, "semaphores have expected values");
76 }
77
child_cnt(void)78 static void child_cnt(void)
79 {
80 sops.sem_num = 4;
81 sops.sem_flg = 0;
82
83 /*
84 * Do a semop that will cause the child to sleep.
85 * The child process will be killed in the func_ncnt
86 * routine which should cause an error to be return
87 * by the semop() call.
88 */
89 if (semop(sem_id, &sops, 1) != -1)
90 tst_brk(TBROK, "semop succeeded - cnt_setup");
91 }
92
cnt_setup(int opval)93 static void cnt_setup(int opval)
94 {
95 int pid, i;
96
97 sops.sem_num = 4;
98 sops.sem_flg = 0;
99 /*
100 * if seting up for GETZCNT, the semaphore value needs to be positive
101 */
102 if (opval == 0) {
103 sops.sem_op = 1;
104 SAFE_SEMOP(sem_id, &sops, 1);
105 }
106
107 sops.sem_op = opval;
108 for (i = 0; i < NCHILD; i++) {
109 pid = SAFE_FORK();
110 if (pid == 0) {
111 child_cnt();
112 } else {
113 TST_PROCESS_STATE_WAIT(pid, 'S', 0);
114 pid_arr[i] = pid;
115 }
116 }
117 }
118
func_cnt(int rval)119 static void func_cnt(int rval)
120 {
121 if (rval == NCHILD)
122 tst_res(TPASS, "number of sleeping processes is correct");
123 else
124 tst_res(TFAIL, "number of sleeping processes is not correct");
125 }
126
child_pid(void)127 static void child_pid(void)
128 {
129 sops.sem_num = 2;
130 sops.sem_op = 1;
131 sops.sem_flg = 0;
132 /*
133 * Do a semop that will increment the semaphore.
134 */
135 SAFE_SEMOP(sem_id, &sops, 1);
136 exit(0);
137 }
138
pid_setup(void)139 static void pid_setup(void)
140 {
141 int pid;
142
143 pid = SAFE_FORK();
144 if (pid == 0) {
145 child_pid();
146 } else {
147 pid_arr[2] = pid;
148 TST_PROCESS_STATE_WAIT(pid, 'Z', 0);
149 }
150 }
151
func_pid(int rval)152 static void func_pid(int rval)
153 {
154 if (rval == pid_arr[2])
155 tst_res(TPASS, "last pid value is correct");
156 else
157 tst_res(TFAIL, "last pid value is not correct");
158 }
159
func_gval(int rval)160 static void func_gval(int rval)
161 {
162 /*
163 * This is a simple test. The semaphore value should be equal
164 * to ONE as it was set in the last test (GETPID).
165 */
166 if (rval == 1)
167 tst_res(TPASS, "semaphore value is correct");
168 else
169 tst_res(TFAIL, "semaphore value is not correct");
170 }
171
sall_setup(void)172 static void sall_setup(void)
173 {
174 int i;
175
176 for (i = 0; i < PSEMS; i++) {
177 array[i] = 3;
178 }
179 }
180
func_sall(void)181 static void func_sall(void)
182 {
183 int i;
184 unsigned short rarray[PSEMS];
185
186 SAFE_SEMCTL(sem_id, 0, GETALL, (union semun)rarray);
187 for (i = 0; i < PSEMS; i++) {
188 if (array[i] != rarray[i]) {
189 tst_res(TFAIL, "semaphore values are not correct");
190 return;
191 }
192 }
193
194 tst_res(TPASS, "semaphore values are correct");
195 }
196
func_sval(void)197 static void func_sval(void)
198 {
199 int semv = SAFE_SEMCTL(sem_id, 4, GETVAL);
200
201 if (semv != INCVAL)
202 tst_res(TFAIL, "semaphore value is not what was set");
203 else
204 tst_res(TPASS, "semaphore value is correct");
205 }
206
func_rmid(void)207 static void func_rmid(void)
208 {
209 TST_EXP_FAIL(semop(sem_id, &sops, 1), EINVAL, "semaphore appears to be removed");
210 sem_id = -1;
211 }
212
func_iinfo(int hidx)213 static void func_iinfo(int hidx)
214 {
215 if (hidx >= 0) {
216 sem_index = hidx;
217 tst_res(TPASS, "the highest index is correct");
218 } else {
219 sem_index = 0;
220 tst_res(TFAIL, "the highest index is incorrect");
221 }
222 }
223
func_sinfo(void)224 static void func_sinfo(void)
225 {
226 if (ipc_buf.semusz < 1)
227 tst_res(TFAIL, "number of semaphore sets is incorrect");
228 else
229 tst_res(TPASS, "number of semaphore sets is correct");
230 }
231
func_sstat(int semidx)232 static void func_sstat(int semidx)
233 {
234 if (semidx >= 0)
235 tst_res(TPASS, "id of the semaphore set is correct");
236 else
237 tst_res(TFAIL, "id of the semaphore set is incorrect");
238 }
239
240 static struct tcases {
241 int *semid;
242 int semnum;
243 int cmd;
244 void (*func_test) ();
245 union semun arg;
246 void (*func_setup) ();
247 } tests[] = {
248 {&sem_id, 0, IPC_STAT, func_stat, SEMUN_CAST & buf, NULL},
249 {&sem_id, 0, IPC_SET, func_set, SEMUN_CAST & buf, set_setup},
250 {&sem_id, 0, GETALL, func_gall, SEMUN_CAST array, NULL},
251 {&sem_id, 4, GETNCNT, func_cnt, SEMUN_CAST & buf, cnt_setup},
252 {&sem_id, 2, GETPID, func_pid, SEMUN_CAST & buf, pid_setup},
253 {&sem_id, 2, GETVAL, func_gval, SEMUN_CAST & buf, NULL},
254 {&sem_id, 4, GETZCNT, func_cnt, SEMUN_CAST & buf, cnt_setup},
255 {&sem_id, 0, SETALL, func_sall, SEMUN_CAST array, sall_setup},
256 {&sem_id, 4, SETVAL, func_sval, SEMUN_CAST INCVAL, NULL},
257 {&sem_id, 0, IPC_INFO, func_iinfo, SEMUN_CAST & ipc_buf, NULL},
258 {&sem_id, 0, SEM_INFO, func_sinfo, SEMUN_CAST & ipc_buf, NULL},
259 {&sem_index, 0, SEM_STAT, func_sstat, SEMUN_CAST & buf, NULL},
260 {&sem_id, 0, IPC_RMID, func_rmid, SEMUN_CAST & buf, NULL},
261 };
262
verify_semctl(unsigned int n)263 static void verify_semctl(unsigned int n)
264 {
265 struct tcases *tc = &tests[n];
266 int rval;
267
268 if (sem_id == -1)
269 sem_id = SAFE_SEMGET(IPC_PRIVATE, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA);
270 if (tc->func_setup) {
271 switch (tc->cmd) {
272 case GETNCNT:
273 tc->func_setup(-1);
274 break;
275 case GETZCNT:
276 tc->func_setup(0);
277 break;
278 default:
279 tc->func_setup();
280 break;
281 }
282 }
283
284 rval = SAFE_SEMCTL(*(tc->semid), tc->semnum, tc->cmd, tc->arg);
285 switch (tc->cmd) {
286 case GETNCNT:
287 case GETZCNT:
288 case GETPID:
289 case GETVAL:
290 case IPC_INFO:
291 case SEM_STAT:
292 tc->func_test(rval);
293 break;
294 default:
295 tc->func_test();
296 break;
297 }
298
299 if (tc->cmd == GETNCNT || tc->cmd == GETZCNT)
300 kill_all_children();
301 }
302
cleanup(void)303 static void cleanup(void)
304 {
305 if (sem_id >= 0)
306 SAFE_SEMCTL(sem_id, 0, IPC_RMID);
307 }
308
309 static struct tst_test test = {
310 .cleanup = cleanup,
311 .test = verify_semctl,
312 .tcnt = ARRAY_SIZE(tests),
313 .forks_child = 1,
314 };
315