1101902Salfred/*- 2101902Salfred * Copyright (c) 1999 The NetBSD Foundation, Inc. 3101902Salfred * All rights reserved. 4101902Salfred * 5101902Salfred * This code is derived from software contributed to The NetBSD Foundation 6101902Salfred * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 7101902Salfred * NASA Ames Research Center. 8101902Salfred * 9101902Salfred * Redistribution and use in source and binary forms, with or without 10101902Salfred * modification, are permitted provided that the following conditions 11101902Salfred * are met: 12101902Salfred * 1. Redistributions of source code must retain the above copyright 13101902Salfred * notice, this list of conditions and the following disclaimer. 14101902Salfred * 2. Redistributions in binary form must reproduce the above copyright 15101902Salfred * notice, this list of conditions and the following disclaimer in the 16101902Salfred * documentation and/or other materials provided with the distribution. 17101902Salfred * 18101902Salfred * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19101902Salfred * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20101902Salfred * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21101902Salfred * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22101902Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23101902Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24101902Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25101902Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26101902Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27101902Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28101902Salfred * POSSIBILITY OF SUCH DAMAGE. 29101902Salfred * 30101902Salfred * Obtained from: $NetBSD: semtest.c,v 1.4 2002/07/20 08:36:25 grant Exp $ 31101902Salfred * $FreeBSD$ 32101902Salfred */ 33101902Salfred 34101902Salfred/* 35101902Salfred * Test the SVID-compatible Semaphore facility. 36101902Salfred */ 37101902Salfred 38235719Skevlo#include <sys/types.h> 39101902Salfred#include <sys/ipc.h> 40101902Salfred#include <sys/sem.h> 41101902Salfred#include <sys/wait.h> 42101902Salfred 43101902Salfred#include <err.h> 44101902Salfred#include <errno.h> 45101902Salfred#include <signal.h> 46101902Salfred#include <stdio.h> 47101902Salfred#include <stdlib.h> 48101902Salfred#include <string.h> 49101902Salfred#include <time.h> 50101902Salfred#include <unistd.h> 51101902Salfred 52101902Salfredint main (int, char *[]); 53101902Salfredvoid print_semid_ds (struct semid_ds *, mode_t); 54101902Salfredvoid sigsys_handler (int); 55101902Salfredvoid sigchld_handler(int); 56101902Salfredvoid cleanup (void); 57101902Salfredvoid waiter (void); 58101902Salfredvoid usage (void); 59101902Salfred 60101902Salfredint sender_semid = -1; 61101902Salfredpid_t child_pid; 62101902Salfredint child_count; 63101902Salfredint signal_was_sigchld; 64101902Salfred 65101902Salfredkey_t semkey; 66101902Salfred 67101902Salfred/* 68101902Salfred * This is the original semun union used by the sysvsem utility. 69101902Salfred * It is deliberately kept here under #if 0'ed condition for future 70101902Salfred * reference. PLEASE DO NOT REMOVE. The {SET,GET}ALL in FreeBSD 71101902Salfred * are signed values, so the default version in sys/sem.h suffices. 72101902Salfred */ 73101902Salfred#if 0 74101902Salfredunion semun { 75101902Salfred int val; /* value for SETVAL */ 76101902Salfred struct semid_ds *buf; /* buffer for IPC_{STAT,SET} */ 77101902Salfred u_short *array; /* array for GETALL & SETALL */ 78101902Salfred}; 79101902Salfred#endif 80101902Salfred 81101902Salfredint 82101902Salfredmain(int argc, char *argv[]) 83101902Salfred{ 84101902Salfred struct sigaction sa; 85101902Salfred union semun sun; 86101902Salfred struct semid_ds s_ds; 87101902Salfred sigset_t sigmask; 88101902Salfred int i; 89101902Salfred 90101902Salfred if (argc != 2) 91101902Salfred usage(); 92101902Salfred 93101902Salfred /* 94101902Salfred * Install a SIGSYS handler so that we can exit gracefully if 95101902Salfred * System V Semaphore support isn't in the kernel. 96101902Salfred */ 97101902Salfred sa.sa_handler = sigsys_handler; 98101902Salfred sigemptyset(&sa.sa_mask); 99101902Salfred sa.sa_flags = 0; 100101902Salfred if (sigaction(SIGSYS, &sa, NULL) == -1) 101101902Salfred err(1, "sigaction SIGSYS"); 102101902Salfred 103101902Salfred /* 104101902Salfred * Install and SIGCHLD handler to deal with all possible exit 105101902Salfred * conditions of the receiver. 106101902Salfred */ 107101902Salfred sa.sa_handler = sigchld_handler; 108101902Salfred sigemptyset(&sa.sa_mask); 109101902Salfred sa.sa_flags = 0; 110101902Salfred if (sigaction(SIGCHLD, &sa, NULL) == -1) 111101902Salfred err(1, "sigaction SIGCHLD"); 112101902Salfred 113101902Salfred semkey = ftok(argv[1], 4160); 114101902Salfred 115101902Salfred /* 116101902Salfred * Initialize child_pid to ourselves to that the cleanup function 117101902Salfred * works before we create the receiver. 118101902Salfred */ 119101902Salfred child_pid = getpid(); 120101902Salfred 121101902Salfred /* 122101902Salfred * Make sure that when the sender exits, the message queue is 123101902Salfred * removed. 124101902Salfred */ 125101902Salfred if (atexit(cleanup) == -1) 126101902Salfred err(1, "atexit"); 127101902Salfred 128101902Salfred if ((sender_semid = semget(semkey, 1, IPC_CREAT | 0640)) == -1) 129101902Salfred err(1, "semget"); 130101902Salfred 131101902Salfred 132101902Salfred sun.buf = &s_ds; 133101902Salfred if (semctl(sender_semid, 0, IPC_STAT, sun) == -1) 134101902Salfred err(1, "semctl IPC_STAT"); 135101902Salfred 136101902Salfred print_semid_ds(&s_ds, 0640); 137101902Salfred 138101902Salfred s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600; 139101902Salfred 140101902Salfred sun.buf = &s_ds; 141101902Salfred if (semctl(sender_semid, 0, IPC_SET, sun) == -1) 142101902Salfred err(1, "semctl IPC_SET"); 143101902Salfred 144101902Salfred memset(&s_ds, 0, sizeof(s_ds)); 145101902Salfred 146101902Salfred sun.buf = &s_ds; 147101902Salfred if (semctl(sender_semid, 0, IPC_STAT, sun) == -1) 148101902Salfred err(1, "semctl IPC_STAT"); 149101902Salfred 150101902Salfred if ((s_ds.sem_perm.mode & 0777) != 0600) 151101902Salfred err(1, "IPC_SET of mode didn't hold"); 152101902Salfred 153101902Salfred print_semid_ds(&s_ds, 0600); 154101902Salfred 155101902Salfred for (child_count = 0; child_count < 5; child_count++) { 156101902Salfred switch ((child_pid = fork())) { 157101902Salfred case -1: 158101902Salfred err(1, "fork"); 159101902Salfred /* NOTREACHED */ 160101902Salfred 161101902Salfred case 0: 162101902Salfred waiter(); 163101902Salfred break; 164101902Salfred 165101902Salfred default: 166101902Salfred break; 167101902Salfred } 168101902Salfred } 169101902Salfred 170101902Salfred /* 171101902Salfred * Wait for all of the waiters to be attempting to acquire the 172101902Salfred * semaphore. 173101902Salfred */ 174101902Salfred for (;;) { 175101902Salfred i = semctl(sender_semid, 0, GETNCNT); 176101902Salfred if (i == -1) 177101902Salfred err(1, "semctl GETNCNT"); 178101902Salfred if (i == 5) 179101902Salfred break; 180101902Salfred } 181101902Salfred 182101902Salfred /* 183101902Salfred * Now set the thundering herd in motion by initializing the 184101902Salfred * semaphore to the value 1. 185101902Salfred */ 186101902Salfred sun.val = 1; 187101902Salfred if (semctl(sender_semid, 0, SETVAL, sun) == -1) 188101902Salfred err(1, "sender: semctl SETVAL to 1"); 189101902Salfred 190101902Salfred /* 191101902Salfred * Suspend forever; when we get SIGCHLD, the handler will exit. 192101902Salfred */ 193101902Salfred sigemptyset(&sigmask); 194101902Salfred for (;;) { 195101902Salfred (void) sigsuspend(&sigmask); 196101902Salfred if (signal_was_sigchld) 197101902Salfred signal_was_sigchld = 0; 198101902Salfred else 199101902Salfred break; 200101902Salfred } 201101902Salfred 202101902Salfred /* 203101902Salfred * ...and any other signal is an unexpected error. 204101902Salfred */ 205101902Salfred errx(1, "sender: received unexpected signal"); 206101902Salfred} 207101902Salfred 208101902Salfredvoid 209101902Salfredsigsys_handler(int signo) 210101902Salfred{ 211101902Salfred 212101902Salfred errx(1, "System V Semaphore support is not present in the kernel"); 213101902Salfred} 214101902Salfred 215101902Salfredvoid 216101902Salfredsigchld_handler(int signo) 217101902Salfred{ 218101902Salfred union semun sun; 219101902Salfred struct semid_ds s_ds; 220101902Salfred int cstatus; 221101902Salfred 222101902Salfred /* 223101902Salfred * Reap the child; if it exited successfully, then we're on the 224101902Salfred * right track! 225101902Salfred */ 226101902Salfred if (wait(&cstatus) == -1) 227101902Salfred err(1, "wait"); 228101902Salfred 229101902Salfred if (WIFEXITED(cstatus) == 0) 230101902Salfred errx(1, "receiver exited abnormally"); 231101902Salfred 232101902Salfred if (WEXITSTATUS(cstatus) != 0) 233101902Salfred errx(1, "receiver exited with status %d", 234101902Salfred WEXITSTATUS(cstatus)); 235101902Salfred 236101902Salfred /* 237101902Salfred * If we get here, the child has exited normally, and we should 238101902Salfred * decrement the child count. If the child_count reaches 0, we 239101902Salfred * should exit. 240101902Salfred */ 241101902Salfred 242101902Salfred sun.buf = &s_ds; 243101902Salfred if (semctl(sender_semid, 0, IPC_STAT, sun) == -1) 244101902Salfred err(1, "semctl IPC_STAT"); 245101902Salfred 246101902Salfred print_semid_ds(&s_ds, 0600); 247101902Salfred 248101902Salfred if (--child_count != 0) { 249101902Salfred signal_was_sigchld = 1; 250101902Salfred return; 251101902Salfred } 252101902Salfred 253101902Salfred exit(0); 254101902Salfred} 255101902Salfred 256101902Salfredvoid 257101902Salfredcleanup() 258101902Salfred{ 259101902Salfred 260101902Salfred /* 261101902Salfred * If we're the sender, and it exists, remove the message queue. 262101902Salfred */ 263101902Salfred if (child_pid != 0 && sender_semid != -1) { 264101902Salfred if (semctl(sender_semid, 0, IPC_RMID) == -1) 265101902Salfred warn("semctl IPC_RMID"); 266101902Salfred } 267101902Salfred} 268101902Salfred 269101902Salfredvoid 270101902Salfredprint_semid_ds(struct semid_ds *sp, mode_t mode) 271101902Salfred{ 272101902Salfred uid_t uid = geteuid(); 273101902Salfred gid_t gid = getegid(); 274101902Salfred 275101902Salfred printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 276101902Salfred sp->sem_perm.uid, sp->sem_perm.gid, 277101902Salfred sp->sem_perm.cuid, sp->sem_perm.cgid, 278101902Salfred sp->sem_perm.mode & 0777); 279101902Salfred 280101902Salfred printf("nsems %u\n", sp->sem_nsems); 281101902Salfred 282101902Salfred printf("otime: %s", ctime(&sp->sem_otime)); 283101902Salfred printf("ctime: %s", ctime(&sp->sem_ctime)); 284101902Salfred 285101902Salfred /* 286101902Salfred * Sanity check a few things. 287101902Salfred */ 288101902Salfred 289101902Salfred if (sp->sem_perm.uid != uid || sp->sem_perm.cuid != uid) 290101902Salfred errx(1, "uid mismatch"); 291101902Salfred 292101902Salfred if (sp->sem_perm.gid != gid || sp->sem_perm.cgid != gid) 293101902Salfred errx(1, "gid mismatch"); 294101902Salfred 295101902Salfred if ((sp->sem_perm.mode & 0777) != mode) 296101902Salfred errx(1, "mode mismatch %o != %o", 297101902Salfred (sp->sem_perm.mode & 0777), mode); 298101902Salfred} 299101902Salfred 300101902Salfredvoid 301101902Salfredusage() 302101902Salfred{ 303101902Salfred 304101902Salfred fprintf(stderr, "usage: %s keypath\n", getprogname()); 305101902Salfred exit(1); 306101902Salfred} 307101902Salfred 308101902Salfredvoid 309101902Salfredwaiter() 310101902Salfred{ 311101902Salfred struct sembuf s; 312101902Salfred int semid; 313101902Salfred 314101902Salfred if ((semid = semget(semkey, 1, 0)) == -1) 315101902Salfred err(1, "waiter: semget"); 316101902Salfred 317101902Salfred /* 318101902Salfred * Attempt to acquire the semaphore. 319101902Salfred */ 320101902Salfred s.sem_num = 0; 321101902Salfred s.sem_op = -1; 322101902Salfred s.sem_flg = SEM_UNDO; 323101902Salfred 324101902Salfred if (semop(semid, &s, 1) == -1) 325101902Salfred err(1, "waiter: semop -1"); 326101902Salfred 327101902Salfred printf("WOO! GOT THE SEMAPHORE!\n"); 328101902Salfred sleep(1); 329101902Salfred 330101902Salfred /* 331101902Salfred * Release the semaphore and exit. 332101902Salfred */ 333101902Salfred s.sem_num = 0; 334101902Salfred s.sem_op = 1; 335101902Salfred s.sem_flg = SEM_UNDO; 336101902Salfred 337101902Salfred if (semop(semid, &s, 1) == -1) 338101902Salfred err(1, "waiter: semop +1"); 339101902Salfred 340101902Salfred exit(0); 341101902Salfred} 342