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: shmtest.c,v 1.3 2002/07/20 08:36:26 grant Exp $ 31101902Salfred * $FreeBSD$ 32101902Salfred */ 33101902Salfred 34101902Salfred/* 35101902Salfred * Test the SVID-compatible Shared Memory facility. 36101902Salfred */ 37101902Salfred 38235719Skevlo#include <sys/types.h> 39101902Salfred#include <sys/ipc.h> 40101902Salfred#include <sys/shm.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 __P((int, char *[])); 53101902Salfredvoid print_shmid_ds __P((struct shmid_ds *, mode_t)); 54101902Salfredvoid sigsys_handler __P((int)); 55101902Salfredvoid sigchld_handler __P((int)); 56101902Salfredvoid cleanup __P((void)); 57101902Salfredvoid receiver __P((void)); 58101902Salfredvoid usage __P((void)); 59101902Salfred 60101902Salfredconst char *m_str = "The quick brown fox jumped over the lazy dog."; 61101902Salfred 62101902Salfredint sender_shmid = -1; 63101902Salfredpid_t child_pid; 64101902Salfred 65101902Salfredkey_t shmkey; 66101902Salfred 67101902Salfredsize_t pgsize; 68101902Salfred 69101902Salfredint 70101902Salfredmain(argc, argv) 71101902Salfred int argc; 72101902Salfred char *argv[]; 73101902Salfred{ 74101902Salfred struct sigaction sa; 75101902Salfred struct shmid_ds s_ds; 76101902Salfred sigset_t sigmask; 77101902Salfred char *shm_buf; 78101902Salfred 79101902Salfred if (argc != 2) 80101902Salfred usage(); 81101902Salfred 82101902Salfred /* 83101902Salfred * Install a SIGSYS handler so that we can exit gracefully if 84101902Salfred * System V Shared Memory support isn't in the kernel. 85101902Salfred */ 86101902Salfred sa.sa_handler = sigsys_handler; 87101902Salfred sigemptyset(&sa.sa_mask); 88101902Salfred sa.sa_flags = 0; 89101902Salfred if (sigaction(SIGSYS, &sa, NULL) == -1) 90101902Salfred err(1, "sigaction SIGSYS"); 91101902Salfred 92101902Salfred /* 93101902Salfred * Install and SIGCHLD handler to deal with all possible exit 94101902Salfred * conditions of the receiver. 95101902Salfred */ 96101902Salfred sa.sa_handler = sigchld_handler; 97101902Salfred sigemptyset(&sa.sa_mask); 98101902Salfred sa.sa_flags = 0; 99101902Salfred if (sigaction(SIGCHLD, &sa, NULL) == -1) 100101902Salfred err(1, "sigaction SIGCHLD"); 101101902Salfred 102101902Salfred pgsize = sysconf(_SC_PAGESIZE); 103101902Salfred 104101902Salfred shmkey = ftok(argv[1], 4160); 105101902Salfred 106101902Salfred /* 107101902Salfred * Initialize child_pid to ourselves to that the cleanup function 108101902Salfred * works before we create the receiver. 109101902Salfred */ 110101902Salfred child_pid = getpid(); 111101902Salfred 112101902Salfred /* 113101902Salfred * Make sure that when the sender exits, the message queue is 114101902Salfred * removed. 115101902Salfred */ 116101902Salfred if (atexit(cleanup) == -1) 117101902Salfred err(1, "atexit"); 118101902Salfred 119101902Salfred if ((sender_shmid = shmget(shmkey, pgsize, IPC_CREAT | 0640)) == -1) 120101902Salfred err(1, "shmget"); 121101902Salfred 122101902Salfred if (shmctl(sender_shmid, IPC_STAT, &s_ds) == -1) 123101902Salfred err(1, "shmctl IPC_STAT"); 124101902Salfred 125101902Salfred print_shmid_ds(&s_ds, 0640); 126101902Salfred 127101902Salfred s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600; 128101902Salfred 129101902Salfred if (shmctl(sender_shmid, IPC_SET, &s_ds) == -1) 130101902Salfred err(1, "shmctl IPC_SET"); 131101902Salfred 132101902Salfred memset(&s_ds, 0, sizeof(s_ds)); 133101902Salfred 134101902Salfred if (shmctl(sender_shmid, IPC_STAT, &s_ds) == -1) 135101902Salfred err(1, "shmctl IPC_STAT"); 136101902Salfred 137101902Salfred if ((s_ds.shm_perm.mode & 0777) != 0600) 138101902Salfred err(1, "IPC_SET of mode didn't hold"); 139101902Salfred 140101902Salfred print_shmid_ds(&s_ds, 0600); 141101902Salfred 142101902Salfred if ((shm_buf = shmat(sender_shmid, NULL, 0)) == (void *) -1) 143101902Salfred err(1, "sender: shmat"); 144101902Salfred 145101902Salfred /* 146101902Salfred * Write the test pattern into the shared memory buffer. 147101902Salfred */ 148101902Salfred strcpy(shm_buf, m_str); 149101902Salfred 150101902Salfred switch ((child_pid = fork())) { 151101902Salfred case -1: 152101902Salfred err(1, "fork"); 153101902Salfred /* NOTREACHED */ 154101902Salfred 155101902Salfred case 0: 156101902Salfred receiver(); 157101902Salfred break; 158101902Salfred 159101902Salfred default: 160101902Salfred break; 161101902Salfred } 162101902Salfred 163101902Salfred /* 164101902Salfred * Suspend forever; when we get SIGCHLD, the handler will exit. 165101902Salfred */ 166101902Salfred sigemptyset(&sigmask); 167101902Salfred (void) sigsuspend(&sigmask); 168101902Salfred 169101902Salfred /* 170101902Salfred * ...and any other signal is an unexpected error. 171101902Salfred */ 172101902Salfred errx(1, "sender: received unexpected signal"); 173101902Salfred} 174101902Salfred 175101902Salfredvoid 176101902Salfredsigsys_handler(signo) 177101902Salfred int signo; 178101902Salfred{ 179101902Salfred 180101902Salfred errx(1, "System V Shared Memory support is not present in the kernel"); 181101902Salfred} 182101902Salfred 183101902Salfredvoid 184101902Salfredsigchld_handler(signo) 185101902Salfred int signo; 186101902Salfred{ 187101902Salfred struct shmid_ds s_ds; 188101902Salfred int cstatus; 189101902Salfred 190101902Salfred /* 191101902Salfred * Reap the child; if it exited successfully, then the test passed! 192101902Salfred */ 193101902Salfred if (waitpid(child_pid, &cstatus, 0) != child_pid) 194101902Salfred err(1, "waitpid"); 195101902Salfred 196101902Salfred if (WIFEXITED(cstatus) == 0) 197101902Salfred errx(1, "receiver exited abnormally"); 198101902Salfred 199101902Salfred if (WEXITSTATUS(cstatus) != 0) 200101902Salfred errx(1, "receiver exited with status %d", 201101902Salfred WEXITSTATUS(cstatus)); 202101902Salfred 203101902Salfred /* 204101902Salfred * If we get here, the child has exited normally, and thus 205101902Salfred * we should exit normally too. First, tho, we print out 206101902Salfred * the final stats for the message queue. 207101902Salfred */ 208101902Salfred 209101902Salfred if (shmctl(sender_shmid, IPC_STAT, &s_ds) == -1) 210101902Salfred err(1, "shmctl IPC_STAT"); 211101902Salfred 212101902Salfred print_shmid_ds(&s_ds, 0600); 213101902Salfred 214101902Salfred exit(0); 215101902Salfred} 216101902Salfred 217101902Salfredvoid 218101902Salfredcleanup() 219101902Salfred{ 220101902Salfred 221101902Salfred /* 222101902Salfred * If we're the sender, and it exists, remove the shared memory area. 223101902Salfred */ 224101902Salfred if (child_pid != 0 && sender_shmid != -1) { 225101902Salfred if (shmctl(sender_shmid, IPC_RMID, NULL) == -1) 226101902Salfred warn("shmctl IPC_RMID"); 227101902Salfred } 228101902Salfred} 229101902Salfred 230101902Salfredvoid 231101902Salfredprint_shmid_ds(sp, mode) 232101902Salfred struct shmid_ds *sp; 233101902Salfred mode_t mode; 234101902Salfred{ 235101902Salfred uid_t uid = geteuid(); 236101902Salfred gid_t gid = getegid(); 237101902Salfred 238101902Salfred printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 239101902Salfred sp->shm_perm.uid, sp->shm_perm.gid, 240101902Salfred sp->shm_perm.cuid, sp->shm_perm.cgid, 241101902Salfred sp->shm_perm.mode & 0777); 242101902Salfred 243101902Salfred printf("segsz %lu, lpid %d, cpid %d, nattch %u\n", 244101902Salfred (u_long)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid, 245101902Salfred sp->shm_nattch); 246101902Salfred 247101902Salfred printf("atime: %s", ctime(&sp->shm_atime)); 248101902Salfred printf("dtime: %s", ctime(&sp->shm_dtime)); 249101902Salfred printf("ctime: %s", ctime(&sp->shm_ctime)); 250101902Salfred 251101902Salfred /* 252101902Salfred * Sanity check a few things. 253101902Salfred */ 254101902Salfred 255101902Salfred if (sp->shm_perm.uid != uid || sp->shm_perm.cuid != uid) 256101902Salfred errx(1, "uid mismatch"); 257101902Salfred 258101902Salfred if (sp->shm_perm.gid != gid || sp->shm_perm.cgid != gid) 259101902Salfred errx(1, "gid mismatch"); 260101902Salfred 261101902Salfred if ((sp->shm_perm.mode & 0777) != mode) 262101902Salfred errx(1, "mode mismatch"); 263101902Salfred} 264101902Salfred 265101902Salfredvoid 266101902Salfredusage() 267101902Salfred{ 268101902Salfred 269101902Salfred fprintf(stderr, "usage: %s keypath\n", getprogname()); 270101902Salfred exit(1); 271101902Salfred} 272101902Salfred 273101902Salfredvoid 274101902Salfredreceiver() 275101902Salfred{ 276101902Salfred int shmid; 277101902Salfred void *shm_buf; 278101902Salfred 279101902Salfred if ((shmid = shmget(shmkey, pgsize, 0)) == -1) 280101902Salfred err(1, "receiver: shmget"); 281101902Salfred 282101902Salfred if ((shm_buf = shmat(shmid, NULL, 0)) == (void *) -1) 283101902Salfred err(1, "receiver: shmat"); 284101902Salfred 285101902Salfred printf("%s\n", (const char *)shm_buf); 286101902Salfred if (strcmp((const char *)shm_buf, m_str) != 0) 287101902Salfred err(1, "receiver: data isn't correct"); 288101902Salfred 289101902Salfred exit(0); 290101902Salfred} 291