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