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