1 /* $OpenBSD: msgtest.c,v 1.7 2021/12/13 16:56:50 deraadt Exp $ */ 2 /* $NetBSD: msgtest.c,v 1.6 2001/02/19 22:44:41 cgd Exp $ */ 3 4 /*- 5 * Copyright (c) 1999 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10 * NASA Ames Research Center. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Test the SVID-compatible Message Queue facility. 36 */ 37 38 #include <sys/ipc.h> 39 #include <sys/msg.h> 40 #include <sys/wait.h> 41 42 #include <err.h> 43 #include <errno.h> 44 #include <signal.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <time.h> 49 #include <unistd.h> 50 51 int main(int, char *[]); 52 void print_msqid_ds(struct msqid_ds *, mode_t); 53 void sigsys_handler(int); 54 void sigchld_handler(int); 55 void cleanup(void); 56 void receiver(void); 57 58 #define MESSAGE_TEXT_LEN 256 59 60 struct thismsg { 61 long mtype; 62 char mtext[MESSAGE_TEXT_LEN]; 63 }; 64 65 const char *m1_str = "California is overrated."; 66 const char *m2_str = "The quick brown fox jumped over the lazy dog."; 67 68 #define MTYPE_1 1 69 #define MTYPE_1_ACK 2 70 71 #define MTYPE_2 3 72 #define MTYPE_2_ACK 4 73 74 int sender_msqid = -1; 75 pid_t child_pid; 76 77 key_t msgkey; 78 79 char keyname[] = "/tmp/msgtestXXXXXXXX"; 80 81 int verbose; 82 83 int 84 main(int argc, char **argv) 85 { 86 struct sigaction sa; 87 struct msqid_ds m_ds; 88 struct thismsg m; 89 sigset_t sigmask; 90 int fd, ch; 91 92 if ((fd = mkstemp(keyname)) < 0) 93 err(1, "mkstemp"); 94 95 close(fd); 96 97 while ((ch = getopt(argc, argv, "v")) != -1) { 98 switch (ch) { 99 case 'v': 100 verbose = 1; 101 break; 102 default: 103 fprintf(stderr, "Usage: msgtest [-v]\n"); 104 exit(1); 105 } 106 } 107 108 /* 109 * Install a SIGSYS handler so that we can exit gracefully if 110 * System V Message Queue support isn't in the kernel. 111 */ 112 sa.sa_handler = sigsys_handler; 113 sigemptyset(&sa.sa_mask); 114 sa.sa_flags = 0; 115 if (sigaction(SIGSYS, &sa, NULL) == -1) 116 err(1, "sigaction SIGSYS"); 117 118 /* 119 * Install and SIGCHLD handler to deal with all possible exit 120 * conditions of the receiver. 121 */ 122 sa.sa_handler = sigchld_handler; 123 sigemptyset(&sa.sa_mask); 124 sa.sa_flags = 0; 125 if (sigaction(SIGCHLD, &sa, NULL) == -1) 126 err(1, "sigaction SIGCHLD"); 127 128 msgkey = ftok(keyname, 4160); 129 130 /* 131 * Initialize child_pid to ourselves to that the cleanup function 132 * works before we create the receiver. 133 */ 134 child_pid = getpid(); 135 136 /* 137 * Make sure that when the sender exits, the message queue is 138 * removed. 139 */ 140 if (atexit(cleanup) == -1) 141 err(1, "atexit"); 142 143 if ((sender_msqid = msgget(msgkey, IPC_CREAT | 0640)) == -1) 144 err(1, "msgget"); 145 146 if (msgctl(sender_msqid, IPC_STAT, &m_ds) == -1) 147 err(1, "msgctl IPC_STAT"); 148 149 if (verbose) 150 print_msqid_ds(&m_ds, 0640); 151 152 m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600; 153 154 if (msgctl(sender_msqid, IPC_SET, &m_ds) == -1) 155 err(1, "msgctl IPC_SET"); 156 157 memset(&m_ds, 0, sizeof(m_ds)); 158 159 if (msgctl(sender_msqid, IPC_STAT, &m_ds) == -1) 160 err(1, "msgctl IPC_STAT"); 161 162 if ((m_ds.msg_perm.mode & 0777) != 0600) 163 err(1, "IPC_SET of mode didn't hold"); 164 165 if (verbose) 166 print_msqid_ds(&m_ds, 0600); 167 168 switch ((child_pid = fork())) { 169 case -1: 170 err(1, "fork"); 171 /* NOTREACHED */ 172 173 case 0: 174 receiver(); 175 break; 176 177 default: 178 break; 179 } 180 181 /* 182 * Send the first message to the receiver and wait for the ACK. 183 */ 184 m.mtype = MTYPE_1; 185 strlcpy(m.mtext, m1_str, sizeof m.mtext); 186 if (msgsnd(sender_msqid, &m, sizeof(m), 0) == -1) 187 err(1, "sender: msgsnd 1"); 188 189 if (msgrcv(sender_msqid, &m, sizeof(m), MTYPE_1_ACK, 0) != sizeof(m)) 190 err(1, "sender: msgrcv 1 ack"); 191 192 if (verbose) 193 print_msqid_ds(&m_ds, 0600); 194 195 /* 196 * Send the second message to the receiver and wait for the ACK. 197 */ 198 m.mtype = MTYPE_2; 199 strlcpy(m.mtext, m2_str, sizeof m.mtext); 200 if (msgsnd(sender_msqid, &m, sizeof(m), 0) == -1) 201 err(1, "sender: msgsnd 2"); 202 203 if (msgrcv(sender_msqid, &m, sizeof(m), MTYPE_2_ACK, 0) != sizeof(m)) 204 err(1, "sender: msgrcv 2 ack"); 205 206 /* 207 * Suspend forever; when we get SIGCHLD, the handler will exit. 208 */ 209 sigemptyset(&sigmask); 210 (void) sigsuspend(&sigmask); 211 212 /* 213 * ...and any other signal is an unexpected error. 214 */ 215 errx(1, "sender: received unexpected signal"); 216 } 217 218 void 219 sigsys_handler(signo) 220 int signo; 221 { 222 223 errx(1, "System V Message Queue support is not present in the kernel"); 224 } 225 226 void 227 sigchld_handler(signo) 228 int signo; 229 { 230 struct msqid_ds m_ds; 231 int cstatus; 232 233 /* 234 * Reap the child; if it exited successfully, then the test passed! 235 */ 236 if (waitpid(child_pid, &cstatus, 0) != child_pid) 237 err(1, "waitpid"); 238 239 if (WIFEXITED(cstatus) == 0) 240 errx(1, "receiver exited abnormally"); 241 242 if (WEXITSTATUS(cstatus) != 0) 243 errx(1, "receiver exited with status %d", 244 WEXITSTATUS(cstatus)); 245 246 /* 247 * If we get here, the child has exited normally, and thus 248 * we should exit normally too. First, tho, we print out 249 * the final stats for the message queue. 250 */ 251 252 if (msgctl(sender_msqid, IPC_STAT, &m_ds) == -1) 253 err(1, "msgctl IPC_STAT"); 254 255 if (verbose) 256 print_msqid_ds(&m_ds, 0600); 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_msqid != -1) { 269 if (msgctl(sender_msqid, IPC_RMID, NULL) == -1) 270 warn("msgctl IPC_RMID"); 271 } 272 273 remove(keyname); 274 } 275 276 void 277 print_msqid_ds(mp, mode) 278 struct msqid_ds *mp; 279 mode_t mode; 280 { 281 uid_t uid = geteuid(); 282 gid_t gid = getegid(); 283 284 printf("PERM: uid %u, gid %u, cuid %u, cgid %u, mode 0%o\n", 285 mp->msg_perm.uid, mp->msg_perm.gid, 286 mp->msg_perm.cuid, mp->msg_perm.cgid, 287 mp->msg_perm.mode & 0777); 288 289 printf("qnum %lu, qbytes %lu, lspid %d, lrpid %d\n", 290 mp->msg_qnum, (u_long)mp->msg_qbytes, mp->msg_lspid, 291 mp->msg_lrpid); 292 293 printf("stime: %s", ctime(&mp->msg_stime)); 294 printf("rtime: %s", ctime(&mp->msg_rtime)); 295 printf("ctime: %s", ctime(&mp->msg_ctime)); 296 297 /* 298 * Sanity check a few things. 299 */ 300 301 if (mp->msg_perm.uid != uid || mp->msg_perm.cuid != uid) 302 errx(1, "uid mismatch"); 303 304 if (mp->msg_perm.gid != gid || mp->msg_perm.cgid != gid) 305 errx(1, "gid mismatch"); 306 307 if ((mp->msg_perm.mode & 0777) != mode) 308 errx(1, "mode mismatch"); 309 } 310 311 void 312 receiver() 313 { 314 struct thismsg m; 315 int msqid; 316 317 if ((msqid = msgget(msgkey, 0)) == -1) 318 err(1, "receiver: msgget"); 319 320 /* 321 * Receive the first message, print it, and send an ACK. 322 */ 323 324 if (msgrcv(msqid, &m, sizeof(m), MTYPE_1, 0) != sizeof(m)) 325 err(1, "receiver: msgrcv 1"); 326 327 if (verbose) 328 printf("%s\n", m.mtext); 329 if (strcmp(m.mtext, m1_str) != 0) 330 err(1, "receiver: message 1 data isn't correct"); 331 332 m.mtype = MTYPE_1_ACK; 333 334 if (msgsnd(msqid, &m, sizeof(m), 0) == -1) 335 err(1, "receiver: msgsnd ack 1"); 336 337 /* 338 * Receive the second message, print it, and send an ACK. 339 */ 340 341 if (msgrcv(msqid, &m, sizeof(m), MTYPE_2, 0) != sizeof(m)) 342 err(1, "receiver: msgrcv 2"); 343 344 if (verbose) 345 printf("%s\n", m.mtext); 346 if (strcmp(m.mtext, m2_str) != 0) 347 err(1, "receiver: message 2 data isn't correct"); 348 349 m.mtype = MTYPE_2_ACK; 350 351 if (msgsnd(msqid, &m, sizeof(m), 0) == -1) 352 err(1, "receiver: msgsnd ack 2"); 353 354 exit(0); 355 } 356