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