1 /*- 2 * Copyright (c) 1999 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 7 * NASA Ames Research Center. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the NetBSD 20 * Foundation, Inc. and its contributors. 21 * 4. Neither the name of The NetBSD Foundation nor the names of its 22 * contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Obtained from: $NetBSD: semtest.c,v 1.4 2002/07/20 08:36:25 grant Exp $ 38 */ 39 40 /* 41 * Test the SVID-compatible Semaphore facility. 42 */ 43 44 #include <sys/param.h> 45 #include <sys/ipc.h> 46 #include <sys/sem.h> 47 #include <sys/wait.h> 48 49 #include <err.h> 50 #include <errno.h> 51 #include <signal.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <time.h> 56 #include <unistd.h> 57 58 void print_semid_ds (struct semid_ds *, mode_t); 59 void sigsys_handler (int); 60 void sigchld_handler(int); 61 void cleanup (void); 62 void waiter (void); 63 void usage (void); 64 65 int sender_semid = -1; 66 pid_t child_pid; 67 int child_count; 68 int signal_was_sigchld; 69 70 key_t semkey; 71 72 /* 73 * This is the original semun union used by the sysvsem utility. 74 * It is deliberately kept here under #if 0'ed condition for future 75 * reference. PLEASE DO NOT REMOVE. The {SET,GET}ALL in DragonFly 76 * are signed values, so the default version in sys/sem.h suffices. 77 */ 78 #if 0 79 union semun { 80 int val; /* value for SETVAL */ 81 struct semid_ds *buf; /* buffer for IPC_{STAT,SET} */ 82 u_short *array; /* array for GETALL & SETALL */ 83 }; 84 #endif 85 86 int 87 main(int argc, char *argv[]) 88 { 89 struct sigaction sa; 90 union semun sun; 91 struct semid_ds s_ds; 92 sigset_t sigmask; 93 int i; 94 95 if (argc != 2) 96 usage(); 97 98 /* 99 * Install a SIGSYS handler so that we can exit gracefully if 100 * System V Semaphore support isn't in the kernel. 101 */ 102 sa.sa_handler = sigsys_handler; 103 sigemptyset(&sa.sa_mask); 104 sa.sa_flags = 0; 105 if (sigaction(SIGSYS, &sa, NULL) == -1) 106 err(1, "sigaction SIGSYS"); 107 108 /* 109 * Install and SIGCHLD handler to deal with all possible exit 110 * conditions of the receiver. 111 */ 112 sa.sa_handler = sigchld_handler; 113 sigemptyset(&sa.sa_mask); 114 sa.sa_flags = 0; 115 if (sigaction(SIGCHLD, &sa, NULL) == -1) 116 err(1, "sigaction SIGCHLD"); 117 118 semkey = ftok(argv[1], 4160); 119 120 /* 121 * Initialize child_pid to ourselves to that the cleanup function 122 * works before we create the receiver. 123 */ 124 child_pid = getpid(); 125 126 /* 127 * Make sure that when the sender exits, the message queue is 128 * removed. 129 */ 130 if (atexit(cleanup) == -1) 131 err(1, "atexit"); 132 133 if ((sender_semid = semget(semkey, 1, IPC_CREAT | 0640)) == -1) 134 err(1, "semget"); 135 136 137 sun.buf = &s_ds; 138 if (semctl(sender_semid, 0, IPC_STAT, sun) == -1) 139 err(1, "semctl IPC_STAT"); 140 141 print_semid_ds(&s_ds, 0640); 142 143 s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600; 144 145 sun.buf = &s_ds; 146 if (semctl(sender_semid, 0, IPC_SET, sun) == -1) 147 err(1, "semctl IPC_SET"); 148 149 memset(&s_ds, 0, sizeof(s_ds)); 150 151 sun.buf = &s_ds; 152 if (semctl(sender_semid, 0, IPC_STAT, sun) == -1) 153 err(1, "semctl IPC_STAT"); 154 155 if ((s_ds.sem_perm.mode & 0777) != 0600) 156 err(1, "IPC_SET of mode didn't hold"); 157 158 print_semid_ds(&s_ds, 0600); 159 160 for (child_count = 0; child_count < 5; child_count++) { 161 switch ((child_pid = fork())) { 162 case -1: 163 err(1, "fork"); 164 /* NOTREACHED */ 165 166 case 0: 167 waiter(); 168 break; 169 170 default: 171 break; 172 } 173 } 174 175 /* 176 * Wait for all of the waiters to be attempting to acquire the 177 * semaphore. 178 */ 179 for (;;) { 180 i = semctl(sender_semid, 0, GETNCNT); 181 if (i == -1) 182 err(1, "semctl GETNCNT"); 183 if (i == 5) 184 break; 185 } 186 187 /* 188 * Now set the thundering herd in motion by initializing the 189 * semaphore to the value 1. 190 */ 191 sun.val = 1; 192 if (semctl(sender_semid, 0, SETVAL, sun) == -1) 193 err(1, "sender: semctl SETVAL to 1"); 194 195 /* 196 * Suspend forever; when we get SIGCHLD, the handler will exit. 197 */ 198 sigemptyset(&sigmask); 199 for (;;) { 200 (void) sigsuspend(&sigmask); 201 if (signal_was_sigchld) 202 signal_was_sigchld = 0; 203 else 204 break; 205 } 206 207 /* 208 * ...and any other signal is an unexpected error. 209 */ 210 errx(1, "sender: received unexpected signal"); 211 } 212 213 void 214 sigsys_handler(int signo) 215 { 216 217 errx(1, "System V Semaphore support is not present in the kernel"); 218 } 219 220 void 221 sigchld_handler(int signo) 222 { 223 union semun sun; 224 struct semid_ds s_ds; 225 int cstatus; 226 227 /* 228 * Reap the child; if it exited successfully, then we're on the 229 * right track! 230 */ 231 if (wait(&cstatus) == -1) 232 err(1, "wait"); 233 234 if (WIFEXITED(cstatus) == 0) 235 errx(1, "receiver exited abnormally"); 236 237 if (WEXITSTATUS(cstatus) != 0) 238 errx(1, "receiver exited with status %d", 239 WEXITSTATUS(cstatus)); 240 241 /* 242 * If we get here, the child has exited normally, and we should 243 * decrement the child count. If the child_count reaches 0, we 244 * should exit. 245 */ 246 247 sun.buf = &s_ds; 248 if (semctl(sender_semid, 0, IPC_STAT, sun) == -1) 249 err(1, "semctl IPC_STAT"); 250 251 print_semid_ds(&s_ds, 0600); 252 253 if (--child_count != 0) { 254 signal_was_sigchld = 1; 255 return; 256 } 257 258 exit(0); 259 } 260 261 void 262 cleanup() 263 { 264 265 /* 266 * If we're the sender, and it exists, remove the message queue. 267 */ 268 if (child_pid != 0 && sender_semid != -1) { 269 if (semctl(sender_semid, 0, IPC_RMID) == -1) 270 warn("semctl IPC_RMID"); 271 } 272 } 273 274 void 275 print_semid_ds(struct semid_ds *sp, mode_t mode) 276 { 277 uid_t uid = geteuid(); 278 gid_t gid = getegid(); 279 280 printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 281 sp->sem_perm.uid, sp->sem_perm.gid, 282 sp->sem_perm.cuid, sp->sem_perm.cgid, 283 sp->sem_perm.mode & 0777); 284 285 printf("nsems %u\n", sp->sem_nsems); 286 287 printf("otime: %s", ctime(&sp->sem_otime)); 288 printf("ctime: %s", ctime(&sp->sem_ctime)); 289 290 /* 291 * Sanity check a few things. 292 */ 293 294 if (sp->sem_perm.uid != uid || sp->sem_perm.cuid != uid) 295 errx(1, "uid mismatch"); 296 297 if (sp->sem_perm.gid != gid || sp->sem_perm.cgid != gid) 298 errx(1, "gid mismatch"); 299 300 if ((sp->sem_perm.mode & 0777) != mode) 301 errx(1, "mode mismatch %o != %o", 302 (sp->sem_perm.mode & 0777), mode); 303 } 304 305 void 306 usage() 307 { 308 309 fprintf(stderr, "usage: %s keypath\n", getprogname()); 310 exit(1); 311 } 312 313 void 314 waiter() 315 { 316 struct sembuf s; 317 int semid; 318 319 if ((semid = semget(semkey, 1, 0)) == -1) 320 err(1, "waiter: semget"); 321 322 /* 323 * Attempt to acquire the semaphore. 324 */ 325 s.sem_num = 0; 326 s.sem_op = -1; 327 s.sem_flg = SEM_UNDO; 328 329 if (semop(semid, &s, 1) == -1) 330 err(1, "waiter: semop -1"); 331 332 printf("WOO! GOT THE SEMAPHORE!\n"); 333 sleep(1); 334 335 /* 336 * Release the semaphore and exit. 337 */ 338 s.sem_num = 0; 339 s.sem_op = 1; 340 s.sem_flg = SEM_UNDO; 341 342 if (semop(semid, &s, 1) == -1) 343 err(1, "waiter: semop +1"); 344 345 exit(0); 346 } 347