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