xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/ipc/semctl/semctl01.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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