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