Home | History | Annotate | Line # | Download | only in kernel
t_sysv.c revision 1.5
      1 /*	$NetBSD: t_sysv.c,v 1.5 2018/02/03 02:57:15 pgoyette 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 		read(input, &value, sizeof(value));
    131 		return value;
    132 	}
    133 }
    134 
    135 
    136 void
    137 sigsys_handler(int signo)
    138 {
    139 
    140 	did_sigsys = 1;
    141 }
    142 
    143 void
    144 sigchld_handler(int signo)
    145 {
    146 	int c_status;
    147 
    148 	did_sigchild = 1;
    149 	/*
    150 	 * Reap the child and return its status
    151 	 */
    152 	if (wait(&c_status) == -1)
    153 		child_status = -errno;
    154 	else
    155 		child_status = c_status;
    156 
    157 	child_count--;
    158 }
    159 
    160 key_t get_ftok(int id)
    161 {
    162 	int fd;
    163 	char token_key[64], token_dir[64];
    164 	char *tmpdir;
    165 	key_t key;
    166 
    167 	strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key));
    168 	tmpdir = mkdtemp(token_key);
    169 	ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno);
    170 
    171 	strlcpy(token_dir, tmpdir, sizeof(token_dir));
    172 	strlcpy(token_key, tmpdir, sizeof(token_key));
    173 	strlcat(token_key, "/token_key", sizeof(token_key));
    174 
    175 	/* Create the file, since ftok() requires it to exist! */
    176 
    177 	fd = open(token_key, O_RDWR | O_CREAT | O_EXCL, 0600);
    178 	if (fd == -1) {
    179 		rmdir(tmpdir);
    180 		atf_tc_fail("open() of temp file failed: %d", errno);
    181 		return (key_t)-1;
    182 	} else
    183 		close(fd);
    184 
    185 	key = ftok(token_key, id);
    186 	ATF_REQUIRE_MSG(key != (key_t)-1, "ftok() failed");
    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 		strcpy(m.mtext, m1_str);
    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 		strcpy(m.mtext, m2_str);
    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,
    818 	    "mode mismatch %o != %o", sp->shm_perm.mode & 0777, mode);
    819 }
    820 
    821 void
    822 sharer(void)
    823 {
    824 	int shmid;
    825 	void *shm_buf;
    826 
    827 	shmid = shmget(shmkey, pgsize, 0);
    828 	ATF_REQUIRE_MSG(shmid != -1, "receiver: shmget:%d", errno);
    829 
    830 	shm_buf = shmat(shmid, NULL, 0);
    831 	ATF_REQUIRE_MSG(shm_buf != (void *) -1, "receiver: shmat: %d", errno);
    832 
    833 	printf("%s\n", (const char *)shm_buf);
    834 
    835 	ATF_REQUIRE_MSG(strcmp((const char *)shm_buf, m2_str) == 0,
    836 	    "receiver: data isn't correct");
    837 
    838 	exit(0);
    839 }
    840 
    841 ATF_TP_ADD_TCS(tp)
    842 {
    843 
    844 	ATF_TP_ADD_TC(tp, msg);
    845 	ATF_TP_ADD_TC(tp, sem);
    846 	ATF_TP_ADD_TC(tp, shm);
    847 
    848 	return atf_no_error();
    849 }
    850 
    851