Home | History | Annotate | Line # | Download | only in kernel
t_sysv.c revision 1.3
      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