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: shmtest.c,v 1.3 2002/07/20 08:36:26 grant Exp $ 38 */ 39 40 /* 41 * Test the SVID-compatible Shared Memory facility. 42 */ 43 44 #include <sys/param.h> 45 #include <sys/ipc.h> 46 #include <sys/shm.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_shmid_ds (struct shmid_ds *, mode_t); 59 void sigsys_handler (int); 60 void sigchld_handler (int); 61 void cleanup (void); 62 void receiver (void); 63 void usage (void); 64 65 const char *m_str = "The quick brown fox jumped over the lazy dog."; 66 67 int sender_shmid = -1; 68 pid_t child_pid; 69 70 key_t shmkey; 71 72 size_t pgsize; 73 74 int 75 main(argc, argv) 76 int argc; 77 char *argv[]; 78 { 79 struct sigaction sa; 80 struct shmid_ds s_ds; 81 sigset_t sigmask; 82 char *shm_buf; 83 84 if (argc != 2) 85 usage(); 86 87 /* 88 * Install a SIGSYS handler so that we can exit gracefully if 89 * System V Shared Memory support isn't in the kernel. 90 */ 91 sa.sa_handler = sigsys_handler; 92 sigemptyset(&sa.sa_mask); 93 sa.sa_flags = 0; 94 if (sigaction(SIGSYS, &sa, NULL) == -1) 95 err(1, "sigaction SIGSYS"); 96 97 /* 98 * Install and SIGCHLD handler to deal with all possible exit 99 * conditions of the receiver. 100 */ 101 sa.sa_handler = sigchld_handler; 102 sigemptyset(&sa.sa_mask); 103 sa.sa_flags = 0; 104 if (sigaction(SIGCHLD, &sa, NULL) == -1) 105 err(1, "sigaction SIGCHLD"); 106 107 pgsize = sysconf(_SC_PAGESIZE); 108 109 shmkey = ftok(argv[1], 4160); 110 111 /* 112 * Initialize child_pid to ourselves to that the cleanup function 113 * works before we create the receiver. 114 */ 115 child_pid = getpid(); 116 117 /* 118 * Make sure that when the sender exits, the message queue is 119 * removed. 120 */ 121 if (atexit(cleanup) == -1) 122 err(1, "atexit"); 123 124 if ((sender_shmid = shmget(shmkey, pgsize, IPC_CREAT | 0640)) == -1) 125 err(1, "shmget"); 126 127 if (shmctl(sender_shmid, IPC_STAT, &s_ds) == -1) 128 err(1, "shmctl IPC_STAT"); 129 130 print_shmid_ds(&s_ds, 0640); 131 132 s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600; 133 134 if (shmctl(sender_shmid, IPC_SET, &s_ds) == -1) 135 err(1, "shmctl IPC_SET"); 136 137 memset(&s_ds, 0, sizeof(s_ds)); 138 139 if (shmctl(sender_shmid, IPC_STAT, &s_ds) == -1) 140 err(1, "shmctl IPC_STAT"); 141 142 if ((s_ds.shm_perm.mode & 0777) != 0600) 143 err(1, "IPC_SET of mode didn't hold"); 144 145 print_shmid_ds(&s_ds, 0600); 146 147 if ((shm_buf = shmat(sender_shmid, NULL, 0)) == (void *) -1) 148 err(1, "sender: shmat"); 149 150 /* 151 * Write the test pattern into the shared memory buffer. 152 */ 153 strcpy(shm_buf, m_str); 154 155 switch ((child_pid = fork())) { 156 case -1: 157 err(1, "fork"); 158 /* NOTREACHED */ 159 160 case 0: 161 receiver(); 162 break; 163 164 default: 165 break; 166 } 167 168 /* 169 * Suspend forever; when we get SIGCHLD, the handler will exit. 170 */ 171 sigemptyset(&sigmask); 172 (void) sigsuspend(&sigmask); 173 174 /* 175 * ...and any other signal is an unexpected error. 176 */ 177 errx(1, "sender: received unexpected signal"); 178 } 179 180 void 181 sigsys_handler(signo) 182 int signo; 183 { 184 185 errx(1, "System V Shared Memory support is not present in the kernel"); 186 } 187 188 void 189 sigchld_handler(signo) 190 int signo; 191 { 192 struct shmid_ds s_ds; 193 int cstatus; 194 195 /* 196 * Reap the child; if it exited successfully, then the test passed! 197 */ 198 if (waitpid(child_pid, &cstatus, 0) != child_pid) 199 err(1, "waitpid"); 200 201 if (WIFEXITED(cstatus) == 0) 202 errx(1, "receiver exited abnormally"); 203 204 if (WEXITSTATUS(cstatus) != 0) 205 errx(1, "receiver exited with status %d", 206 WEXITSTATUS(cstatus)); 207 208 /* 209 * If we get here, the child has exited normally, and thus 210 * we should exit normally too. First, tho, we print out 211 * the final stats for the message queue. 212 */ 213 214 if (shmctl(sender_shmid, IPC_STAT, &s_ds) == -1) 215 err(1, "shmctl IPC_STAT"); 216 217 print_shmid_ds(&s_ds, 0600); 218 219 exit(0); 220 } 221 222 void 223 cleanup() 224 { 225 226 /* 227 * If we're the sender, and it exists, remove the shared memory area. 228 */ 229 if (child_pid != 0 && sender_shmid != -1) { 230 if (shmctl(sender_shmid, IPC_RMID, NULL) == -1) 231 warn("shmctl IPC_RMID"); 232 } 233 } 234 235 void 236 print_shmid_ds(sp, mode) 237 struct shmid_ds *sp; 238 mode_t mode; 239 { 240 uid_t uid = geteuid(); 241 gid_t gid = getegid(); 242 243 printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 244 sp->shm_perm.uid, sp->shm_perm.gid, 245 sp->shm_perm.cuid, sp->shm_perm.cgid, 246 sp->shm_perm.mode & 0777); 247 248 printf("segsz %lu, lpid %d, cpid %d, nattch %u\n", 249 (u_long)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid, 250 sp->shm_nattch); 251 252 printf("atime: %s", ctime(&sp->shm_atime)); 253 printf("dtime: %s", ctime(&sp->shm_dtime)); 254 printf("ctime: %s", ctime(&sp->shm_ctime)); 255 256 /* 257 * Sanity check a few things. 258 */ 259 260 if (sp->shm_perm.uid != uid || sp->shm_perm.cuid != uid) 261 errx(1, "uid mismatch"); 262 263 if (sp->shm_perm.gid != gid || sp->shm_perm.cgid != gid) 264 errx(1, "gid mismatch"); 265 266 if ((sp->shm_perm.mode & 0777) != mode) 267 errx(1, "mode mismatch"); 268 } 269 270 void 271 usage() 272 { 273 274 fprintf(stderr, "usage: %s keypath\n", getprogname()); 275 exit(1); 276 } 277 278 void 279 receiver() 280 { 281 int shmid; 282 void *shm_buf; 283 284 if ((shmid = shmget(shmkey, pgsize, 0)) == -1) 285 err(1, "receiver: shmget"); 286 287 if ((shm_buf = shmat(shmid, NULL, 0)) == (void *) -1) 288 err(1, "receiver: shmat"); 289 290 printf("%s\n", (const char *)shm_buf); 291 if (strcmp((const char *)shm_buf, m_str) != 0) 292 err(1, "receiver: data isn't correct"); 293 294 exit(0); 295 } 296