1/*	$NetBSD: t_sysv.c,v 1.6 2022/05/14 14:02:03 christos Exp $	*/
2
3/*-
4 * Copyright (c) 1999, 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center, and by Andrew Doran.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * Test the SVID-compatible Message Queue facility.
35 */
36
37#include <atf-c.h>
38
39#include <err.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <signal.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <time.h>
47#include <unistd.h>
48
49#include <sys/ipc.h>
50#include <sys/msg.h>
51#include <sys/param.h>
52#include <sys/sem.h>
53#include <sys/shm.h>
54#include <sys/wait.h>
55
56volatile int did_sigsys;
57
58void	sigsys_handler(int);
59
60key_t	get_ftok(int);
61
62void	print_msqid_ds(struct msqid_ds *, mode_t);
63void	receiver(void);
64
65void	print_semid_ds(struct semid_ds *, mode_t);
66void	waiter(void);
67
68void	print_shmid_ds(struct shmid_ds *, mode_t);
69void	sharer(void);
70
71#define	MESSAGE_TEXT_LEN	256
72
73struct testmsg {
74	long	mtype;
75	char	mtext[MESSAGE_TEXT_LEN];
76};
77
78const char *m1_str = "California is overrated.";
79const char *m2_str = "The quick brown fox jumped over the lazy dog.";
80
81size_t	pgsize;
82
83#define	MTYPE_1		1
84#define	MTYPE_1_ACK	2
85
86#define	MTYPE_2		3
87#define	MTYPE_2_ACK	4
88
89pid_t	child_pid;
90
91key_t	msgkey, semkey, shmkey;
92
93int	maxloop = 1;
94
95union semun {
96	int	val;		/* value for SETVAL */
97	struct	semid_ds *buf;	/* buffer for IPC_{STAT,SET} */
98	u_short	*array;		/* array for GETALL & SETALL */
99};
100
101
102/* Writes an integer to a file.  To be used from the body of the test
103 * cases below to pass any global identifiers to the cleanup routine. */
104static void
105write_int(const char *path, const int value)
106{
107	int output;
108
109	output = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
110	ATF_REQUIRE_MSG(output != -1, "Failed to create %s", path);
111	write(output, &value, sizeof(value));
112	close(output);
113}
114
115
116/* Reads an integer from a file.  To be used from the cleanup routines
117 * of the test cases below. */
118static int
119read_int(const char *path)
120{
121	int input, value;
122
123	input = open(path, O_RDONLY);
124	if (input == -1)
125		return -1;
126
127	read(input, &value, sizeof(value));
128	return value;
129}
130
131
132void
133sigsys_handler(int signo)
134{
135
136	did_sigsys = 1;
137}
138
139key_t get_ftok(int id)
140{
141	int fd;
142	char token_key[64], token_dir[64];
143	char *tmpdir;
144	key_t key;
145
146	strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key));
147	tmpdir = mkdtemp(token_key);
148	ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno);
149
150	strlcpy(token_dir, tmpdir, sizeof(token_dir));
151	strlcpy(token_key, tmpdir, sizeof(token_key));
152	strlcat(token_key, "/token_key", sizeof(token_key));
153
154	/* Create the file, since ftok() requires it to exist! */
155
156	fd = open(token_key, O_RDWR | O_CREAT | O_EXCL, 0600);
157	if (fd == -1) {
158		rmdir(tmpdir);
159		atf_tc_fail("open() of temp file failed: %d", errno);
160		return (key_t)-1;
161	}
162
163	close(fd);
164
165	key = ftok(token_key, id);
166	ATF_REQUIRE_MSG(key != (key_t)-1, "ftok() failed");
167
168	ATF_REQUIRE_MSG(unlink(token_key) != -1, "unlink() failed: %d", errno);
169	ATF_REQUIRE_MSG(rmdir(token_dir) != -1, "rmdir() failed: %d", errno);
170
171	return key;
172}
173
174ATF_TC_WITH_CLEANUP(msg);
175ATF_TC_HEAD(msg, tc)
176{
177
178	atf_tc_set_md_var(tc, "timeout", "3");
179	atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
180}
181
182ATF_TC_BODY(msg, tc)
183{
184	struct sigaction sa;
185	struct msqid_ds m_ds;
186	struct testmsg m;
187	int sender_msqid;
188	int loop;
189	int c_status;
190	pid_t wait_result;
191
192	/*
193	 * Install a SIGSYS handler so that we can exit gracefully if
194	 * System V Message Queue support isn't in the kernel.
195	 */
196	did_sigsys = 0;
197	sa.sa_handler = sigsys_handler;
198	sigemptyset(&sa.sa_mask);
199	sa.sa_flags = 0;
200	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
201	    "sigaction SIGSYS: %d", errno);
202
203	msgkey = get_ftok(4160);
204	ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed");
205
206	sender_msqid = msgget(msgkey, IPC_CREAT | 0640);
207	ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno);
208	write_int("sender_msqid", sender_msqid);
209
210	if (did_sigsys) {
211		atf_tc_skip("SYSV Message Queue not supported");
212		return;
213	}
214
215	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
216	"msgctl IPC_STAT 1: %d", errno);
217
218	print_msqid_ds(&m_ds, 0640);
219
220	m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600;
221
222	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1,
223	    "msgctl IPC_SET: %d", errno);
224
225	memset(&m_ds, 0, sizeof(m_ds));
226
227	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
228	    "msgctl IPC_STAT 2: %d", errno);
229
230	ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600,
231	    "IPC_SET of mode didn't hold");
232
233	print_msqid_ds(&m_ds, 0600);
234
235	fflush(stdout);
236
237	switch ((child_pid = fork())) {
238	case -1:
239		atf_tc_fail("fork: %d", errno);
240		return;
241
242	case 0:
243		receiver();
244		break;
245
246	default:
247		break;
248	}
249
250	for (loop = 0; loop < maxloop; loop++) {
251		/*
252		 * Send the first message to the receiver and wait for the ACK.
253		 */
254		m.mtype = MTYPE_1;
255		strcpy(m.mtext, m1_str);
256		ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN,
257		    0) != -1, "sender: msgsnd 1: %d", errno);
258
259		ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
260		    MTYPE_1_ACK, 0) == MESSAGE_TEXT_LEN,
261		    "sender: msgrcv 1 ack: %d", errno);
262
263		print_msqid_ds(&m_ds, 0600);
264
265		/*
266		 * Send the second message to the receiver and wait for the ACK.
267		 */
268		m.mtype = MTYPE_2;
269		strcpy(m.mtext, m2_str);
270		ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 0)
271		    != -1, "sender: msgsnd 2: %d", errno);
272
273		ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
274		    MTYPE_2_ACK, 0) == MESSAGE_TEXT_LEN,
275		    "sender: msgrcv 2 ack: %d", errno);
276	}
277
278	/*
279	 * Wait for child to finish
280	 */
281	wait_result = wait(&c_status);
282	ATF_REQUIRE_EQ_MSG(wait_result, child_pid, "wait returned %d (%s)",
283	    wait_result, wait_result == -1 ? strerror(errno) : "");
284	ATF_REQUIRE_MSG(WIFEXITED(c_status), "child abnormal exit: %d (sig %d)",
285	    c_status, WTERMSIG(c_status));
286	ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d",
287	    WEXITSTATUS(c_status));
288
289	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
290	    "msgctl IPC_STAT: %d", errno);
291
292	print_msqid_ds(&m_ds, 0600);
293}
294
295ATF_TC_CLEANUP(msg, tc)
296{
297	int sender_msqid;
298
299	/*
300	 * Remove the message queue if it exists.
301	 */
302	sender_msqid = read_int("sender_msqid");
303	if (sender_msqid == -1)
304		return;
305	if (msgctl(sender_msqid, IPC_RMID, NULL) == -1)
306		err(EXIT_FAILURE, "msgctl IPC_RMID");
307}
308
309void
310print_msqid_ds(struct msqid_ds *mp, mode_t mode)
311{
312	uid_t uid = geteuid();
313	gid_t gid = getegid();
314
315	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
316	    mp->msg_perm.uid, mp->msg_perm.gid,
317	    mp->msg_perm.cuid, mp->msg_perm.cgid,
318	    mp->msg_perm.mode & 0777);
319
320	printf("qnum %lu, qbytes %ju, lspid %d, lrpid %d\n",
321	    mp->msg_qnum, (uintmax_t)mp->msg_qbytes, mp->msg_lspid,
322	    mp->msg_lrpid);
323
324	printf("stime: %s", ctime(&mp->msg_stime));
325	printf("rtime: %s", ctime(&mp->msg_rtime));
326	printf("ctime: %s", ctime(&mp->msg_ctime));
327
328	/*
329	 * Sanity check a few things.
330	 */
331
332	ATF_REQUIRE_MSG(mp->msg_perm.uid == uid && mp->msg_perm.cuid == uid,
333	    "uid mismatch");
334
335	ATF_REQUIRE_MSG(mp->msg_perm.gid == gid && mp->msg_perm.cgid == gid,
336	    "gid mismatch");
337
338	ATF_REQUIRE_MSG((mp->msg_perm.mode & 0777) == mode, "mode mismatch");
339}
340
341void
342receiver(void)
343{
344	struct testmsg m;
345	int msqid, loop;
346
347	if ((msqid = msgget(msgkey, 0)) == -1)
348		err(EXIT_FAILURE, "receiver: msgget");
349
350	for (loop = 0; loop < maxloop; loop++) {
351		/*
352		 * Receive the first message, print it, and send an ACK.
353		 */
354		if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_1, 0)
355		    != MESSAGE_TEXT_LEN)
356			err(EXIT_FAILURE, "receiver: msgrcv 1");
357
358		printf("%s\n", m.mtext);
359		if (strcmp(m.mtext, m1_str) != 0)
360			errx(EXIT_FAILURE,
361			    "receiver: message 1 data isn't correct");
362
363		m.mtype = MTYPE_1_ACK;
364
365		if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
366			err(EXIT_FAILURE, "receiver: msgsnd ack 1");
367
368		/*
369		 * Receive the second message, print it, and send an ACK.
370		 */
371
372		if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_2, 0)
373		    != MESSAGE_TEXT_LEN)
374			err(EXIT_FAILURE, "receiver: msgrcv 2");
375
376		printf("%s\n", m.mtext);
377		if (strcmp(m.mtext, m2_str) != 0)
378			errx(EXIT_FAILURE,
379			    "receiver: message 2 data isn't correct");
380
381		m.mtype = MTYPE_2_ACK;
382
383		if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
384			err(EXIT_FAILURE, "receiver: msgsnd ack 2");
385	}
386
387	exit(EXIT_SUCCESS);
388}
389
390/*
391 * Test the SVID-compatible Semaphore facility.
392 */
393
394ATF_TC_WITH_CLEANUP(sem);
395ATF_TC_HEAD(sem, tc)
396{
397
398	atf_tc_set_md_var(tc, "timeout", "3");
399	atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
400}
401
402ATF_TC_BODY(sem, tc)
403{
404	struct sigaction sa;
405	union semun sun;
406	struct semid_ds s_ds;
407	int sender_semid;
408	int i;
409	int c_status;
410	int child_count;
411	pid_t wait_result;
412
413	/*
414	 * Install a SIGSYS handler so that we can exit gracefully if
415	 * System V Semaphore support isn't in the kernel.
416	 */
417	did_sigsys = 0;
418	sa.sa_handler = sigsys_handler;
419	sigemptyset(&sa.sa_mask);
420	sa.sa_flags = 0;
421	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
422	    "sigaction SIGSYS: %d", errno);
423
424	semkey = get_ftok(4160);
425	ATF_REQUIRE_MSG(semkey != (key_t)-1, "get_ftok failed");
426
427	sender_semid = semget(semkey, 1, IPC_CREAT | 0640);
428	ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno);
429	write_int("sender_semid", sender_semid);
430
431	if (did_sigsys) {
432		atf_tc_skip("SYSV Semaphore not supported");
433		return;
434	}
435
436	sun.buf = &s_ds;
437	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
438	    "semctl IPC_STAT: %d", errno);
439
440	print_semid_ds(&s_ds, 0640);
441
442	s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600;
443
444	sun.buf = &s_ds;
445	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1,
446	    "semctl IPC_SET: %d", errno);
447
448	memset(&s_ds, 0, sizeof(s_ds));
449
450	sun.buf = &s_ds;
451	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
452	    "semctl IPC_STAT: %d", errno);
453
454	ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600,
455	    "IPC_SET of mode didn't hold");
456
457	print_semid_ds(&s_ds, 0600);
458
459	fflush(stdout);
460
461	for (child_count = 0; child_count < 5; child_count++) {
462		switch ((child_pid = fork())) {
463		case -1:
464			atf_tc_fail("fork: %d", errno);
465			return;
466
467		case 0:
468			waiter();
469			break;
470
471		default:
472			break;
473		}
474	}
475
476	/*
477	 * Wait for all of the waiters to be attempting to acquire the
478	 * semaphore.
479	 */
480	for (;;) {
481		i = semctl(sender_semid, 0, GETNCNT);
482		if (i == -1)
483			atf_tc_fail("semctl GETNCNT: %d", i);
484		if (i == 5)
485			break;
486	}
487
488	/*
489	 * Now set the thundering herd in motion by initializing the
490	 * semaphore to the value 1.
491	 */
492	sun.val = 1;
493	ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1,
494	    "sender: semctl SETVAL to 1: %d", errno);
495
496	/*
497	 * Wait for all children to finish
498	 */
499	while (child_count-- > 0) {
500		wait_result = wait(&c_status);
501		ATF_REQUIRE_MSG(wait_result != -1, "wait failed: %s",
502		    strerror(errno));
503		ATF_REQUIRE_MSG(WIFEXITED(c_status),
504		    "child abnormal exit: %d (sig %d)",
505		    c_status, WTERMSIG(c_status));
506		ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d",
507		    WEXITSTATUS(c_status));
508
509		sun.buf = &s_ds;
510		ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
511		    "semctl IPC_STAT: %d", errno);
512
513		print_semid_ds(&s_ds, 0600);
514	}
515}
516
517ATF_TC_CLEANUP(sem, tc)
518{
519	int sender_semid;
520
521	/*
522	 * Remove the semaphore if it exists
523	 */
524	sender_semid = read_int("sender_semid");
525	if (sender_semid == -1)
526		return;
527	if (semctl(sender_semid, 0, IPC_RMID) == -1)
528		err(EXIT_FAILURE, "semctl IPC_RMID");
529}
530
531void
532print_semid_ds(struct semid_ds *sp, mode_t mode)
533{
534	uid_t uid = geteuid();
535	gid_t gid = getegid();
536
537	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
538	    sp->sem_perm.uid, sp->sem_perm.gid,
539	    sp->sem_perm.cuid, sp->sem_perm.cgid,
540	    sp->sem_perm.mode & 0777);
541
542	printf("nsems %u\n", sp->sem_nsems);
543
544	printf("otime: %s", ctime(&sp->sem_otime));
545	printf("ctime: %s", ctime(&sp->sem_ctime));
546
547	/*
548	 * Sanity check a few things.
549	 */
550
551	ATF_REQUIRE_MSG(sp->sem_perm.uid == uid && sp->sem_perm.cuid == uid,
552	    "uid mismatch");
553
554	ATF_REQUIRE_MSG(sp->sem_perm.gid == gid && sp->sem_perm.cgid == gid,
555	    "gid mismatch");
556
557	ATF_REQUIRE_MSG((sp->sem_perm.mode & 0777) == mode,
558	    "mode mismatch %o != %o", (sp->sem_perm.mode & 0777), mode);
559}
560
561void
562waiter(void)
563{
564	struct sembuf s;
565	int semid;
566
567	if ((semid = semget(semkey, 1, 0)) == -1)
568		err(EXIT_FAILURE, "waiter: semget");
569
570	/*
571	 * Attempt to acquire the semaphore.
572	 */
573	s.sem_num = 0;
574	s.sem_op = -1;
575	s.sem_flg = SEM_UNDO;
576
577	if (semop(semid, &s, 1) == -1)
578		err(EXIT_FAILURE, "waiter: semop -1");
579
580	printf("WOO!  GOT THE SEMAPHORE!\n");
581	usleep(10000);
582
583	/*
584	 * Release the semaphore and exit.
585	 */
586	s.sem_num = 0;
587	s.sem_op = 1;
588	s.sem_flg = SEM_UNDO;
589
590	if (semop(semid, &s, 1) == -1)
591		err(EXIT_FAILURE, "waiter: semop +1");
592
593	exit(EXIT_SUCCESS);
594}
595
596/*
597 * Test the SVID-compatible Shared Memory facility.
598 */
599
600ATF_TC_WITH_CLEANUP(shm);
601ATF_TC_HEAD(shm, tc)
602{
603
604	atf_tc_set_md_var(tc, "timeout", "3");
605	atf_tc_set_md_var(tc, "descr", "Checks sysv shared memory");
606}
607
608ATF_TC_BODY(shm, tc)
609{
610	struct sigaction sa;
611	struct shmid_ds s_ds;
612	char *shm_buf;
613	int sender_shmid;
614	int c_status;
615	pid_t wait_result;
616
617	/*
618	 * Install a SIGSYS handler so that we can exit gracefully if
619	 * System V Shared Memory support isn't in the kernel.
620	 */
621	did_sigsys = 0;
622	sa.sa_handler = sigsys_handler;
623	sigemptyset(&sa.sa_mask);
624	sa.sa_flags = 0;
625	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
626	    "sigaction SIGSYS: %d", errno);
627
628	pgsize = sysconf(_SC_PAGESIZE);
629
630	shmkey = get_ftok(4160);
631	ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed");
632
633	ATF_REQUIRE_MSG((sender_shmid = shmget(shmkey, pgsize,
634					       IPC_CREAT | 0640)) != -1,
635	    "shmget: %d", errno);
636	write_int("sender_shmid", sender_shmid);
637
638	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
639	    "shmctl IPC_STAT: %d", errno);
640
641	print_shmid_ds(&s_ds, 0640);
642
643	s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600;
644
645	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_SET, &s_ds) != -1,
646	    "shmctl IPC_SET: %d", errno);
647
648	memset(&s_ds, 0, sizeof(s_ds));
649
650	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
651	    "shmctl IPC_STAT: %d", errno);
652
653	ATF_REQUIRE_MSG((s_ds.shm_perm.mode & 0777) == 0600,
654	    "IPC_SET of mode didn't hold");
655
656	print_shmid_ds(&s_ds, 0600);
657
658	shm_buf = shmat(sender_shmid, NULL, 0);
659	ATF_REQUIRE_MSG(shm_buf != (void *) -1, "sender: shmat: %d", errno);
660
661	/*
662	 * Write the test pattern into the shared memory buffer.
663	 */
664	strcpy(shm_buf, m2_str);
665
666	fflush(stdout);
667
668	switch ((child_pid = fork())) {
669	case -1:
670		atf_tc_fail("fork: %d", errno);
671		return;
672
673	case 0:
674		sharer();
675		break;
676
677	default:
678		break;
679	}
680
681	/*
682	 * Wait for child to finish
683	 */
684	wait_result = wait(&c_status);
685	ATF_REQUIRE_EQ_MSG(wait_result, child_pid, "wait returned %d (%s)",
686	    wait_result, wait_result == -1 ? strerror(errno) : "");
687	ATF_REQUIRE_MSG(WIFEXITED(c_status), "child abnormal exit: %d (sig %d)",
688	    c_status, WTERMSIG(c_status));
689	ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d",
690	    WEXITSTATUS(c_status));
691
692	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
693	    "shmctl IPC_STAT: %d", errno);
694
695	print_shmid_ds(&s_ds, 0600);
696}
697
698ATF_TC_CLEANUP(shm, tc)
699{
700	int sender_shmid;
701
702	/*
703	 * Remove the shared memory area if it exists.
704	 */
705	sender_shmid = read_int("sender_shmid");
706	if (sender_shmid == -1)
707		return;
708	if (shmctl(sender_shmid, IPC_RMID, NULL) == -1)
709		err(EXIT_FAILURE, "shmctl IPC_RMID");
710}
711
712void
713print_shmid_ds(struct shmid_ds *sp, mode_t mode)
714{
715	uid_t uid = geteuid();
716	gid_t gid = getegid();
717
718	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
719	    sp->shm_perm.uid, sp->shm_perm.gid,
720	    sp->shm_perm.cuid, sp->shm_perm.cgid,
721	    sp->shm_perm.mode & 0777);
722
723	printf("segsz %ju, lpid %d, cpid %d, nattch %u\n",
724	    (uintmax_t)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid,
725	    sp->shm_nattch);
726
727	printf("atime: %s", ctime(&sp->shm_atime));
728	printf("dtime: %s", ctime(&sp->shm_dtime));
729	printf("ctime: %s", ctime(&sp->shm_ctime));
730
731	/*
732	 * Sanity check a few things.
733	 */
734
735	ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid,
736	    "uid mismatch");
737
738	ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid,
739	    "gid mismatch");
740
741	ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode,
742	    "mode mismatch %o != %o", sp->shm_perm.mode & 0777, mode);
743}
744
745void
746sharer(void)
747{
748	int shmid;
749	void *shm_buf;
750
751	shmid = shmget(shmkey, pgsize, 0);
752	if (shmid == -1)
753		err(EXIT_FAILURE, "receiver: shmget");
754
755	shm_buf = shmat(shmid, NULL, 0);
756	if (shm_buf == (void *) -1)
757		err(EXIT_FAILURE, "receiver: shmat");
758
759	printf("%s\n", (const char *)shm_buf);
760
761	if (strcmp((const char *)shm_buf, m2_str) != 0)
762		errx(EXIT_FAILURE, "receiver: data isn't correct");
763
764	exit(EXIT_SUCCESS);
765}
766
767ATF_TP_ADD_TCS(tp)
768{
769
770	ATF_TP_ADD_TC(tp, msg);
771	ATF_TP_ADD_TC(tp, sem);
772	ATF_TP_ADD_TC(tp, shm);
773
774	return atf_no_error();
775}
776