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