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