1/*	$NetBSD: t_sysv.c,v 1.4 2014/03/02 20:13:12 jmmv 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, did_sigchild;
57volatile int child_status, child_count;
58
59void	sigsys_handler(int);
60void	sigchld_handler(int);
61
62key_t	get_ftok(int);
63
64void	print_msqid_ds(struct msqid_ds *, mode_t);
65void	receiver(void);
66
67void	print_semid_ds(struct semid_ds *, mode_t);
68void	waiter(void);
69
70void	print_shmid_ds(struct shmid_ds *, mode_t);
71void	sharer(void);
72
73#define	MESSAGE_TEXT_LEN	256
74
75struct mymsg {
76	long	mtype;
77	char	mtext[MESSAGE_TEXT_LEN];
78};
79
80const char *m1_str = "California is overrated.";
81const char *m2_str = "The quick brown fox jumped over the lazy dog.";
82
83size_t	pgsize;
84
85#define	MTYPE_1		1
86#define	MTYPE_1_ACK	2
87
88#define	MTYPE_2		3
89#define	MTYPE_2_ACK	4
90
91pid_t	child_pid;
92
93key_t	msgkey, semkey, shmkey;
94
95int	maxloop = 1;
96
97union semun {
98	int	val;		/* value for SETVAL */
99	struct	semid_ds *buf;	/* buffer for IPC_{STAT,SET} */
100	u_short	*array;		/* array for GETALL & SETALL */
101};
102
103
104/* Writes an integer to a file.  To be used from the body of the test
105 * cases below to pass any global identifiers to the cleanup routine. */
106static void
107write_int(const char *path, const int value)
108{
109	int output;
110
111	output = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
112	ATF_REQUIRE_MSG(output != -1, "Failed to create %s", path);
113	write(output, &value, sizeof(value));
114	close(output);
115}
116
117
118/* Reads an integer from a file.  To be used from the cleanup routines
119 * of the test cases below. */
120static int
121read_int(const char *path)
122{
123	int input;
124
125	input = open(path, O_RDONLY);
126	if (input == -1)
127		return -1;
128	else {
129		int value;
130		read(input, &value, sizeof(value));
131		return value;
132	}
133}
134
135
136void
137sigsys_handler(int signo)
138{
139
140	did_sigsys = 1;
141}
142
143void
144sigchld_handler(int signo)
145{
146	int c_status;
147
148	did_sigchild = 1;
149	/*
150	 * Reap the child and return its status
151	 */
152	if (wait(&c_status) == -1)
153		child_status = -errno;
154	else
155		child_status = c_status;
156
157	child_count--;
158}
159
160key_t get_ftok(int id)
161{
162	int fd;
163	char token_key[64], token_dir[64];
164	char *tmpdir;
165	key_t key;
166
167	strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key));
168	tmpdir = mkdtemp(token_key);
169	ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno);
170
171	strlcpy(token_dir, tmpdir, sizeof(token_dir));
172	strlcpy(token_key, tmpdir, sizeof(token_key));
173	strlcat(token_key, "/token_key", sizeof(token_key));
174
175	/* Create the file, since ftok() requires it to exist! */
176
177	fd = open(token_key, O_RDWR | O_CREAT | O_EXCL);
178	if (fd == -1) {
179		rmdir(tmpdir);
180		atf_tc_fail("open() of temp file failed: %d", errno);
181		return (key_t)-1;
182	} else
183		close(fd);
184
185	key = ftok(token_key, id);
186
187	ATF_REQUIRE_MSG(unlink(token_key) != -1, "unlink() failed: %d", errno);
188	ATF_REQUIRE_MSG(rmdir(token_dir) != -1, "rmdir() failed: %d", errno);
189
190	return key;
191}
192
193ATF_TC_WITH_CLEANUP(msg);
194ATF_TC_HEAD(msg, tc)
195{
196
197	atf_tc_set_md_var(tc, "timeout", "3");
198	atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
199}
200
201ATF_TC_BODY(msg, tc)
202{
203	struct sigaction sa;
204	struct msqid_ds m_ds;
205	struct mymsg m;
206	sigset_t sigmask;
207	int sender_msqid;
208	int loop;
209	int c_status;
210
211	/*
212	 * Install a SIGSYS handler so that we can exit gracefully if
213	 * System V Message Queue support isn't in the kernel.
214	 */
215	did_sigsys = 0;
216	sa.sa_handler = sigsys_handler;
217	sigemptyset(&sa.sa_mask);
218	sa.sa_flags = 0;
219	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
220	    "sigaction SIGSYS: %d", errno);
221
222	/*
223	 * Install a SIGCHLD handler to deal with all possible exit
224	 * conditions of the receiver.
225	 */
226	did_sigchild = 0;
227	child_count = 0;
228	sa.sa_handler = sigchld_handler;
229	sigemptyset(&sa.sa_mask);
230	sa.sa_flags = 0;
231	ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
232	    "sigaction SIGCHLD: %d", errno);
233
234	msgkey = get_ftok(4160);
235	ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed");
236
237	sender_msqid = msgget(msgkey, IPC_CREAT | 0640);
238	ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno);
239	write_int("sender_msqid", sender_msqid);
240
241	if (did_sigsys) {
242		atf_tc_skip("SYSV Message Queue not supported");
243		return;
244	}
245
246	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
247	"msgctl IPC_STAT 1: %d", errno);
248
249	print_msqid_ds(&m_ds, 0640);
250
251	m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600;
252
253	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1,
254	    "msgctl IPC_SET: %d", errno);
255
256	memset(&m_ds, 0, sizeof(m_ds));
257
258	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
259	    "msgctl IPC_STAT 2: %d", errno);
260
261	ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600,
262	    "IPC_SET of mode didn't hold");
263
264	print_msqid_ds(&m_ds, 0600);
265
266	switch ((child_pid = fork())) {
267	case -1:
268		atf_tc_fail("fork: %d", errno);
269		return;
270
271	case 0:
272		child_count++;
273		receiver();
274		break;
275
276	default:
277		break;
278	}
279
280	for (loop = 0; loop < maxloop; loop++) {
281		/*
282		 * Send the first message to the receiver and wait for the ACK.
283		 */
284		m.mtype = MTYPE_1;
285		strcpy(m.mtext, m1_str);
286		ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN,
287		    0) != -1, "sender: msgsnd 1: %d", errno);
288
289		ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
290				       MTYPE_1_ACK, 0) == MESSAGE_TEXT_LEN,
291		    "sender: msgrcv 1 ack: %d", errno);
292
293		print_msqid_ds(&m_ds, 0600);
294
295		/*
296		 * Send the second message to the receiver and wait for the ACK.
297		 */
298		m.mtype = MTYPE_2;
299		strcpy(m.mtext, m2_str);
300		ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 0) != -1,
301		    "sender: msgsnd 2: %d", errno);
302
303		ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
304				       MTYPE_2_ACK, 0) == MESSAGE_TEXT_LEN,
305		    "sender: msgrcv 2 ack: %d", errno);
306	}
307
308	/*
309	 * Wait for child to finish
310	 */
311	sigemptyset(&sigmask);
312	(void) sigsuspend(&sigmask);
313
314	/*
315	 * ...and any other signal is an unexpected error.
316	 */
317	if (did_sigchild) {
318		c_status = child_status;
319		if (c_status < 0)
320			atf_tc_fail("waitpid: %d", -c_status);
321		else if (WIFEXITED(c_status) == 0)
322			atf_tc_fail("child abnormal exit: %d", c_status);
323		else if (WEXITSTATUS(c_status) != 0)
324			atf_tc_fail("c status: %d", WEXITSTATUS(c_status));
325		else {
326			ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds)
327			    != -1, "msgctl IPC_STAT: %d", errno);
328
329			print_msqid_ds(&m_ds, 0600);
330			atf_tc_pass();
331		}
332	} else
333		atf_tc_fail("sender: received unexpected signal");
334}
335
336ATF_TC_CLEANUP(msg, tc)
337{
338	int sender_msqid;
339
340	/*
341	 * Remove the message queue if it exists.
342	 */
343	sender_msqid = read_int("sender_msqid");
344	if (sender_msqid != -1)
345		if (msgctl(sender_msqid, IPC_RMID, NULL) == -1)
346			err(1, "msgctl IPC_RMID");
347}
348
349void
350print_msqid_ds(mp, mode)
351	struct msqid_ds *mp;
352	mode_t mode;
353{
354	uid_t uid = geteuid();
355	gid_t gid = getegid();
356
357	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
358	    mp->msg_perm.uid, mp->msg_perm.gid,
359	    mp->msg_perm.cuid, mp->msg_perm.cgid,
360	    mp->msg_perm.mode & 0777);
361
362	printf("qnum %lu, qbytes %lu, lspid %d, lrpid %d\n",
363	    mp->msg_qnum, (u_long)mp->msg_qbytes, mp->msg_lspid,
364	    mp->msg_lrpid);
365
366	printf("stime: %s", ctime(&mp->msg_stime));
367	printf("rtime: %s", ctime(&mp->msg_rtime));
368	printf("ctime: %s", ctime(&mp->msg_ctime));
369
370	/*
371	 * Sanity check a few things.
372	 */
373
374	ATF_REQUIRE_MSG(mp->msg_perm.uid == uid && mp->msg_perm.cuid == uid,
375	    "uid mismatch");
376
377	ATF_REQUIRE_MSG(mp->msg_perm.gid == gid && mp->msg_perm.cgid == gid,
378	    "gid mismatch");
379
380	ATF_REQUIRE_MSG((mp->msg_perm.mode & 0777) == mode, "mode mismatch");
381}
382
383void
384receiver()
385{
386	struct mymsg m;
387	int msqid, loop;
388
389	if ((msqid = msgget(msgkey, 0)) == -1)
390		err(1, "receiver: msgget");
391
392	for (loop = 0; loop < maxloop; loop++) {
393		/*
394		 * Receive the first message, print it, and send an ACK.
395		 */
396		if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_1, 0) != MESSAGE_TEXT_LEN)
397			err(1, "receiver: msgrcv 1");
398
399		printf("%s\n", m.mtext);
400		if (strcmp(m.mtext, m1_str) != 0)
401			err(1, "receiver: message 1 data isn't correct");
402
403		m.mtype = MTYPE_1_ACK;
404
405		if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
406			err(1, "receiver: msgsnd ack 1");
407
408		/*
409		 * Receive the second message, print it, and send an ACK.
410		 */
411
412		if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_2, 0) != MESSAGE_TEXT_LEN)
413			err(1, "receiver: msgrcv 2");
414
415		printf("%s\n", m.mtext);
416		if (strcmp(m.mtext, m2_str) != 0)
417			err(1, "receiver: message 2 data isn't correct");
418
419		m.mtype = MTYPE_2_ACK;
420
421		if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
422			err(1, "receiver: msgsnd ack 2");
423	}
424
425	exit(0);
426}
427
428/*
429 * Test the SVID-compatible Semaphore facility.
430 */
431
432ATF_TC_WITH_CLEANUP(sem);
433ATF_TC_HEAD(sem, tc)
434{
435
436	atf_tc_set_md_var(tc, "timeout", "3");
437	atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
438}
439
440ATF_TC_BODY(sem, tc)
441{
442	struct sigaction sa;
443	union semun sun;
444	struct semid_ds s_ds;
445	sigset_t sigmask;
446	int sender_semid;
447	int i;
448	int c_status;
449
450	/*
451	 * Install a SIGSYS handler so that we can exit gracefully if
452	 * System V Semaphore support isn't in the kernel.
453	 */
454	did_sigsys = 0;
455	sa.sa_handler = sigsys_handler;
456	sigemptyset(&sa.sa_mask);
457	sa.sa_flags = 0;
458	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
459	    "sigaction SIGSYS: %d", errno);
460
461	/*
462	 * Install a SIGCHLD handler to deal with all possible exit
463	 * conditions of the receiver.
464	 */
465	did_sigchild = 0;
466	child_count = 0;
467	sa.sa_handler = sigchld_handler;
468	sigemptyset(&sa.sa_mask);
469	sa.sa_flags = 0;
470	ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
471	    "sigaction SIGCHLD: %d", errno);
472
473	semkey = get_ftok(4160);
474	ATF_REQUIRE_MSG(semkey != (key_t)-1, "get_ftok failed");
475
476	sender_semid = semget(semkey, 1, IPC_CREAT | 0640);
477	ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno);
478	write_int("sender_semid", sender_semid);
479
480	if (did_sigsys) {
481		atf_tc_skip("SYSV Semaphore not supported");
482		return;
483	}
484
485	sun.buf = &s_ds;
486	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
487	    "semctl IPC_STAT: %d", errno);
488
489	print_semid_ds(&s_ds, 0640);
490
491	s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600;
492
493	sun.buf = &s_ds;
494	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1,
495	    "semctl IPC_SET: %d", errno);
496
497	memset(&s_ds, 0, sizeof(s_ds));
498
499	sun.buf = &s_ds;
500	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
501	    "semctl IPC_STAT: %d", errno);
502
503	ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600,
504	    "IPC_SET of mode didn't hold");
505
506	print_semid_ds(&s_ds, 0600);
507
508	for (child_count = 0; child_count < 5; child_count++) {
509		switch ((child_pid = fork())) {
510		case -1:
511			atf_tc_fail("fork: %d", errno);
512			return;
513
514		case 0:
515			waiter();
516			break;
517
518		default:
519			break;
520		}
521	}
522
523	/*
524	 * Wait for all of the waiters to be attempting to acquire the
525	 * semaphore.
526	 */
527	for (;;) {
528		i = semctl(sender_semid, 0, GETNCNT);
529		if (i == -1)
530			atf_tc_fail("semctl GETNCNT: %d", i);
531		if (i == 5)
532			break;
533	}
534
535	/*
536	 * Now set the thundering herd in motion by initializing the
537	 * semaphore to the value 1.
538	 */
539	sun.val = 1;
540	ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1,
541	    "sender: semctl SETVAL to 1: %d", errno);
542
543	/*
544	 * Wait for all children to finish
545	 */
546	sigemptyset(&sigmask);
547	for (;;) {
548		(void) sigsuspend(&sigmask);
549		if (did_sigchild) {
550			c_status = child_status;
551			if (c_status < 0)
552				atf_tc_fail("waitpid: %d", -c_status);
553			else if (WIFEXITED(c_status) == 0)
554				atf_tc_fail("c abnormal exit: %d", c_status);
555			else if (WEXITSTATUS(c_status) != 0)
556				atf_tc_fail("c status: %d",
557				    WEXITSTATUS(c_status));
558			else {
559				sun.buf = &s_ds;
560				ATF_REQUIRE_MSG(semctl(sender_semid, 0,
561						    IPC_STAT, sun) != -1,
562				    "semctl IPC_STAT: %d", errno);
563
564				print_semid_ds(&s_ds, 0600);
565				atf_tc_pass();
566			}
567			if (child_count <= 0)
568				break;
569			did_sigchild = 0;
570		} else {
571			atf_tc_fail("sender: received unexpected signal");
572			break;
573		}
574	}
575}
576
577ATF_TC_CLEANUP(sem, tc)
578{
579	int sender_semid;
580
581	/*
582	 * Remove the semaphore if it exists
583	 */
584	sender_semid = read_int("sender_semid");
585	if (sender_semid != -1)
586		if (semctl(sender_semid, 0, IPC_RMID) == -1)
587			err(1, "semctl IPC_RMID");
588}
589
590void
591print_semid_ds(sp, mode)
592	struct semid_ds *sp;
593	mode_t mode;
594{
595	uid_t uid = geteuid();
596	gid_t gid = getegid();
597
598	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
599	    sp->sem_perm.uid, sp->sem_perm.gid,
600	    sp->sem_perm.cuid, sp->sem_perm.cgid,
601	    sp->sem_perm.mode & 0777);
602
603	printf("nsems %u\n", sp->sem_nsems);
604
605	printf("otime: %s", ctime(&sp->sem_otime));
606	printf("ctime: %s", ctime(&sp->sem_ctime));
607
608	/*
609	 * Sanity check a few things.
610	 */
611
612	ATF_REQUIRE_MSG(sp->sem_perm.uid == uid && sp->sem_perm.cuid == uid,
613	    "uid mismatch");
614
615	ATF_REQUIRE_MSG(sp->sem_perm.gid == gid && sp->sem_perm.cgid == gid,
616	    "gid mismatch");
617
618	ATF_REQUIRE_MSG((sp->sem_perm.mode & 0777) == mode,
619	    "mode mismatch %o != %o", (sp->sem_perm.mode & 0777), mode);
620}
621
622void
623waiter()
624{
625	struct sembuf s;
626	int semid;
627
628	if ((semid = semget(semkey, 1, 0)) == -1)
629		err(1, "waiter: semget");
630
631	/*
632	 * Attempt to acquire the semaphore.
633	 */
634	s.sem_num = 0;
635	s.sem_op = -1;
636	s.sem_flg = SEM_UNDO;
637
638	if (semop(semid, &s, 1) == -1)
639		err(1, "waiter: semop -1");
640
641	printf("WOO!  GOT THE SEMAPHORE!\n");
642	sleep(1);
643
644	/*
645	 * Release the semaphore and exit.
646	 */
647	s.sem_num = 0;
648	s.sem_op = 1;
649	s.sem_flg = SEM_UNDO;
650
651	if (semop(semid, &s, 1) == -1)
652		err(1, "waiter: semop +1");
653
654	exit(0);
655}
656
657/*
658 * Test the SVID-compatible Shared Memory facility.
659 */
660
661ATF_TC_WITH_CLEANUP(shm);
662ATF_TC_HEAD(shm, tc)
663{
664
665	atf_tc_set_md_var(tc, "timeout", "3");
666	atf_tc_set_md_var(tc, "descr", "Checks sysv shared memory");
667}
668
669ATF_TC_BODY(shm, tc)
670{
671	struct sigaction sa;
672	struct shmid_ds s_ds;
673	sigset_t sigmask;
674	char *shm_buf;
675	int sender_shmid;
676	int c_status;
677
678	/*
679	 * Install a SIGSYS handler so that we can exit gracefully if
680	 * System V Shared Memory support isn't in the kernel.
681	 */
682	did_sigsys = 0;
683	sa.sa_handler = sigsys_handler;
684	sigemptyset(&sa.sa_mask);
685	sa.sa_flags = 0;
686	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
687	    "sigaction SIGSYS: %d", errno);
688
689	/*
690	 * Install a SIGCHLD handler to deal with all possible exit
691	 * conditions of the sharer.
692	 */
693	did_sigchild = 0;
694	child_count = 0;
695	sa.sa_handler = sigchld_handler;
696	sigemptyset(&sa.sa_mask);
697	sa.sa_flags = 0;
698	ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
699	    "sigaction SIGCHLD: %d", errno);
700
701	pgsize = sysconf(_SC_PAGESIZE);
702
703	shmkey = get_ftok(4160);
704	ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed");
705
706	ATF_REQUIRE_MSG((sender_shmid = shmget(shmkey, pgsize,
707					       IPC_CREAT | 0640)) != -1,
708	    "shmget: %d", errno);
709	write_int("sender_shmid", sender_shmid);
710
711	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
712	    "shmctl IPC_STAT: %d", errno);
713
714	print_shmid_ds(&s_ds, 0640);
715
716	s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600;
717
718	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_SET, &s_ds) != -1,
719	    "shmctl IPC_SET: %d", errno);
720
721	memset(&s_ds, 0, sizeof(s_ds));
722
723	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
724	    "shmctl IPC_STAT: %d", errno);
725
726	ATF_REQUIRE_MSG((s_ds.shm_perm.mode & 0777) == 0600,
727	    "IPC_SET of mode didn't hold");
728
729	print_shmid_ds(&s_ds, 0600);
730
731	shm_buf = shmat(sender_shmid, NULL, 0);
732	ATF_REQUIRE_MSG(shm_buf != (void *) -1, "sender: shmat: %d", errno);
733
734	/*
735	 * Write the test pattern into the shared memory buffer.
736	 */
737	strcpy(shm_buf, m2_str);
738
739	switch ((child_pid = fork())) {
740	case -1:
741		atf_tc_fail("fork: %d", errno);
742		return;
743
744	case 0:
745		sharer();
746		break;
747
748	default:
749		break;
750	}
751
752	/*
753	 * Wait for child to finish
754	 */
755	sigemptyset(&sigmask);
756	(void) sigsuspend(&sigmask);
757
758	if (did_sigchild) {
759		c_status = child_status;
760		if (c_status < 0)
761			atf_tc_fail("waitpid: %d", -c_status);
762		else if (WIFEXITED(c_status) == 0)
763			atf_tc_fail("c abnormal exit: %d", c_status);
764		else if (WEXITSTATUS(c_status) != 0)
765			atf_tc_fail("c status: %d", WEXITSTATUS(c_status));
766		else {
767			ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT,
768					       &s_ds) != -1,
769			    "shmctl IPC_STAT: %d", errno);
770
771			print_shmid_ds(&s_ds, 0600);
772			atf_tc_pass();
773		}
774	} else
775		atf_tc_fail("sender: received unexpected signal");
776}
777
778ATF_TC_CLEANUP(shm, tc)
779{
780	int sender_shmid;
781
782	/*
783	 * Remove the shared memory area if it exists.
784	 */
785	sender_shmid = read_int("sender_shmid");
786	if (sender_shmid != -1)
787		if (shmctl(sender_shmid, IPC_RMID, NULL) == -1)
788			err(1, "shmctl IPC_RMID");
789}
790
791void
792print_shmid_ds(sp, mode)
793	struct shmid_ds *sp;
794	mode_t mode;
795{
796	uid_t uid = geteuid();
797	gid_t gid = getegid();
798
799	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
800	    sp->shm_perm.uid, sp->shm_perm.gid,
801	    sp->shm_perm.cuid, sp->shm_perm.cgid,
802	    sp->shm_perm.mode & 0777);
803
804	printf("segsz %lu, lpid %d, cpid %d, nattch %u\n",
805	    (u_long)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid,
806	    sp->shm_nattch);
807
808	printf("atime: %s", ctime(&sp->shm_atime));
809	printf("dtime: %s", ctime(&sp->shm_dtime));
810	printf("ctime: %s", ctime(&sp->shm_ctime));
811
812	/*
813	 * Sanity check a few things.
814	 */
815
816	ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid,
817	    "uid mismatch");
818
819	ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid,
820	    "gid mismatch");
821
822	ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode, "mode mismatch");
823}
824
825void
826sharer()
827{
828	int shmid;
829	void *shm_buf;
830
831	shmid = shmget(shmkey, pgsize, 0);
832	ATF_REQUIRE_MSG(shmid != -1, "receiver: shmget:%d", errno);
833
834	shm_buf = shmat(shmid, NULL, 0);
835	ATF_REQUIRE_MSG(shm_buf != (void *) -1, "receiver: shmat: %d", errno);
836
837	printf("%s\n", (const char *)shm_buf);
838
839	ATF_REQUIRE_MSG(strcmp((const char *)shm_buf, m2_str) == 0,
840	    "receiver: data isn't correct");
841
842	exit(0);
843}
844
845ATF_TP_ADD_TCS(tp)
846{
847
848	ATF_TP_ADD_TC(tp, msg);
849	ATF_TP_ADD_TC(tp, sem);
850	ATF_TP_ADD_TC(tp, shm);
851
852	return atf_no_error();
853}
854
855