t_sysv.c revision 343426
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
57volatile int did_sigsys, did_sigchild;
58volatile int child_status, child_count;
59
60void	sigsys_handler(int);
61void	sigchld_handler(int);
62
63key_t	get_ftok(int);
64
65void	print_msqid_ds(struct msqid_ds *, mode_t);
66void	receiver(void);
67
68void	print_semid_ds(struct semid_ds *, mode_t);
69void	waiter(void);
70
71void	print_shmid_ds(struct shmid_ds *, mode_t);
72void	sharer(void);
73
74#define	MESSAGE_TEXT_LEN	256
75
76struct testmsg {
77	long	mtype;
78	char	mtext[MESSAGE_TEXT_LEN];
79};
80
81const char *m1_str = "California is overrated.";
82const char *m2_str = "The quick brown fox jumped over the lazy dog.";
83
84size_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
92pid_t	child_pid;
93
94key_t	msgkey, semkey, shmkey;
95
96int	maxloop = 1;
97
98#ifndef __FreeBSD__
99union semun {
100	int	val;		/* value for SETVAL */
101	struct	semid_ds *buf;	/* buffer for IPC_{STAT,SET} */
102	u_short	*array;		/* array for GETALL & SETALL */
103};
104#endif
105
106
107/* Writes an integer to a file.  To be used from the body of the test
108 * cases below to pass any global identifiers to the cleanup routine. */
109static void
110write_int(const char *path, const int value)
111{
112	int output;
113
114	output = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
115	ATF_REQUIRE_MSG(output != -1, "Failed to create %s", path);
116	write(output, &value, sizeof(value));
117	close(output);
118}
119
120
121/* Reads an integer from a file.  To be used from the cleanup routines
122 * of the test cases below. */
123static int
124read_int(const char *path)
125{
126	int input;
127
128	input = open(path, O_RDONLY);
129	if (input == -1)
130		return -1;
131	else {
132		int value;
133		ATF_REQUIRE_EQ(read(input, &value, sizeof(value)), sizeof(value));
134		close(input);
135		return value;
136	}
137}
138
139
140void
141sigsys_handler(int signo)
142{
143
144	did_sigsys = 1;
145}
146
147void
148sigchld_handler(int signo)
149{
150	int c_status;
151
152	did_sigchild = 1;
153	/*
154	 * Reap the child and return its status
155	 */
156	if (wait(&c_status) == -1)
157		child_status = -errno;
158	else
159		child_status = c_status;
160
161	child_count--;
162}
163
164key_t get_ftok(int id)
165{
166	int fd;
167	char token_key[64], token_dir[64];
168	char *tmpdir;
169	key_t key;
170
171	strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key));
172	tmpdir = mkdtemp(token_key);
173	ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno);
174
175	strlcpy(token_dir, tmpdir, sizeof(token_dir));
176	strlcpy(token_key, tmpdir, sizeof(token_key));
177	strlcat(token_key, "/token_key", sizeof(token_key));
178
179	/* Create the file, since ftok() requires it to exist! */
180
181	fd = open(token_key, O_RDWR | O_CREAT | O_EXCL, 0600);
182	if (fd == -1) {
183		rmdir(tmpdir);
184		atf_tc_fail("open() of temp file failed: %d", errno);
185		return (key_t)-1;
186	} else
187		close(fd);
188
189	key = ftok(token_key, id);
190
191	ATF_REQUIRE_MSG(unlink(token_key) != -1, "unlink() failed: %d", errno);
192	ATF_REQUIRE_MSG(rmdir(token_dir) != -1, "rmdir() failed: %d", errno);
193
194	return key;
195}
196
197ATF_TC_WITH_CLEANUP(msg);
198ATF_TC_HEAD(msg, tc)
199{
200
201	atf_tc_set_md_var(tc, "timeout", "3");
202	atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
203}
204
205ATF_TC_BODY(msg, tc)
206{
207	struct sigaction sa;
208	struct msqid_ds m_ds;
209	struct testmsg m;
210	sigset_t sigmask;
211	int sender_msqid;
212	int loop;
213	int c_status;
214
215	/*
216	 * Install a SIGSYS handler so that we can exit gracefully if
217	 * System V Message Queue support isn't in the kernel.
218	 */
219	did_sigsys = 0;
220	sa.sa_handler = sigsys_handler;
221	sigemptyset(&sa.sa_mask);
222	sa.sa_flags = 0;
223	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
224	    "sigaction SIGSYS: %d", errno);
225
226	/*
227	 * Install a SIGCHLD handler to deal with all possible exit
228	 * conditions of the receiver.
229	 */
230	did_sigchild = 0;
231	child_count = 0;
232	sa.sa_handler = sigchld_handler;
233	sigemptyset(&sa.sa_mask);
234	sa.sa_flags = 0;
235	ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
236	    "sigaction SIGCHLD: %d", errno);
237
238	msgkey = get_ftok(4160);
239	ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed");
240
241	sender_msqid = msgget(msgkey, IPC_CREAT | 0640);
242	ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno);
243	write_int("sender_msqid", sender_msqid);
244
245	if (did_sigsys) {
246		atf_tc_skip("SYSV Message Queue not supported");
247		return;
248	}
249
250	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
251	"msgctl IPC_STAT 1: %d", errno);
252
253	print_msqid_ds(&m_ds, 0640);
254
255	m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600;
256
257	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1,
258	    "msgctl IPC_SET: %d", errno);
259
260	memset(&m_ds, 0, sizeof(m_ds));
261
262	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
263	    "msgctl IPC_STAT 2: %d", errno);
264
265	ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600,
266	    "IPC_SET of mode didn't hold");
267
268	print_msqid_ds(&m_ds, 0600);
269
270	switch ((child_pid = fork())) {
271	case -1:
272		atf_tc_fail("fork: %d", errno);
273		return;
274
275	case 0:
276		child_count++;
277		receiver();
278		break;
279
280	default:
281		break;
282	}
283
284	for (loop = 0; loop < maxloop; loop++) {
285		/*
286		 * Send the first message to the receiver and wait for the ACK.
287		 */
288		m.mtype = MTYPE_1;
289		strlcpy(m.mtext, m1_str, sizeof(m.mtext));
290		ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN,
291		    0) != -1, "sender: msgsnd 1: %d", errno);
292
293		ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
294				       MTYPE_1_ACK, 0) == MESSAGE_TEXT_LEN,
295		    "sender: msgrcv 1 ack: %d", errno);
296
297		print_msqid_ds(&m_ds, 0600);
298
299		/*
300		 * Send the second message to the receiver and wait for the ACK.
301		 */
302		m.mtype = MTYPE_2;
303		strlcpy(m.mtext, m2_str, sizeof(m.mtext));
304		ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 0) != -1,
305		    "sender: msgsnd 2: %d", errno);
306
307		ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
308				       MTYPE_2_ACK, 0) == MESSAGE_TEXT_LEN,
309		    "sender: msgrcv 2 ack: %d", errno);
310	}
311
312	/*
313	 * Wait for child to finish
314	 */
315	sigemptyset(&sigmask);
316	(void) sigsuspend(&sigmask);
317
318	/*
319	 * ...and any other signal is an unexpected error.
320	 */
321	if (did_sigchild) {
322		c_status = child_status;
323		if (c_status < 0)
324			atf_tc_fail("waitpid: %d", -c_status);
325		else if (WIFEXITED(c_status) == 0)
326			atf_tc_fail("child abnormal exit: %d", c_status);
327		else if (WEXITSTATUS(c_status) != 0)
328			atf_tc_fail("c status: %d", WEXITSTATUS(c_status));
329		else {
330			ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds)
331			    != -1, "msgctl IPC_STAT: %d", errno);
332
333			print_msqid_ds(&m_ds, 0600);
334			atf_tc_pass();
335		}
336	} else
337		atf_tc_fail("sender: received unexpected signal");
338}
339
340ATF_TC_CLEANUP(msg, tc)
341{
342	int sender_msqid;
343
344	/*
345	 * Remove the message queue if it exists.
346	 */
347	sender_msqid = read_int("sender_msqid");
348	if (sender_msqid != -1)
349		if (msgctl(sender_msqid, IPC_RMID, NULL) == -1)
350			err(1, "msgctl IPC_RMID");
351}
352
353void
354print_msqid_ds(struct msqid_ds *mp, mode_t mode)
355{
356	uid_t uid = geteuid();
357	gid_t gid = getegid();
358
359	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
360	    mp->msg_perm.uid, mp->msg_perm.gid,
361	    mp->msg_perm.cuid, mp->msg_perm.cgid,
362	    mp->msg_perm.mode & 0777);
363
364	printf("qnum %lu, qbytes %lu, lspid %d, lrpid %d\n",
365	    mp->msg_qnum, (u_long)mp->msg_qbytes, mp->msg_lspid,
366	    mp->msg_lrpid);
367
368	printf("stime: %s", ctime(&mp->msg_stime));
369	printf("rtime: %s", ctime(&mp->msg_rtime));
370	printf("ctime: %s", ctime(&mp->msg_ctime));
371
372	/*
373	 * Sanity check a few things.
374	 */
375
376	ATF_REQUIRE_MSG(mp->msg_perm.uid == uid && mp->msg_perm.cuid == uid,
377	    "uid mismatch");
378
379	ATF_REQUIRE_MSG(mp->msg_perm.gid == gid && mp->msg_perm.cgid == gid,
380	    "gid mismatch");
381
382	ATF_REQUIRE_MSG((mp->msg_perm.mode & 0777) == mode, "mode mismatch");
383}
384
385void
386receiver(void)
387{
388	struct testmsg m;
389	int msqid, loop;
390
391	if ((msqid = msgget(msgkey, 0)) == -1)
392		err(1, "receiver: msgget");
393
394	for (loop = 0; loop < maxloop; loop++) {
395		/*
396		 * Receive the first message, print it, and send an ACK.
397		 */
398		if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_1, 0) != MESSAGE_TEXT_LEN)
399			err(1, "receiver: msgrcv 1");
400
401		printf("%s\n", m.mtext);
402		if (strcmp(m.mtext, m1_str) != 0)
403			err(1, "receiver: message 1 data isn't correct");
404
405		m.mtype = MTYPE_1_ACK;
406
407		if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
408			err(1, "receiver: msgsnd ack 1");
409
410		/*
411		 * Receive the second message, print it, and send an ACK.
412		 */
413
414		if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_2, 0) != MESSAGE_TEXT_LEN)
415			err(1, "receiver: msgrcv 2");
416
417		printf("%s\n", m.mtext);
418		if (strcmp(m.mtext, m2_str) != 0)
419			err(1, "receiver: message 2 data isn't correct");
420
421		m.mtype = MTYPE_2_ACK;
422
423		if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
424			err(1, "receiver: msgsnd ack 2");
425	}
426
427	exit(0);
428}
429
430/*
431 * Test the SVID-compatible Semaphore facility.
432 */
433
434ATF_TC_WITH_CLEANUP(sem);
435ATF_TC_HEAD(sem, tc)
436{
437
438	atf_tc_set_md_var(tc, "timeout", "3");
439	atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
440}
441
442ATF_TC_BODY(sem, tc)
443{
444	struct sigaction sa;
445	union semun sun;
446	struct semid_ds s_ds;
447	sigset_t sigmask;
448	int sender_semid;
449	int i;
450	int c_status;
451
452	/*
453	 * Install a SIGSYS handler so that we can exit gracefully if
454	 * System V Semaphore support isn't in the kernel.
455	 */
456	did_sigsys = 0;
457	sa.sa_handler = sigsys_handler;
458	sigemptyset(&sa.sa_mask);
459	sa.sa_flags = 0;
460	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
461	    "sigaction SIGSYS: %d", errno);
462
463	/*
464	 * Install a SIGCHLD handler to deal with all possible exit
465	 * conditions of the receiver.
466	 */
467	did_sigchild = 0;
468	child_count = 0;
469	sa.sa_handler = sigchld_handler;
470	sigemptyset(&sa.sa_mask);
471	sa.sa_flags = 0;
472	ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
473	    "sigaction SIGCHLD: %d", errno);
474
475	semkey = get_ftok(4160);
476	ATF_REQUIRE_MSG(semkey != (key_t)-1, "get_ftok failed");
477
478	sender_semid = semget(semkey, 1, IPC_CREAT | 0640);
479	ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno);
480	write_int("sender_semid", sender_semid);
481
482	if (did_sigsys) {
483		atf_tc_skip("SYSV Semaphore not supported");
484		return;
485	}
486
487	sun.buf = &s_ds;
488	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
489	    "semctl IPC_STAT: %d", errno);
490
491	print_semid_ds(&s_ds, 0640);
492
493	s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600;
494
495	sun.buf = &s_ds;
496	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1,
497	    "semctl IPC_SET: %d", errno);
498
499	memset(&s_ds, 0, sizeof(s_ds));
500
501	sun.buf = &s_ds;
502	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
503	    "semctl IPC_STAT: %d", errno);
504
505	ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600,
506	    "IPC_SET of mode didn't hold");
507
508	print_semid_ds(&s_ds, 0600);
509
510	for (child_count = 0; child_count < 5; child_count++) {
511		switch ((child_pid = fork())) {
512		case -1:
513			atf_tc_fail("fork: %d", errno);
514			return;
515
516		case 0:
517			waiter();
518			break;
519
520		default:
521			break;
522		}
523	}
524
525	/*
526	 * Wait for all of the waiters to be attempting to acquire the
527	 * semaphore.
528	 */
529	for (;;) {
530		i = semctl(sender_semid, 0, GETNCNT);
531		if (i == -1)
532			atf_tc_fail("semctl GETNCNT: %d", i);
533		if (i == 5)
534			break;
535	}
536
537	/*
538	 * Now set the thundering herd in motion by initializing the
539	 * semaphore to the value 1.
540	 */
541	sun.val = 1;
542	ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1,
543	    "sender: semctl SETVAL to 1: %d", errno);
544
545	/*
546	 * Wait for all children to finish
547	 */
548	sigemptyset(&sigmask);
549	for (;;) {
550		(void) sigsuspend(&sigmask);
551		if (did_sigchild) {
552			c_status = child_status;
553			if (c_status < 0)
554				atf_tc_fail("waitpid: %d", -c_status);
555			else if (WIFEXITED(c_status) == 0)
556				atf_tc_fail("c abnormal exit: %d", c_status);
557			else if (WEXITSTATUS(c_status) != 0)
558				atf_tc_fail("c status: %d",
559				    WEXITSTATUS(c_status));
560			else {
561				sun.buf = &s_ds;
562				ATF_REQUIRE_MSG(semctl(sender_semid, 0,
563						    IPC_STAT, sun) != -1,
564				    "semctl IPC_STAT: %d", errno);
565
566				print_semid_ds(&s_ds, 0600);
567				atf_tc_pass();
568			}
569			if (child_count <= 0)
570				break;
571			did_sigchild = 0;
572		} else {
573			atf_tc_fail("sender: received unexpected signal");
574			break;
575		}
576	}
577}
578
579ATF_TC_CLEANUP(sem, tc)
580{
581	int sender_semid;
582
583	/*
584	 * Remove the semaphore if it exists
585	 */
586	sender_semid = read_int("sender_semid");
587	if (sender_semid != -1)
588		if (semctl(sender_semid, 0, IPC_RMID) == -1)
589			err(1, "semctl IPC_RMID");
590}
591
592void
593print_semid_ds(struct semid_ds *sp, 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
622void
623waiter(void)
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
661ATF_TC_WITH_CLEANUP(shm);
662ATF_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
669ATF_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
778static void
779shmid_cleanup(const char *name)
780{
781	int shmid;
782
783	/*
784	 * Remove the shared memory area if it exists.
785	 */
786	shmid = read_int(name);
787	if (shmid != -1) {
788		if (shmctl(shmid, IPC_RMID, NULL) == -1)
789			err(1, "shmctl IPC_RMID");
790	}
791}
792
793ATF_TC_CLEANUP(shm, tc)
794{
795
796	shmid_cleanup("sender_shmid");
797}
798
799void
800print_shmid_ds(struct shmid_ds *sp, mode_t mode)
801{
802	uid_t uid = geteuid();
803	gid_t gid = getegid();
804
805	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
806	    sp->shm_perm.uid, sp->shm_perm.gid,
807	    sp->shm_perm.cuid, sp->shm_perm.cgid,
808	    sp->shm_perm.mode & 0777);
809
810	printf("segsz %lu, lpid %d, cpid %d, nattch %u\n",
811	    (u_long)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid,
812	    sp->shm_nattch);
813
814	printf("atime: %s", ctime(&sp->shm_atime));
815	printf("dtime: %s", ctime(&sp->shm_dtime));
816	printf("ctime: %s", ctime(&sp->shm_ctime));
817
818	/*
819	 * Sanity check a few things.
820	 */
821
822	ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid,
823	    "uid mismatch");
824
825	ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid,
826	    "gid mismatch");
827
828	ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode, "mode mismatch");
829}
830
831void
832sharer(void)
833{
834	int shmid;
835	void *shm_buf;
836
837	shmid = shmget(shmkey, pgsize, 0);
838	ATF_REQUIRE_MSG(shmid != -1, "receiver: shmget:%d", errno);
839
840	shm_buf = shmat(shmid, NULL, 0);
841	ATF_REQUIRE_MSG(shm_buf != (void *) -1, "receiver: shmat: %d", errno);
842
843	printf("%s\n", (const char *)shm_buf);
844
845	ATF_REQUIRE_MSG(strcmp((const char *)shm_buf, m2_str) == 0,
846	    "receiver: data isn't correct");
847
848	exit(0);
849}
850
851#ifdef SHM_REMAP
852ATF_TC_WITH_CLEANUP(shm_remap);
853ATF_TC_HEAD(shm_remap, tc)
854{
855
856	atf_tc_set_md_var(tc, "descr", "Checks SHM_REMAP");
857}
858
859ATF_TC_BODY(shm_remap, tc)
860{
861	char *shm_buf;
862	int shmid_remap;
863
864	pgsize = sysconf(_SC_PAGESIZE);
865
866	shmkey = get_ftok(4160);
867	ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed");
868
869	ATF_REQUIRE_MSG((shmid_remap = shmget(shmkey, pgsize,
870	    IPC_CREAT | 0640)) != -1, "shmget: %d", errno);
871	write_int("shmid_remap", shmid_remap);
872
873	ATF_REQUIRE_MSG((shm_buf = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
874	    MAP_ANON | MAP_PRIVATE, -1, 0)) != MAP_FAILED, "mmap: %d", errno);
875
876	ATF_REQUIRE_MSG(shmat(shmid_remap, shm_buf, 0) == (void *)-1,
877	    "shmat without MAP_REMAP succeeded");
878	ATF_REQUIRE_MSG(shmat(shmid_remap, shm_buf, SHM_REMAP) == shm_buf,
879	    "shmat(SHM_REMAP): %d", errno);
880}
881
882ATF_TC_CLEANUP(shm_remap, tc)
883{
884
885	shmid_cleanup("shmid_remap");
886}
887#endif	/* SHM_REMAP */
888
889ATF_TP_ADD_TCS(tp)
890{
891
892	ATF_TP_ADD_TC(tp, msg);
893	ATF_TP_ADD_TC(tp, sem);
894	ATF_TP_ADD_TC(tp, shm);
895#ifdef SHM_REMAP
896	ATF_TP_ADD_TC(tp, shm_remap);
897#endif
898
899	return atf_no_error();
900}
901
902