xref: /freebsd-src/contrib/netbsd-tests/kernel/t_sysv.c (revision 091002585974d17c9533f943ec351c13a69788ab)
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 
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 testmsg {
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 pid_t	child_pid;
92 
93 key_t	msgkey, semkey, shmkey;
94 
95 int	maxloop = 1;
96 
97 #ifndef __FreeBSD__
98 union 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. */
108 static void
109 write_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. */
122 static int
123 read_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 
139 void
140 sigsys_handler(int signo)
141 {
142 
143 	did_sigsys = 1;
144 }
145 
146 void
147 sigchld_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 
163 key_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 
196 ATF_TC_WITH_CLEANUP(msg);
197 ATF_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 
204 ATF_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 
339 ATF_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 
352 void
353 print_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 
384 void
385 receiver(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 
433 ATF_TC_WITH_CLEANUP(sem);
434 ATF_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 
441 ATF_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 
578 ATF_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 
591 void
592 print_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 
621 void
622 waiter(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 
660 ATF_TC_WITH_CLEANUP(shm);
661 ATF_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 
668 ATF_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 
777 ATF_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 
790 void
791 print_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 
822 void
823 sharer(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 
842 ATF_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