1117397Skan/* $OpenBSD: msgtest.c,v 1.7 2021/12/13 16:56:50 deraadt Exp $ */ 2117397Skan/* $NetBSD: msgtest.c,v 1.6 2001/02/19 22:44:41 cgd Exp $ */ 3117397Skan 4117397Skan/*- 5117397Skan * Copyright (c) 1999 The NetBSD Foundation, Inc. 6117397Skan * All rights reserved. 7117397Skan * 8117397Skan * This code is derived from software contributed to The NetBSD Foundation 9117397Skan * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10117397Skan * NASA Ames Research Center. 11117397Skan * 12117397Skan * Redistribution and use in source and binary forms, with or without 13117397Skan * modification, are permitted provided that the following conditions 14117397Skan * are met: 15117397Skan * 1. Redistributions of source code must retain the above copyright 16117397Skan * notice, this list of conditions and the following disclaimer. 17117397Skan * 2. Redistributions in binary form must reproduce the above copyright 18169691Skan * notice, this list of conditions and the following disclaimer in the 19117397Skan * documentation and/or other materials provided with the distribution. 20117397Skan * 21117397Skan * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22117397Skan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23117397Skan * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24117397Skan * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25117397Skan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26117397Skan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27117397Skan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28117397Skan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29117397Skan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30169691Skan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31169691Skan * POSSIBILITY OF SUCH DAMAGE. 32169691Skan */ 33169691Skan 34117397Skan/* 35132720Skan * Test the SVID-compatible Message Queue facility. 36132720Skan */ 37117397Skan 38117397Skan#include <sys/ipc.h> 39117397Skan#include <sys/msg.h> 40117397Skan#include <sys/wait.h> 41117397Skan 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 51int main(int, char *[]); 52void print_msqid_ds(struct msqid_ds *, mode_t); 53void sigsys_handler(int); 54void sigchld_handler(int); 55void cleanup(void); 56void receiver(void); 57 58#define MESSAGE_TEXT_LEN 256 59 60struct thismsg { 61 long mtype; 62 char mtext[MESSAGE_TEXT_LEN]; 63}; 64 65const char *m1_str = "California is overrated."; 66const 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 74int sender_msqid = -1; 75pid_t child_pid; 76 77key_t msgkey; 78 79char keyname[] = "/tmp/msgtestXXXXXXXX"; 80 81int verbose; 82 83int 84main(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 218void 219sigsys_handler(signo) 220 int signo; 221{ 222 223 errx(1, "System V Message Queue support is not present in the kernel"); 224} 225 226void 227sigchld_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 261void 262cleanup() 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 276void 277print_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 311void 312receiver() 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