xref: /freebsd/contrib/netbsd-tests/kernel/t_sysv.c (revision 2cf0c51793da5a2fc03db8990fc2feb3f9aa119f)
1 /*	$NetBSD: t_sysv.c,v 1.4 2014/03/02 20:13:12 jmmv Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999, 2007 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9  * NASA Ames Research Center, and by Andrew Doran.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Test the SVID-compatible Message Queue facility.
35  */
36 
37 #include <atf-c.h>
38 
39 #include <err.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <signal.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <time.h>
47 #include <unistd.h>
48 
49 #include <sys/ipc.h>
50 #include <sys/mman.h>
51 #include <sys/msg.h>
52 #include <sys/param.h>
53 #include <sys/sem.h>
54 #include <sys/shm.h>
55 #include <sys/wait.h>
56 
57 volatile int did_sigsys;
58 
59 void	sigsys_handler(int);
60 
61 key_t	get_ftok(int);
62 
63 void	print_msqid_ds(struct msqid_ds *, mode_t);
64 void	receiver(void);
65 
66 void	print_semid_ds(struct semid_ds *, mode_t);
67 void	waiter(void);
68 
69 void	print_shmid_ds(struct shmid_ds *, mode_t);
70 void	sharer(void);
71 
72 #define	MESSAGE_TEXT_LEN	256
73 
74 struct testmsg {
75 	long	mtype;
76 	char	mtext[MESSAGE_TEXT_LEN];
77 };
78 
79 const char *m1_str = "California is overrated.";
80 const char *m2_str = "The quick brown fox jumped over the lazy dog.";
81 
82 size_t	pgsize;
83 
84 #define	MTYPE_1		1
85 #define	MTYPE_1_ACK	2
86 
87 #define	MTYPE_2		3
88 #define	MTYPE_2_ACK	4
89 
90 pid_t	child_pid;
91 
92 key_t	msgkey, semkey, shmkey;
93 
94 int	maxloop = 1;
95 
96 union semun {
97 	int	val;		/* value for SETVAL */
98 	struct	semid_ds *buf;	/* buffer for IPC_{STAT,SET} */
99 	u_short	*array;		/* array for GETALL & SETALL */
100 };
101 
102 
103 /* Writes an integer to a file.  To be used from the body of the test
104  * cases below to pass any global identifiers to the cleanup routine. */
105 static void
106 write_int(const char *path, const int value)
107 {
108 	int output;
109 
110 	output = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
111 	ATF_REQUIRE_MSG(output != -1, "Failed to create %s", path);
112 	write(output, &value, sizeof(value));
113 	close(output);
114 }
115 
116 
117 /* Reads an integer from a file.  To be used from the cleanup routines
118  * of the test cases below. */
119 static int
120 read_int(const char *path)
121 {
122 	int input;
123 
124 	input = open(path, O_RDONLY);
125 	if (input == -1)
126 		return -1;
127 	else {
128 		int value;
129 		ATF_REQUIRE_EQ(read(input, &value, sizeof(value)), sizeof(value));
130 		close(input);
131 		return value;
132 	}
133 }
134 
135 
136 void
137 sigsys_handler(int signo)
138 {
139 
140 	did_sigsys = 1;
141 }
142 
143 key_t get_ftok(int id)
144 {
145 	int fd;
146 	char token_key[64], token_dir[64];
147 	char *tmpdir;
148 	key_t key;
149 
150 	strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key));
151 	tmpdir = mkdtemp(token_key);
152 	ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno);
153 
154 	strlcpy(token_dir, tmpdir, sizeof(token_dir));
155 	strlcpy(token_key, tmpdir, sizeof(token_key));
156 	strlcat(token_key, "/token_key", sizeof(token_key));
157 
158 	/* Create the file, since ftok() requires it to exist! */
159 
160 	fd = open(token_key, O_RDWR | O_CREAT | O_EXCL, 0600);
161 	if (fd == -1) {
162 		rmdir(tmpdir);
163 		atf_tc_fail("open() of temp file failed: %d", errno);
164 		return (key_t)-1;
165 	} else
166 		close(fd);
167 
168 	key = ftok(token_key, id);
169 
170 	ATF_REQUIRE_MSG(unlink(token_key) != -1, "unlink() failed: %d", errno);
171 	ATF_REQUIRE_MSG(rmdir(token_dir) != -1, "rmdir() failed: %d", errno);
172 
173 	return key;
174 }
175 
176 ATF_TC_WITH_CLEANUP(msg);
177 ATF_TC_HEAD(msg, tc)
178 {
179 
180 	atf_tc_set_md_var(tc, "timeout", "3");
181 	atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
182 }
183 
184 ATF_TC_BODY(msg, tc)
185 {
186 	struct sigaction sa;
187 	struct msqid_ds m_ds;
188 	struct testmsg m;
189 	int sender_msqid;
190 	int loop;
191 	int c_status;
192 	pid_t wait_result;
193 
194 	/*
195 	 * Install a SIGSYS handler so that we can exit gracefully if
196 	 * System V Message Queue support isn't in the kernel.
197 	 */
198 	did_sigsys = 0;
199 	sa.sa_handler = sigsys_handler;
200 	sigemptyset(&sa.sa_mask);
201 	sa.sa_flags = 0;
202 	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
203 	    "sigaction SIGSYS: %d", errno);
204 
205 	msgkey = get_ftok(4160);
206 	ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed");
207 
208 	sender_msqid = msgget(msgkey, IPC_CREAT | 0640);
209 	ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno);
210 	write_int("sender_msqid", sender_msqid);
211 
212 	if (did_sigsys) {
213 		atf_tc_skip("SYSV Message Queue not supported");
214 		return;
215 	}
216 
217 	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
218 	"msgctl IPC_STAT 1: %d", errno);
219 
220 	print_msqid_ds(&m_ds, 0640);
221 
222 	m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600;
223 
224 	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1,
225 	    "msgctl IPC_SET: %d", errno);
226 
227 	memset(&m_ds, 0, sizeof(m_ds));
228 
229 	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
230 	    "msgctl IPC_STAT 2: %d", errno);
231 
232 	ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600,
233 	    "IPC_SET of mode didn't hold");
234 
235 	print_msqid_ds(&m_ds, 0600);
236 
237 	fflush(stdout);
238 
239 	switch ((child_pid = fork())) {
240 	case -1:
241 		atf_tc_fail("fork: %d", errno);
242 		return;
243 
244 	case 0:
245 		receiver();
246 		break;
247 
248 	default:
249 		break;
250 	}
251 
252 	for (loop = 0; loop < maxloop; loop++) {
253 		/*
254 		 * Send the first message to the receiver and wait for the ACK.
255 		 */
256 		m.mtype = MTYPE_1;
257 		strlcpy(m.mtext, m1_str, sizeof(m.mtext));
258 		ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN,
259 		    0) != -1, "sender: msgsnd 1: %d", errno);
260 
261 		ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
262 				       MTYPE_1_ACK, 0) == MESSAGE_TEXT_LEN,
263 		    "sender: msgrcv 1 ack: %d", errno);
264 
265 		print_msqid_ds(&m_ds, 0600);
266 
267 		/*
268 		 * Send the second message to the receiver and wait for the ACK.
269 		 */
270 		m.mtype = MTYPE_2;
271 		strlcpy(m.mtext, m2_str, sizeof(m.mtext));
272 		ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 0) != -1,
273 		    "sender: msgsnd 2: %d", errno);
274 
275 		ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
276 				       MTYPE_2_ACK, 0) == MESSAGE_TEXT_LEN,
277 		    "sender: msgrcv 2 ack: %d", errno);
278 	}
279 
280 	/*
281 	 * Wait for child to finish
282 	 */
283 	wait_result = wait(&c_status);
284 	ATF_REQUIRE_EQ_MSG(wait_result, child_pid, "wait returned %d (%s)",
285 	    wait_result, wait_result == -1 ? strerror(errno) : "");
286 	ATF_REQUIRE_MSG(WIFEXITED(c_status), "child abnormal exit: %d (sig %d)",
287 	    c_status, WTERMSIG(c_status));
288 	ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d",
289 	    WEXITSTATUS(c_status));
290 
291 	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
292 	    "msgctl IPC_STAT: %d", errno);
293 
294 	print_msqid_ds(&m_ds, 0600);
295 }
296 
297 ATF_TC_CLEANUP(msg, tc)
298 {
299 	int sender_msqid;
300 
301 	/*
302 	 * Remove the message queue if it exists.
303 	 */
304 	sender_msqid = read_int("sender_msqid");
305 	if (sender_msqid != -1)
306 		if (msgctl(sender_msqid, IPC_RMID, NULL) == -1)
307 			err(1, "msgctl IPC_RMID");
308 }
309 
310 void
311 print_msqid_ds(struct msqid_ds *mp, mode_t mode)
312 {
313 	uid_t uid = geteuid();
314 	gid_t gid = getegid();
315 
316 	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
317 	    mp->msg_perm.uid, mp->msg_perm.gid,
318 	    mp->msg_perm.cuid, mp->msg_perm.cgid,
319 	    mp->msg_perm.mode & 0777);
320 
321 	printf("qnum %lu, qbytes %lu, lspid %d, lrpid %d\n",
322 	    mp->msg_qnum, (u_long)mp->msg_qbytes, mp->msg_lspid,
323 	    mp->msg_lrpid);
324 
325 	printf("stime: %s", ctime(&mp->msg_stime));
326 	printf("rtime: %s", ctime(&mp->msg_rtime));
327 	printf("ctime: %s", ctime(&mp->msg_ctime));
328 
329 	/*
330 	 * Sanity check a few things.
331 	 */
332 
333 	ATF_REQUIRE_MSG(mp->msg_perm.uid == uid && mp->msg_perm.cuid == uid,
334 	    "uid mismatch");
335 
336 	ATF_REQUIRE_MSG(mp->msg_perm.gid == gid && mp->msg_perm.cgid == gid,
337 	    "gid mismatch");
338 
339 	ATF_REQUIRE_MSG((mp->msg_perm.mode & 0777) == mode, "mode mismatch");
340 }
341 
342 void
343 receiver(void)
344 {
345 	struct testmsg m;
346 	int msqid, loop;
347 
348 	if ((msqid = msgget(msgkey, 0)) == -1)
349 		err(1, "receiver: msgget");
350 
351 	for (loop = 0; loop < maxloop; loop++) {
352 		/*
353 		 * Receive the first message, print it, and send an ACK.
354 		 */
355 		if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_1, 0) != MESSAGE_TEXT_LEN)
356 			err(1, "receiver: msgrcv 1");
357 
358 		printf("%s\n", m.mtext);
359 		if (strcmp(m.mtext, m1_str) != 0)
360 			errx(1, "receiver: message 1 data isn't correct");
361 
362 		m.mtype = MTYPE_1_ACK;
363 
364 		if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
365 			err(1, "receiver: msgsnd ack 1");
366 
367 		/*
368 		 * Receive the second message, print it, and send an ACK.
369 		 */
370 
371 		if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_2, 0) != MESSAGE_TEXT_LEN)
372 			err(1, "receiver: msgrcv 2");
373 
374 		printf("%s\n", m.mtext);
375 		if (strcmp(m.mtext, m2_str) != 0)
376 			errx(1, "receiver: message 2 data isn't correct");
377 
378 		m.mtype = MTYPE_2_ACK;
379 
380 		if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
381 			err(1, "receiver: msgsnd ack 2");
382 	}
383 
384 	exit(0);
385 }
386 
387 /*
388  * Test the SVID-compatible Semaphore facility.
389  */
390 
391 ATF_TC_WITH_CLEANUP(sem);
392 ATF_TC_HEAD(sem, tc)
393 {
394 
395 	atf_tc_set_md_var(tc, "timeout", "3");
396 	atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
397 }
398 
399 ATF_TC_BODY(sem, tc)
400 {
401 	struct sigaction sa;
402 	union semun sun;
403 	struct semid_ds s_ds;
404 	int sender_semid;
405 	int i;
406 	int c_status;
407 	int child_count;
408 	pid_t wait_result;
409 
410 	/*
411 	 * Install a SIGSYS handler so that we can exit gracefully if
412 	 * System V Semaphore support isn't in the kernel.
413 	 */
414 	did_sigsys = 0;
415 	sa.sa_handler = sigsys_handler;
416 	sigemptyset(&sa.sa_mask);
417 	sa.sa_flags = 0;
418 	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
419 	    "sigaction SIGSYS: %d", errno);
420 
421 	semkey = get_ftok(4160);
422 	ATF_REQUIRE_MSG(semkey != (key_t)-1, "get_ftok failed");
423 
424 	sender_semid = semget(semkey, 1, IPC_CREAT | 0640);
425 	ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno);
426 	write_int("sender_semid", sender_semid);
427 
428 	if (did_sigsys) {
429 		atf_tc_skip("SYSV Semaphore not supported");
430 		return;
431 	}
432 
433 	sun.buf = &s_ds;
434 	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
435 	    "semctl IPC_STAT: %d", errno);
436 
437 	print_semid_ds(&s_ds, 0640);
438 
439 	s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600;
440 
441 	sun.buf = &s_ds;
442 	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1,
443 	    "semctl IPC_SET: %d", errno);
444 
445 	memset(&s_ds, 0, sizeof(s_ds));
446 
447 	sun.buf = &s_ds;
448 	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
449 	    "semctl IPC_STAT: %d", errno);
450 
451 	ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600,
452 	    "IPC_SET of mode didn't hold");
453 
454 	print_semid_ds(&s_ds, 0600);
455 
456 	fflush(stdout);
457 
458 	for (child_count = 0; child_count < 5; child_count++) {
459 		switch ((child_pid = fork())) {
460 		case -1:
461 			atf_tc_fail("fork: %d", errno);
462 			return;
463 
464 		case 0:
465 			waiter();
466 			break;
467 
468 		default:
469 			break;
470 		}
471 	}
472 
473 	/*
474 	 * Wait for all of the waiters to be attempting to acquire the
475 	 * semaphore.
476 	 */
477 	for (;;) {
478 		i = semctl(sender_semid, 0, GETNCNT);
479 		if (i == -1)
480 			atf_tc_fail("semctl GETNCNT: %d", i);
481 		if (i == 5)
482 			break;
483 	}
484 
485 	/*
486 	 * Now set the thundering herd in motion by initializing the
487 	 * semaphore to the value 1.
488 	 */
489 	sun.val = 1;
490 	ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1,
491 	    "sender: semctl SETVAL to 1: %d", errno);
492 
493 	/*
494 	 * Wait for all children to finish
495 	 */
496 	while (child_count-- > 0) {
497 		wait_result = wait(&c_status);
498 		ATF_REQUIRE_MSG(wait_result != -1, "wait failed: %s",
499 		    strerror(errno));
500 		ATF_REQUIRE_MSG(WIFEXITED(c_status),
501 		    "child abnormal exit: %d (sig %d)",
502 		    c_status, WTERMSIG(c_status));
503 		ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d",
504 		    WEXITSTATUS(c_status));
505 
506 		sun.buf = &s_ds;
507 		ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
508 		    "semctl IPC_STAT: %d", errno);
509 
510 		print_semid_ds(&s_ds, 0600);
511 	}
512 }
513 
514 ATF_TC_CLEANUP(sem, tc)
515 {
516 	int sender_semid;
517 
518 	/*
519 	 * Remove the semaphore if it exists
520 	 */
521 	sender_semid = read_int("sender_semid");
522 	if (sender_semid != -1)
523 		if (semctl(sender_semid, 0, IPC_RMID) == -1)
524 			err(1, "semctl IPC_RMID");
525 }
526 
527 void
528 print_semid_ds(struct semid_ds *sp, mode_t mode)
529 {
530 	uid_t uid = geteuid();
531 	gid_t gid = getegid();
532 
533 	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
534 	    sp->sem_perm.uid, sp->sem_perm.gid,
535 	    sp->sem_perm.cuid, sp->sem_perm.cgid,
536 	    sp->sem_perm.mode & 0777);
537 
538 	printf("nsems %u\n", sp->sem_nsems);
539 
540 	printf("otime: %s", ctime(&sp->sem_otime));
541 	printf("ctime: %s", ctime(&sp->sem_ctime));
542 
543 	/*
544 	 * Sanity check a few things.
545 	 */
546 
547 	ATF_REQUIRE_MSG(sp->sem_perm.uid == uid && sp->sem_perm.cuid == uid,
548 	    "uid mismatch");
549 
550 	ATF_REQUIRE_MSG(sp->sem_perm.gid == gid && sp->sem_perm.cgid == gid,
551 	    "gid mismatch");
552 
553 	ATF_REQUIRE_MSG((sp->sem_perm.mode & 0777) == mode,
554 	    "mode mismatch %o != %o", (sp->sem_perm.mode & 0777), mode);
555 }
556 
557 void
558 waiter(void)
559 {
560 	struct sembuf s;
561 	int semid;
562 
563 	if ((semid = semget(semkey, 1, 0)) == -1)
564 		err(1, "waiter: semget");
565 
566 	/*
567 	 * Attempt to acquire the semaphore.
568 	 */
569 	s.sem_num = 0;
570 	s.sem_op = -1;
571 	s.sem_flg = SEM_UNDO;
572 
573 	if (semop(semid, &s, 1) == -1)
574 		err(1, "waiter: semop -1");
575 
576 	printf("WOO!  GOT THE SEMAPHORE!\n");
577 	usleep(10000);
578 
579 	/*
580 	 * Release the semaphore and exit.
581 	 */
582 	s.sem_num = 0;
583 	s.sem_op = 1;
584 	s.sem_flg = SEM_UNDO;
585 
586 	if (semop(semid, &s, 1) == -1)
587 		err(1, "waiter: semop +1");
588 
589 	exit(0);
590 }
591 
592 /*
593  * Test the SVID-compatible Shared Memory facility.
594  */
595 
596 ATF_TC_WITH_CLEANUP(shm);
597 ATF_TC_HEAD(shm, tc)
598 {
599 
600 	atf_tc_set_md_var(tc, "timeout", "3");
601 	atf_tc_set_md_var(tc, "descr", "Checks sysv shared memory");
602 }
603 
604 ATF_TC_BODY(shm, tc)
605 {
606 	struct sigaction sa;
607 	struct shmid_ds s_ds;
608 	char *shm_buf;
609 	int sender_shmid;
610 	int c_status;
611 	pid_t wait_result;
612 
613 	/*
614 	 * Install a SIGSYS handler so that we can exit gracefully if
615 	 * System V Shared Memory support isn't in the kernel.
616 	 */
617 	did_sigsys = 0;
618 	sa.sa_handler = sigsys_handler;
619 	sigemptyset(&sa.sa_mask);
620 	sa.sa_flags = 0;
621 	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
622 	    "sigaction SIGSYS: %d", errno);
623 
624 	pgsize = sysconf(_SC_PAGESIZE);
625 
626 	shmkey = get_ftok(4160);
627 	ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed");
628 
629 	ATF_REQUIRE_MSG((sender_shmid = shmget(shmkey, pgsize,
630 					       IPC_CREAT | 0640)) != -1,
631 	    "shmget: %d", errno);
632 	write_int("sender_shmid", sender_shmid);
633 
634 	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
635 	    "shmctl IPC_STAT: %d", errno);
636 
637 	print_shmid_ds(&s_ds, 0640);
638 
639 	s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600;
640 
641 	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_SET, &s_ds) != -1,
642 	    "shmctl IPC_SET: %d", errno);
643 
644 	memset(&s_ds, 0, sizeof(s_ds));
645 
646 	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
647 	    "shmctl IPC_STAT: %d", errno);
648 
649 	ATF_REQUIRE_MSG((s_ds.shm_perm.mode & 0777) == 0600,
650 	    "IPC_SET of mode didn't hold");
651 
652 	print_shmid_ds(&s_ds, 0600);
653 
654 	shm_buf = shmat(sender_shmid, NULL, 0);
655 	ATF_REQUIRE_MSG(shm_buf != (void *) -1, "sender: shmat: %d", errno);
656 
657 	/*
658 	 * Write the test pattern into the shared memory buffer.
659 	 */
660 	strcpy(shm_buf, m2_str);
661 
662 	fflush(stdout);
663 
664 	switch ((child_pid = fork())) {
665 	case -1:
666 		atf_tc_fail("fork: %d", errno);
667 		return;
668 
669 	case 0:
670 		sharer();
671 		break;
672 
673 	default:
674 		break;
675 	}
676 
677 	/*
678 	 * Wait for child to finish
679 	 */
680 	wait_result = wait(&c_status);
681 	ATF_REQUIRE_EQ_MSG(wait_result, child_pid, "wait returned %d (%s)",
682 	    wait_result, wait_result == -1 ? strerror(errno) : "");
683 	ATF_REQUIRE_MSG(WIFEXITED(c_status), "child abnormal exit: %d (sig %d)",
684 	    c_status, WTERMSIG(c_status));
685 	ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d",
686 	    WEXITSTATUS(c_status));
687 
688 	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
689 	    "shmctl IPC_STAT: %d", errno);
690 
691 	print_shmid_ds(&s_ds, 0600);
692 }
693 
694 static void
695 shmid_cleanup(const char *name)
696 {
697 	int shmid;
698 
699 	/*
700 	 * Remove the shared memory area if it exists.
701 	 */
702 	shmid = read_int(name);
703 	if (shmid != -1) {
704 		if (shmctl(shmid, IPC_RMID, NULL) == -1)
705 			err(1, "shmctl IPC_RMID");
706 	}
707 }
708 
709 ATF_TC_CLEANUP(shm, tc)
710 {
711 
712 	shmid_cleanup("sender_shmid");
713 }
714 
715 void
716 print_shmid_ds(struct shmid_ds *sp, mode_t mode)
717 {
718 	uid_t uid = geteuid();
719 	gid_t gid = getegid();
720 
721 	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
722 	    sp->shm_perm.uid, sp->shm_perm.gid,
723 	    sp->shm_perm.cuid, sp->shm_perm.cgid,
724 	    sp->shm_perm.mode & 0777);
725 
726 	printf("segsz %lu, lpid %d, cpid %d, nattch %u\n",
727 	    (u_long)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid,
728 	    sp->shm_nattch);
729 
730 	printf("atime: %s", ctime(&sp->shm_atime));
731 	printf("dtime: %s", ctime(&sp->shm_dtime));
732 	printf("ctime: %s", ctime(&sp->shm_ctime));
733 
734 	/*
735 	 * Sanity check a few things.
736 	 */
737 
738 	ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid,
739 	    "uid mismatch");
740 
741 	ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid,
742 	    "gid mismatch");
743 
744 	ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode, "mode mismatch");
745 }
746 
747 void
748 sharer(void)
749 {
750 	int shmid;
751 	void *shm_buf;
752 
753 	shmid = shmget(shmkey, pgsize, 0);
754 	if (shmid == -1)
755 		err(1, "receiver: shmget");
756 
757 	shm_buf = shmat(shmid, NULL, 0);
758 	if (shm_buf == (void *) -1)
759 		err(1, "receiver: shmat");
760 
761 	printf("%s\n", (const char *)shm_buf);
762 
763 	if (strcmp((const char *)shm_buf, m2_str) != 0)
764 		errx(1, "receiver: data isn't correct");
765 
766 	exit(0);
767 }
768 
769 #ifdef SHM_REMAP
770 ATF_TC_WITH_CLEANUP(shm_remap);
771 ATF_TC_HEAD(shm_remap, tc)
772 {
773 
774 	atf_tc_set_md_var(tc, "descr", "Checks SHM_REMAP");
775 }
776 
777 ATF_TC_BODY(shm_remap, tc)
778 {
779 	char *shm_buf;
780 	int shmid_remap;
781 
782 	pgsize = sysconf(_SC_PAGESIZE);
783 
784 	shmkey = get_ftok(4160);
785 	ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed");
786 
787 	ATF_REQUIRE_MSG((shmid_remap = shmget(shmkey, pgsize,
788 	    IPC_CREAT | 0640)) != -1, "shmget: %d", errno);
789 	write_int("shmid_remap", shmid_remap);
790 
791 	ATF_REQUIRE_MSG((shm_buf = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
792 	    MAP_ANON | MAP_PRIVATE, -1, 0)) != MAP_FAILED, "mmap: %d", errno);
793 
794 	ATF_REQUIRE_MSG(shmat(shmid_remap, shm_buf, 0) == (void *)-1,
795 	    "shmat without MAP_REMAP succeeded");
796 	ATF_REQUIRE_MSG(shmat(shmid_remap, shm_buf, SHM_REMAP) == shm_buf,
797 	    "shmat(SHM_REMAP): %d", errno);
798 }
799 
800 ATF_TC_CLEANUP(shm_remap, tc)
801 {
802 
803 	shmid_cleanup("shmid_remap");
804 }
805 #endif	/* SHM_REMAP */
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 #ifdef SHM_REMAP
814 	ATF_TP_ADD_TC(tp, shm_remap);
815 #endif
816 
817 	return atf_no_error();
818 }
819 
820