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