1*49a6e16fSderaadt /* $OpenBSD: msgtest.c,v 1.7 2021/12/13 16:56:50 deraadt Exp $ */
2984329f2Sart /* $NetBSD: msgtest.c,v 1.6 2001/02/19 22:44:41 cgd Exp $ */
3984329f2Sart
4984329f2Sart /*-
5984329f2Sart * Copyright (c) 1999 The NetBSD Foundation, Inc.
6984329f2Sart * All rights reserved.
7984329f2Sart *
8984329f2Sart * This code is derived from software contributed to The NetBSD Foundation
9984329f2Sart * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10984329f2Sart * NASA Ames Research Center.
11984329f2Sart *
12984329f2Sart * Redistribution and use in source and binary forms, with or without
13984329f2Sart * modification, are permitted provided that the following conditions
14984329f2Sart * are met:
15984329f2Sart * 1. Redistributions of source code must retain the above copyright
16984329f2Sart * notice, this list of conditions and the following disclaimer.
17984329f2Sart * 2. Redistributions in binary form must reproduce the above copyright
18984329f2Sart * notice, this list of conditions and the following disclaimer in the
19984329f2Sart * documentation and/or other materials provided with the distribution.
20984329f2Sart *
21984329f2Sart * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22984329f2Sart * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23984329f2Sart * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24984329f2Sart * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25984329f2Sart * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26984329f2Sart * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27984329f2Sart * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28984329f2Sart * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29984329f2Sart * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30984329f2Sart * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31984329f2Sart * POSSIBILITY OF SUCH DAMAGE.
32984329f2Sart */
33984329f2Sart
34984329f2Sart /*
35984329f2Sart * Test the SVID-compatible Message Queue facility.
36984329f2Sart */
37984329f2Sart
38984329f2Sart #include <sys/ipc.h>
39984329f2Sart #include <sys/msg.h>
40984329f2Sart #include <sys/wait.h>
41984329f2Sart
42984329f2Sart #include <err.h>
43984329f2Sart #include <errno.h>
44984329f2Sart #include <signal.h>
45984329f2Sart #include <stdio.h>
46984329f2Sart #include <stdlib.h>
47984329f2Sart #include <string.h>
48984329f2Sart #include <time.h>
49984329f2Sart #include <unistd.h>
50984329f2Sart
51f3c3a9c6Smillert int main(int, char *[]);
52f3c3a9c6Smillert void print_msqid_ds(struct msqid_ds *, mode_t);
53f3c3a9c6Smillert void sigsys_handler(int);
54f3c3a9c6Smillert void sigchld_handler(int);
55f3c3a9c6Smillert void cleanup(void);
56f3c3a9c6Smillert void receiver(void);
57984329f2Sart
58984329f2Sart #define MESSAGE_TEXT_LEN 256
59984329f2Sart
60984329f2Sart struct thismsg {
61984329f2Sart long mtype;
62984329f2Sart char mtext[MESSAGE_TEXT_LEN];
63984329f2Sart };
64984329f2Sart
65984329f2Sart const char *m1_str = "California is overrated.";
66984329f2Sart const char *m2_str = "The quick brown fox jumped over the lazy dog.";
67984329f2Sart
68984329f2Sart #define MTYPE_1 1
69984329f2Sart #define MTYPE_1_ACK 2
70984329f2Sart
71984329f2Sart #define MTYPE_2 3
72984329f2Sart #define MTYPE_2_ACK 4
73984329f2Sart
74984329f2Sart int sender_msqid = -1;
75984329f2Sart pid_t child_pid;
76984329f2Sart
77984329f2Sart key_t msgkey;
78984329f2Sart
79984329f2Sart char keyname[] = "/tmp/msgtestXXXXXXXX";
80984329f2Sart
81984329f2Sart int verbose;
82984329f2Sart
83984329f2Sart int
main(int argc,char ** argv)84984329f2Sart main(int argc, char **argv)
85984329f2Sart {
86984329f2Sart struct sigaction sa;
87984329f2Sart struct msqid_ds m_ds;
88984329f2Sart struct thismsg m;
89984329f2Sart sigset_t sigmask;
90984329f2Sart int fd, ch;
91984329f2Sart
92984329f2Sart if ((fd = mkstemp(keyname)) < 0)
93984329f2Sart err(1, "mkstemp");
94984329f2Sart
95984329f2Sart close(fd);
96984329f2Sart
97984329f2Sart while ((ch = getopt(argc, argv, "v")) != -1) {
98984329f2Sart switch (ch) {
99984329f2Sart case 'v':
100984329f2Sart verbose = 1;
101984329f2Sart break;
102984329f2Sart default:
103984329f2Sart fprintf(stderr, "Usage: msgtest [-v]\n");
104984329f2Sart exit(1);
105984329f2Sart }
106984329f2Sart }
107984329f2Sart
108984329f2Sart /*
109984329f2Sart * Install a SIGSYS handler so that we can exit gracefully if
110984329f2Sart * System V Message Queue support isn't in the kernel.
111984329f2Sart */
112984329f2Sart sa.sa_handler = sigsys_handler;
113984329f2Sart sigemptyset(&sa.sa_mask);
114984329f2Sart sa.sa_flags = 0;
115984329f2Sart if (sigaction(SIGSYS, &sa, NULL) == -1)
116984329f2Sart err(1, "sigaction SIGSYS");
117984329f2Sart
118984329f2Sart /*
119984329f2Sart * Install and SIGCHLD handler to deal with all possible exit
120984329f2Sart * conditions of the receiver.
121984329f2Sart */
122984329f2Sart sa.sa_handler = sigchld_handler;
123984329f2Sart sigemptyset(&sa.sa_mask);
124984329f2Sart sa.sa_flags = 0;
125984329f2Sart if (sigaction(SIGCHLD, &sa, NULL) == -1)
126984329f2Sart err(1, "sigaction SIGCHLD");
127984329f2Sart
128984329f2Sart msgkey = ftok(keyname, 4160);
129984329f2Sart
130984329f2Sart /*
131984329f2Sart * Initialize child_pid to ourselves to that the cleanup function
132984329f2Sart * works before we create the receiver.
133984329f2Sart */
134984329f2Sart child_pid = getpid();
135984329f2Sart
136984329f2Sart /*
137984329f2Sart * Make sure that when the sender exits, the message queue is
138984329f2Sart * removed.
139984329f2Sart */
140984329f2Sart if (atexit(cleanup) == -1)
141984329f2Sart err(1, "atexit");
142984329f2Sart
143984329f2Sart if ((sender_msqid = msgget(msgkey, IPC_CREAT | 0640)) == -1)
144984329f2Sart err(1, "msgget");
145984329f2Sart
146984329f2Sart if (msgctl(sender_msqid, IPC_STAT, &m_ds) == -1)
147984329f2Sart err(1, "msgctl IPC_STAT");
148984329f2Sart
149984329f2Sart if (verbose)
150984329f2Sart print_msqid_ds(&m_ds, 0640);
151984329f2Sart
152984329f2Sart m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600;
153984329f2Sart
154984329f2Sart if (msgctl(sender_msqid, IPC_SET, &m_ds) == -1)
155984329f2Sart err(1, "msgctl IPC_SET");
156984329f2Sart
157984329f2Sart memset(&m_ds, 0, sizeof(m_ds));
158984329f2Sart
159984329f2Sart if (msgctl(sender_msqid, IPC_STAT, &m_ds) == -1)
160984329f2Sart err(1, "msgctl IPC_STAT");
161984329f2Sart
162984329f2Sart if ((m_ds.msg_perm.mode & 0777) != 0600)
163984329f2Sart err(1, "IPC_SET of mode didn't hold");
164984329f2Sart
165984329f2Sart if (verbose)
166984329f2Sart print_msqid_ds(&m_ds, 0600);
167984329f2Sart
168984329f2Sart switch ((child_pid = fork())) {
169984329f2Sart case -1:
170984329f2Sart err(1, "fork");
171984329f2Sart /* NOTREACHED */
172984329f2Sart
173984329f2Sart case 0:
174984329f2Sart receiver();
175984329f2Sart break;
176984329f2Sart
177984329f2Sart default:
178984329f2Sart break;
179984329f2Sart }
180984329f2Sart
181984329f2Sart /*
182984329f2Sart * Send the first message to the receiver and wait for the ACK.
183984329f2Sart */
184984329f2Sart m.mtype = MTYPE_1;
1854993325bSderaadt strlcpy(m.mtext, m1_str, sizeof m.mtext);
186984329f2Sart if (msgsnd(sender_msqid, &m, sizeof(m), 0) == -1)
187984329f2Sart err(1, "sender: msgsnd 1");
188984329f2Sart
189984329f2Sart if (msgrcv(sender_msqid, &m, sizeof(m), MTYPE_1_ACK, 0) != sizeof(m))
190984329f2Sart err(1, "sender: msgrcv 1 ack");
191984329f2Sart
192984329f2Sart if (verbose)
193984329f2Sart print_msqid_ds(&m_ds, 0600);
194984329f2Sart
195984329f2Sart /*
196984329f2Sart * Send the second message to the receiver and wait for the ACK.
197984329f2Sart */
198984329f2Sart m.mtype = MTYPE_2;
1994993325bSderaadt strlcpy(m.mtext, m2_str, sizeof m.mtext);
200984329f2Sart if (msgsnd(sender_msqid, &m, sizeof(m), 0) == -1)
201984329f2Sart err(1, "sender: msgsnd 2");
202984329f2Sart
203984329f2Sart if (msgrcv(sender_msqid, &m, sizeof(m), MTYPE_2_ACK, 0) != sizeof(m))
204984329f2Sart err(1, "sender: msgrcv 2 ack");
205984329f2Sart
206984329f2Sart /*
207984329f2Sart * Suspend forever; when we get SIGCHLD, the handler will exit.
208984329f2Sart */
209984329f2Sart sigemptyset(&sigmask);
210984329f2Sart (void) sigsuspend(&sigmask);
211984329f2Sart
212984329f2Sart /*
213984329f2Sart * ...and any other signal is an unexpected error.
214984329f2Sart */
215984329f2Sart errx(1, "sender: received unexpected signal");
216984329f2Sart }
217984329f2Sart
218984329f2Sart void
sigsys_handler(signo)219984329f2Sart sigsys_handler(signo)
220984329f2Sart int signo;
221984329f2Sart {
222984329f2Sart
223984329f2Sart errx(1, "System V Message Queue support is not present in the kernel");
224984329f2Sart }
225984329f2Sart
226984329f2Sart void
sigchld_handler(signo)227984329f2Sart sigchld_handler(signo)
228984329f2Sart int signo;
229984329f2Sart {
230984329f2Sart struct msqid_ds m_ds;
231984329f2Sart int cstatus;
232984329f2Sart
233984329f2Sart /*
234984329f2Sart * Reap the child; if it exited successfully, then the test passed!
235984329f2Sart */
236984329f2Sart if (waitpid(child_pid, &cstatus, 0) != child_pid)
237984329f2Sart err(1, "waitpid");
238984329f2Sart
239984329f2Sart if (WIFEXITED(cstatus) == 0)
240984329f2Sart errx(1, "receiver exited abnormally");
241984329f2Sart
242984329f2Sart if (WEXITSTATUS(cstatus) != 0)
243c20d9ad4Sjsyn errx(1, "receiver exited with status %d",
244984329f2Sart WEXITSTATUS(cstatus));
245984329f2Sart
246984329f2Sart /*
247984329f2Sart * If we get here, the child has exited normally, and thus
248984329f2Sart * we should exit normally too. First, tho, we print out
249984329f2Sart * the final stats for the message queue.
250984329f2Sart */
251984329f2Sart
252984329f2Sart if (msgctl(sender_msqid, IPC_STAT, &m_ds) == -1)
253984329f2Sart err(1, "msgctl IPC_STAT");
254984329f2Sart
255984329f2Sart if (verbose)
256984329f2Sart print_msqid_ds(&m_ds, 0600);
257984329f2Sart
258984329f2Sart exit(0);
259984329f2Sart }
260984329f2Sart
261984329f2Sart void
cleanup()262984329f2Sart cleanup()
263984329f2Sart {
264984329f2Sart
265984329f2Sart /*
266984329f2Sart * If we're the sender, and it exists, remove the message queue.
267984329f2Sart */
268984329f2Sart if (child_pid != 0 && sender_msqid != -1) {
269984329f2Sart if (msgctl(sender_msqid, IPC_RMID, NULL) == -1)
270984329f2Sart warn("msgctl IPC_RMID");
271984329f2Sart }
272984329f2Sart
273984329f2Sart remove(keyname);
274984329f2Sart }
275984329f2Sart
276984329f2Sart void
print_msqid_ds(mp,mode)277984329f2Sart print_msqid_ds(mp, mode)
278984329f2Sart struct msqid_ds *mp;
279984329f2Sart mode_t mode;
280984329f2Sart {
281984329f2Sart uid_t uid = geteuid();
282984329f2Sart gid_t gid = getegid();
283984329f2Sart
2842cc39398Sderaadt printf("PERM: uid %u, gid %u, cuid %u, cgid %u, mode 0%o\n",
285984329f2Sart mp->msg_perm.uid, mp->msg_perm.gid,
286984329f2Sart mp->msg_perm.cuid, mp->msg_perm.cgid,
287984329f2Sart mp->msg_perm.mode & 0777);
288984329f2Sart
289984329f2Sart printf("qnum %lu, qbytes %lu, lspid %d, lrpid %d\n",
290984329f2Sart mp->msg_qnum, (u_long)mp->msg_qbytes, mp->msg_lspid,
291984329f2Sart mp->msg_lrpid);
292984329f2Sart
293984329f2Sart printf("stime: %s", ctime(&mp->msg_stime));
294984329f2Sart printf("rtime: %s", ctime(&mp->msg_rtime));
295984329f2Sart printf("ctime: %s", ctime(&mp->msg_ctime));
296984329f2Sart
297984329f2Sart /*
298984329f2Sart * Sanity check a few things.
299984329f2Sart */
300984329f2Sart
301984329f2Sart if (mp->msg_perm.uid != uid || mp->msg_perm.cuid != uid)
302984329f2Sart errx(1, "uid mismatch");
303984329f2Sart
304984329f2Sart if (mp->msg_perm.gid != gid || mp->msg_perm.cgid != gid)
305984329f2Sart errx(1, "gid mismatch");
306984329f2Sart
307984329f2Sart if ((mp->msg_perm.mode & 0777) != mode)
308984329f2Sart errx(1, "mode mismatch");
309984329f2Sart }
310984329f2Sart
311984329f2Sart void
receiver()312984329f2Sart receiver()
313984329f2Sart {
314984329f2Sart struct thismsg m;
315984329f2Sart int msqid;
316984329f2Sart
317984329f2Sart if ((msqid = msgget(msgkey, 0)) == -1)
318984329f2Sart err(1, "receiver: msgget");
319984329f2Sart
320984329f2Sart /*
321984329f2Sart * Receive the first message, print it, and send an ACK.
322984329f2Sart */
323984329f2Sart
324984329f2Sart if (msgrcv(msqid, &m, sizeof(m), MTYPE_1, 0) != sizeof(m))
325984329f2Sart err(1, "receiver: msgrcv 1");
326984329f2Sart
327984329f2Sart if (verbose)
328984329f2Sart printf("%s\n", m.mtext);
329984329f2Sart if (strcmp(m.mtext, m1_str) != 0)
330984329f2Sart err(1, "receiver: message 1 data isn't correct");
331984329f2Sart
332984329f2Sart m.mtype = MTYPE_1_ACK;
333984329f2Sart
334984329f2Sart if (msgsnd(msqid, &m, sizeof(m), 0) == -1)
335984329f2Sart err(1, "receiver: msgsnd ack 1");
336984329f2Sart
337984329f2Sart /*
338984329f2Sart * Receive the second message, print it, and send an ACK.
339984329f2Sart */
340984329f2Sart
341984329f2Sart if (msgrcv(msqid, &m, sizeof(m), MTYPE_2, 0) != sizeof(m))
342984329f2Sart err(1, "receiver: msgrcv 2");
343984329f2Sart
344984329f2Sart if (verbose)
345984329f2Sart printf("%s\n", m.mtext);
346984329f2Sart if (strcmp(m.mtext, m2_str) != 0)
347984329f2Sart err(1, "receiver: message 2 data isn't correct");
348984329f2Sart
349984329f2Sart m.mtype = MTYPE_2_ACK;
350984329f2Sart
351984329f2Sart if (msgsnd(msqid, &m, sizeof(m), 0) == -1)
352984329f2Sart err(1, "receiver: msgsnd ack 2");
353984329f2Sart
354984329f2Sart exit(0);
355984329f2Sart }
356