Path: blob/main/tools/regression/sysvmsg/msgtest.c
39476 views
/*-1* Copyright (c) 1999 The NetBSD Foundation, Inc.2* All rights reserved.3*4* This code is derived from software contributed to The NetBSD Foundation5* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,6* NASA Ames Research Center.7*8* Redistribution and use in source and binary forms, with or without9* modification, are permitted provided that the following conditions10* are met:11* 1. Redistributions of source code must retain the above copyright12* notice, this list of conditions and the following disclaimer.13* 2. Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in the15* documentation and/or other materials provided with the distribution.16*17* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS18* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED19* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR20* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS21* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR22* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF23* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS24* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN25* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)26* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE27* POSSIBILITY OF SUCH DAMAGE.28*29* Obtained from: $NetBSD: msgtest.c,v 1.7 2002/07/20 08:36:25 grant Exp $30*/3132/*33* Test the SVID-compatible Message Queue facility.34*/3536#include <sys/types.h>37#include <sys/ipc.h>38#include <sys/msg.h>39#include <sys/wait.h>4041#include <err.h>42#include <errno.h>43#include <signal.h>44#include <stdio.h>45#include <stdlib.h>46#include <string.h>47#include <time.h>48#include <unistd.h>4950void print_msqid_ds (struct msqid_ds *, mode_t);51void sigsys_handler(int);52void sigchld_handler (int);53void cleanup (void);54void receiver (void);55void usage (void);5657#define MESSAGE_TEXT_LEN 2555859/*60* Define it as test_mymsg because we already have struct mymsg and we dont61* want to conflict with it. Also, regression fails when the default mymsg62* struct is used, because mtext[] array is '1', so the passed string cannot63* be processed.64*/65struct test_mymsg {66long mtype;67char mtext[MESSAGE_TEXT_LEN];68};6970const char *m1_str = "California is overrated.";71const char *m2_str = "The quick brown fox jumped over the lazy dog.";7273#define MTYPE_1 174#define MTYPE_1_ACK 27576#define MTYPE_2 377#define MTYPE_2_ACK 47879int sender_msqid = -1;80pid_t child_pid;8182key_t msgkey;8384int85main(int argc, char *argv[])86{87struct sigaction sa;88struct msqid_ds m_ds;89struct test_mymsg m;90sigset_t sigmask;9192if (argc != 2)93usage();9495/*96* Install a SIGSYS handler so that we can exit gracefully if97* System V Message Queue support isn't in the kernel.98*/99sa.sa_handler = sigsys_handler;100sigemptyset(&sa.sa_mask);101sa.sa_flags = 0;102if (sigaction(SIGSYS, &sa, NULL) == -1)103err(1, "sigaction SIGSYS");104105/*106* Install and SIGCHLD handler to deal with all possible exit107* conditions of the receiver.108*/109sa.sa_handler = sigchld_handler;110sigemptyset(&sa.sa_mask);111sa.sa_flags = 0;112if (sigaction(SIGCHLD, &sa, NULL) == -1)113err(1, "sigaction SIGCHLD");114115msgkey = ftok(argv[1], 4160);116117/*118* Initialize child_pid to ourselves to that the cleanup function119* works before we create the receiver.120*/121child_pid = getpid();122123/*124* Make sure that when the sender exits, the message queue is125* removed.126*/127if (atexit(cleanup) == -1)128err(1, "atexit");129130if ((sender_msqid = msgget(msgkey, IPC_CREAT | 0640)) == -1)131err(1, "msgget");132133if (msgctl(sender_msqid, IPC_STAT, &m_ds) == -1)134err(1, "msgctl IPC_STAT");135136print_msqid_ds(&m_ds, 0640);137138m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600;139140if (msgctl(sender_msqid, IPC_SET, &m_ds) == -1)141err(1, "msgctl IPC_SET");142143bzero(&m_ds, sizeof m_ds);144145if (msgctl(sender_msqid, IPC_STAT, &m_ds) == -1)146err(1, "msgctl IPC_STAT");147148if ((m_ds.msg_perm.mode & 0777) != 0600)149err(1, "IPC_SET of mode didn't hold");150151print_msqid_ds(&m_ds, 0600);152153switch ((child_pid = fork())) {154case -1:155err(1, "fork");156/* NOTREACHED */157158case 0:159receiver();160break;161162default:163break;164}165166/*167* Send the first message to the receiver and wait for the ACK.168*/169m.mtype = MTYPE_1;170strcpy(m.mtext, m1_str);171if (msgsnd(sender_msqid, &m, strlen(m1_str) + 1, 0) == -1)172err(1, "sender: msgsnd 1");173174if (msgrcv(sender_msqid, &m, sizeof(m.mtext), MTYPE_1_ACK, 0) !=175strlen(m1_str) + 1)176err(1, "sender: msgrcv 1 ack");177178print_msqid_ds(&m_ds, 0600);179180/*181* Send the second message to the receiver and wait for the ACK.182*/183m.mtype = MTYPE_2;184strcpy(m.mtext, m2_str);185if (msgsnd(sender_msqid, &m, strlen(m2_str) + 1, 0) == -1)186err(1, "sender: msgsnd 2");187188if (msgrcv(sender_msqid, &m, sizeof(m.mtext), MTYPE_2_ACK, 0) !=189strlen(m2_str) + 1)190err(1, "sender: msgrcv 2 ack");191192/*193* Suspend forever; when we get SIGCHLD, the handler will exit.194*/195sigemptyset(&sigmask);196(void) sigsuspend(&sigmask);197198/*199* ...and any other signal is an unexpected error.200*/201errx(1, "sender: received unexpected signal");202}203204void205sigsys_handler(int signo)206{207208errx(1, "System V Message Queue support is not present in the kernel");209}210211void212sigchld_handler(int signo)213{214struct msqid_ds m_ds;215int cstatus;216217/*218* Reap the child; if it exited successfully, then the test passed!219*/220if (waitpid(child_pid, &cstatus, 0) != child_pid)221err(1, "waitpid");222223if (WIFEXITED(cstatus) == 0)224errx(1, "receiver exited abnormally");225226if (WEXITSTATUS(cstatus) != 0)227errx(1, "receiver exited with status %d",228WEXITSTATUS(cstatus));229230/*231* If we get here, the child has exited normally, and thus232* we should exit normally too. First, tho, we print out233* the final stats for the message queue.234*/235236if (msgctl(sender_msqid, IPC_STAT, &m_ds) == -1)237err(1, "msgctl IPC_STAT");238239print_msqid_ds(&m_ds, 0600);240241exit(0);242}243244void245cleanup()246{247248/*249* If we're the sender, and it exists, remove the message queue.250*/251if (child_pid != 0 && sender_msqid != -1) {252if (msgctl(sender_msqid, IPC_RMID, NULL) == -1)253warn("msgctl IPC_RMID");254}255}256257void258print_msqid_ds(struct msqid_ds *mp, mode_t mode)259{260uid_t uid = geteuid();261gid_t gid = getegid();262263printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",264mp->msg_perm.uid, mp->msg_perm.gid,265mp->msg_perm.cuid, mp->msg_perm.cgid,266mp->msg_perm.mode & 0777);267268printf("qnum %lu, qbytes %lu, lspid %d, lrpid %d\n",269mp->msg_qnum, (u_long)mp->msg_qbytes, mp->msg_lspid,270mp->msg_lrpid);271272printf("stime: %s", ctime(&mp->msg_stime));273printf("rtime: %s", ctime(&mp->msg_rtime));274printf("ctime: %s", ctime(&mp->msg_ctime));275276/*277* Sanity check a few things.278*/279280if (mp->msg_perm.uid != uid || mp->msg_perm.cuid != uid)281errx(1, "uid mismatch");282283if (mp->msg_perm.gid != gid || mp->msg_perm.cgid != gid)284errx(1, "gid mismatch");285286if ((mp->msg_perm.mode & 0777) != mode)287errx(1, "mode mismatch");288}289290void291usage()292{293294fprintf(stderr, "usage: %s keypath\n", getprogname());295exit(1);296}297298void299receiver()300{301struct test_mymsg m;302int msqid;303304if ((msqid = msgget(msgkey, 0)) == -1)305err(1, "receiver: msgget");306307/*308* Receive the first message, print it, and send an ACK.309*/310311if (msgrcv(msqid, &m, sizeof(m.mtext), MTYPE_1, 0) !=312strlen(m1_str) + 1)313err(1, "receiver: msgrcv 1");314315printf("%s\n", m.mtext);316if (strcmp(m.mtext, m1_str) != 0)317err(1, "receiver: message 1 data isn't correct");318319m.mtype = MTYPE_1_ACK;320321if (msgsnd(msqid, &m, strlen(m1_str) + 1, 0) == -1)322err(1, "receiver: msgsnd ack 1");323324/*325* Receive the second message, print it, and send an ACK.326*/327328if (msgrcv(msqid, &m, sizeof(m.mtext), MTYPE_2, 0) !=329strlen(m2_str) + 1)330err(1, "receiver: msgrcv 2");331332printf("%s\n", m.mtext);333if (strcmp(m.mtext, m2_str) != 0)334err(1, "receiver: message 2 data isn't correct");335336m.mtype = MTYPE_2_ACK;337338if (msgsnd(msqid, &m, strlen(m2_str) + 1, 0) == -1)339err(1, "receiver: msgsnd ack 2");340341exit(0);342}343344345