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