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: msgtest.c,v 1.7 2002/07/20 08:36:25 grant Exp $ 31101902Salfred * $FreeBSD$ 32101902Salfred */ 33101902Salfred 34101902Salfred/* 35101902Salfred * Test the SVID-compatible Message Queue facility. 36101902Salfred */ 37101902Salfred 38235719Skevlo#include <sys/types.h> 39101902Salfred#include <sys/ipc.h> 40101902Salfred#include <sys/msg.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 52101902Salfredvoid print_msqid_ds (struct msqid_ds *, mode_t); 53101902Salfredvoid sigsys_handler(int); 54101902Salfredvoid sigchld_handler (int); 55101902Salfredvoid cleanup (void); 56101902Salfredvoid receiver (void); 57101902Salfredvoid usage (void); 58101902Salfred 59101902Salfred#define MESSAGE_TEXT_LEN 255 60101902Salfred 61101902Salfred/* 62101902Salfred * Define it as test_mymsg because we already have struct mymsg and we dont 63101902Salfred * want to conflict with it. Also, regression fails when the default mymsg 64101902Salfred * struct is used, because mtext[] array is '1', so the passed string cannot 65101902Salfred * be processed. 66101902Salfred */ 67101902Salfredstruct test_mymsg { 68101902Salfred long mtype; 69101902Salfred char mtext[MESSAGE_TEXT_LEN]; 70101902Salfred}; 71101902Salfred 72101902Salfredconst char *m1_str = "California is overrated."; 73101902Salfredconst char *m2_str = "The quick brown fox jumped over the lazy dog."; 74101902Salfred 75101902Salfred#define MTYPE_1 1 76101902Salfred#define MTYPE_1_ACK 2 77101902Salfred 78101902Salfred#define MTYPE_2 3 79101902Salfred#define MTYPE_2_ACK 4 80101902Salfred 81101902Salfredint sender_msqid = -1; 82101902Salfredpid_t child_pid; 83101902Salfred 84101902Salfredkey_t msgkey; 85101902Salfred 86101902Salfredint 87101902Salfredmain(int argc, char *argv[]) 88101902Salfred{ 89101902Salfred struct sigaction sa; 90101902Salfred struct msqid_ds m_ds; 91101902Salfred struct test_mymsg m; 92101902Salfred sigset_t sigmask; 93101902Salfred 94101902Salfred if (argc != 2) 95101902Salfred usage(); 96101902Salfred 97101902Salfred /* 98101902Salfred * Install a SIGSYS handler so that we can exit gracefully if 99101902Salfred * System V Message Queue support isn't in the kernel. 100101902Salfred */ 101101902Salfred sa.sa_handler = sigsys_handler; 102101902Salfred sigemptyset(&sa.sa_mask); 103101902Salfred sa.sa_flags = 0; 104101902Salfred if (sigaction(SIGSYS, &sa, NULL) == -1) 105101902Salfred err(1, "sigaction SIGSYS"); 106101902Salfred 107101902Salfred /* 108101902Salfred * Install and SIGCHLD handler to deal with all possible exit 109101902Salfred * conditions of the receiver. 110101902Salfred */ 111101902Salfred sa.sa_handler = sigchld_handler; 112101902Salfred sigemptyset(&sa.sa_mask); 113101902Salfred sa.sa_flags = 0; 114101902Salfred if (sigaction(SIGCHLD, &sa, NULL) == -1) 115101902Salfred err(1, "sigaction SIGCHLD"); 116101902Salfred 117101902Salfred msgkey = ftok(argv[1], 4160); 118101902Salfred 119101902Salfred /* 120101902Salfred * Initialize child_pid to ourselves to that the cleanup function 121101902Salfred * works before we create the receiver. 122101902Salfred */ 123101902Salfred child_pid = getpid(); 124101902Salfred 125101902Salfred /* 126101902Salfred * Make sure that when the sender exits, the message queue is 127101902Salfred * removed. 128101902Salfred */ 129101902Salfred if (atexit(cleanup) == -1) 130101902Salfred err(1, "atexit"); 131101902Salfred 132101902Salfred if ((sender_msqid = msgget(msgkey, IPC_CREAT | 0640)) == -1) 133101902Salfred err(1, "msgget"); 134101902Salfred 135101902Salfred if (msgctl(sender_msqid, IPC_STAT, &m_ds) == -1) 136101902Salfred err(1, "msgctl IPC_STAT"); 137101902Salfred 138101902Salfred print_msqid_ds(&m_ds, 0640); 139101902Salfred 140101902Salfred m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600; 141101902Salfred 142101902Salfred if (msgctl(sender_msqid, IPC_SET, &m_ds) == -1) 143101902Salfred err(1, "msgctl IPC_SET"); 144101902Salfred 145101902Salfred bzero(&m_ds, sizeof m_ds); 146101902Salfred 147101902Salfred if (msgctl(sender_msqid, IPC_STAT, &m_ds) == -1) 148101902Salfred err(1, "msgctl IPC_STAT"); 149101902Salfred 150101902Salfred if ((m_ds.msg_perm.mode & 0777) != 0600) 151101902Salfred err(1, "IPC_SET of mode didn't hold"); 152101902Salfred 153101902Salfred print_msqid_ds(&m_ds, 0600); 154101902Salfred 155101902Salfred switch ((child_pid = fork())) { 156101902Salfred case -1: 157101902Salfred err(1, "fork"); 158101902Salfred /* NOTREACHED */ 159101902Salfred 160101902Salfred case 0: 161101902Salfred receiver(); 162101902Salfred break; 163101902Salfred 164101902Salfred default: 165101902Salfred break; 166101902Salfred } 167101902Salfred 168101902Salfred /* 169101902Salfred * Send the first message to the receiver and wait for the ACK. 170101902Salfred */ 171101902Salfred m.mtype = MTYPE_1; 172101902Salfred strcpy(m.mtext, m1_str); 173164342Sjkim if (msgsnd(sender_msqid, &m, strlen(m1_str) + 1, 0) == -1) 174101902Salfred err(1, "sender: msgsnd 1"); 175101902Salfred 176164342Sjkim if (msgrcv(sender_msqid, &m, sizeof(m.mtext), MTYPE_1_ACK, 0) != 177164342Sjkim strlen(m1_str) + 1) 178101902Salfred err(1, "sender: msgrcv 1 ack"); 179101902Salfred 180101902Salfred print_msqid_ds(&m_ds, 0600); 181101902Salfred 182101902Salfred /* 183101902Salfred * Send the second message to the receiver and wait for the ACK. 184101902Salfred */ 185101902Salfred m.mtype = MTYPE_2; 186101902Salfred strcpy(m.mtext, m2_str); 187164342Sjkim if (msgsnd(sender_msqid, &m, strlen(m2_str) + 1, 0) == -1) 188101902Salfred err(1, "sender: msgsnd 2"); 189101902Salfred 190164342Sjkim if (msgrcv(sender_msqid, &m, sizeof(m.mtext), MTYPE_2_ACK, 0) != 191164342Sjkim strlen(m2_str) + 1) 192101902Salfred err(1, "sender: msgrcv 2 ack"); 193101902Salfred 194101902Salfred /* 195101902Salfred * Suspend forever; when we get SIGCHLD, the handler will exit. 196101902Salfred */ 197101902Salfred sigemptyset(&sigmask); 198101902Salfred (void) sigsuspend(&sigmask); 199101902Salfred 200101902Salfred /* 201101902Salfred * ...and any other signal is an unexpected error. 202101902Salfred */ 203101902Salfred errx(1, "sender: received unexpected signal"); 204101902Salfred} 205101902Salfred 206101902Salfredvoid 207101902Salfredsigsys_handler(int signo) 208101902Salfred{ 209101902Salfred 210101902Salfred errx(1, "System V Message Queue support is not present in the kernel"); 211101902Salfred} 212101902Salfred 213101902Salfredvoid 214101902Salfredsigchld_handler(int signo) 215101902Salfred{ 216101902Salfred struct msqid_ds m_ds; 217101902Salfred int cstatus; 218101902Salfred 219101902Salfred /* 220101902Salfred * Reap the child; if it exited successfully, then the test passed! 221101902Salfred */ 222101902Salfred if (waitpid(child_pid, &cstatus, 0) != child_pid) 223101902Salfred err(1, "waitpid"); 224101902Salfred 225101902Salfred if (WIFEXITED(cstatus) == 0) 226101902Salfred errx(1, "receiver exited abnormally"); 227101902Salfred 228101902Salfred if (WEXITSTATUS(cstatus) != 0) 229101902Salfred errx(1, "receiver exited with status %d", 230101902Salfred WEXITSTATUS(cstatus)); 231101902Salfred 232101902Salfred /* 233101902Salfred * If we get here, the child has exited normally, and thus 234101902Salfred * we should exit normally too. First, tho, we print out 235101902Salfred * the final stats for the message queue. 236101902Salfred */ 237101902Salfred 238101902Salfred if (msgctl(sender_msqid, IPC_STAT, &m_ds) == -1) 239101902Salfred err(1, "msgctl IPC_STAT"); 240101902Salfred 241101902Salfred print_msqid_ds(&m_ds, 0600); 242101902Salfred 243101902Salfred exit(0); 244101902Salfred} 245101902Salfred 246101902Salfredvoid 247101902Salfredcleanup() 248101902Salfred{ 249101902Salfred 250101902Salfred /* 251101902Salfred * If we're the sender, and it exists, remove the message queue. 252101902Salfred */ 253101902Salfred if (child_pid != 0 && sender_msqid != -1) { 254101902Salfred if (msgctl(sender_msqid, IPC_RMID, NULL) == -1) 255101902Salfred warn("msgctl IPC_RMID"); 256101902Salfred } 257101902Salfred} 258101902Salfred 259101902Salfredvoid 260101902Salfredprint_msqid_ds(struct msqid_ds *mp, mode_t mode) 261101902Salfred{ 262101902Salfred uid_t uid = geteuid(); 263101902Salfred gid_t gid = getegid(); 264101902Salfred 265101902Salfred printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 266101902Salfred mp->msg_perm.uid, mp->msg_perm.gid, 267101902Salfred mp->msg_perm.cuid, mp->msg_perm.cgid, 268101902Salfred mp->msg_perm.mode & 0777); 269101902Salfred 270101902Salfred printf("qnum %lu, qbytes %lu, lspid %d, lrpid %d\n", 271101902Salfred mp->msg_qnum, (u_long)mp->msg_qbytes, mp->msg_lspid, 272101902Salfred mp->msg_lrpid); 273101902Salfred 274101902Salfred printf("stime: %s", ctime(&mp->msg_stime)); 275101902Salfred printf("rtime: %s", ctime(&mp->msg_rtime)); 276101902Salfred printf("ctime: %s", ctime(&mp->msg_ctime)); 277101902Salfred 278101902Salfred /* 279101902Salfred * Sanity check a few things. 280101902Salfred */ 281101902Salfred 282101902Salfred if (mp->msg_perm.uid != uid || mp->msg_perm.cuid != uid) 283101902Salfred errx(1, "uid mismatch"); 284101902Salfred 285101902Salfred if (mp->msg_perm.gid != gid || mp->msg_perm.cgid != gid) 286101902Salfred errx(1, "gid mismatch"); 287101902Salfred 288101902Salfred if ((mp->msg_perm.mode & 0777) != mode) 289101902Salfred errx(1, "mode mismatch"); 290101902Salfred} 291101902Salfred 292101902Salfredvoid 293101902Salfredusage() 294101902Salfred{ 295101902Salfred 296101902Salfred fprintf(stderr, "usage: %s keypath\n", getprogname()); 297101902Salfred exit(1); 298101902Salfred} 299101902Salfred 300101902Salfredvoid 301101902Salfredreceiver() 302101902Salfred{ 303101902Salfred struct test_mymsg m; 304101902Salfred int msqid; 305101902Salfred 306101902Salfred if ((msqid = msgget(msgkey, 0)) == -1) 307101902Salfred err(1, "receiver: msgget"); 308101902Salfred 309101902Salfred /* 310101902Salfred * Receive the first message, print it, and send an ACK. 311101902Salfred */ 312101902Salfred 313164342Sjkim if (msgrcv(msqid, &m, sizeof(m.mtext), MTYPE_1, 0) != 314164342Sjkim strlen(m1_str) + 1) 315101902Salfred err(1, "receiver: msgrcv 1"); 316101902Salfred 317101902Salfred printf("%s\n", m.mtext); 318101902Salfred if (strcmp(m.mtext, m1_str) != 0) 319101902Salfred err(1, "receiver: message 1 data isn't correct"); 320101902Salfred 321101902Salfred m.mtype = MTYPE_1_ACK; 322101902Salfred 323164342Sjkim if (msgsnd(msqid, &m, strlen(m1_str) + 1, 0) == -1) 324101902Salfred err(1, "receiver: msgsnd ack 1"); 325101902Salfred 326101902Salfred /* 327101902Salfred * Receive the second message, print it, and send an ACK. 328101902Salfred */ 329101902Salfred 330164342Sjkim if (msgrcv(msqid, &m, sizeof(m.mtext), MTYPE_2, 0) != 331164342Sjkim strlen(m2_str) + 1) 332101902Salfred err(1, "receiver: msgrcv 2"); 333101902Salfred 334101902Salfred printf("%s\n", m.mtext); 335101902Salfred if (strcmp(m.mtext, m2_str) != 0) 336101902Salfred err(1, "receiver: message 2 data isn't correct"); 337101902Salfred 338101902Salfred m.mtype = MTYPE_2_ACK; 339101902Salfred 340164342Sjkim if (msgsnd(msqid, &m, strlen(m2_str) + 1, 0) == -1) 341101902Salfred err(1, "receiver: msgsnd ack 2"); 342101902Salfred 343101902Salfred exit(0); 344101902Salfred} 345