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 23static int sem_id = -1; 24static int sem_index; 25static struct semid_ds buf; 26static struct seminfo ipc_buf; 27static unsigned short array[PSEMS]; 28static struct sembuf sops; 29static int pid_arr[NCHILD]; 30 31static 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 42static 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 50static void set_setup(void) 51{ 52 buf.sem_perm.mode = SEM_RA | NEWMODE; 53} 54 55static 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 65static 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 78static 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 93static 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 119static 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 127static 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 139static 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 152static 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 160static 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 172static void sall_setup(void) 173{ 174 int i; 175 176 for (i = 0; i < PSEMS; i++) { 177 array[i] = 3; 178 } 179} 180 181static 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 197static 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 207static 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 213static 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 224static 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 232static 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 240static 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 263static 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 303static void cleanup(void) 304{ 305 if (sem_id >= 0) 306 SAFE_SEMCTL(sem_id, 0, IPC_RMID); 307} 308 309static struct tst_test test = { 310 .cleanup = cleanup, 311 .test = verify_semctl, 312 .tcnt = ARRAY_SIZE(tests), 313 .forks_child = 1, 314}; 315