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