1272343Sngie/*	$NetBSD: t_sysv.c,v 1.4 2014/03/02 20:13:12 jmmv Exp $	*/
2272343Sngie
3272343Sngie/*-
4272343Sngie * Copyright (c) 1999, 2007 The NetBSD Foundation, Inc.
5272343Sngie * All rights reserved.
6272343Sngie *
7272343Sngie * This code is derived from software contributed to The NetBSD Foundation
8272343Sngie * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9272343Sngie * NASA Ames Research Center, and by Andrew Doran.
10272343Sngie *
11272343Sngie * Redistribution and use in source and binary forms, with or without
12272343Sngie * modification, are permitted provided that the following conditions
13272343Sngie * are met:
14272343Sngie * 1. Redistributions of source code must retain the above copyright
15272343Sngie *    notice, this list of conditions and the following disclaimer.
16272343Sngie * 2. Redistributions in binary form must reproduce the above copyright
17272343Sngie *    notice, this list of conditions and the following disclaimer in the
18272343Sngie *    documentation and/or other materials provided with the distribution.
19272343Sngie *
20272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22272343Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23272343Sngie * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24272343Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25272343Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26272343Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28272343Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30272343Sngie * POSSIBILITY OF SUCH DAMAGE.
31272343Sngie */
32272343Sngie
33272343Sngie/*
34272343Sngie * Test the SVID-compatible Message Queue facility.
35272343Sngie */
36272343Sngie
37272343Sngie#include <atf-c.h>
38272343Sngie
39272343Sngie#include <err.h>
40272343Sngie#include <errno.h>
41272343Sngie#include <fcntl.h>
42272343Sngie#include <signal.h>
43272343Sngie#include <stdio.h>
44272343Sngie#include <stdlib.h>
45272343Sngie#include <string.h>
46272343Sngie#include <time.h>
47272343Sngie#include <unistd.h>
48272343Sngie
49272343Sngie#include <sys/ipc.h>
50343426Skib#include <sys/mman.h>
51272343Sngie#include <sys/msg.h>
52272343Sngie#include <sys/param.h>
53272343Sngie#include <sys/sem.h>
54272343Sngie#include <sys/shm.h>
55272343Sngie#include <sys/wait.h>
56272343Sngie
57272343Sngievolatile int did_sigsys, did_sigchild;
58272343Sngievolatile int child_status, child_count;
59272343Sngie
60272343Sngievoid	sigsys_handler(int);
61272343Sngievoid	sigchld_handler(int);
62272343Sngie
63272343Sngiekey_t	get_ftok(int);
64272343Sngie
65272343Sngievoid	print_msqid_ds(struct msqid_ds *, mode_t);
66272343Sngievoid	receiver(void);
67272343Sngie
68272343Sngievoid	print_semid_ds(struct semid_ds *, mode_t);
69272343Sngievoid	waiter(void);
70272343Sngie
71272343Sngievoid	print_shmid_ds(struct shmid_ds *, mode_t);
72272343Sngievoid	sharer(void);
73272343Sngie
74272343Sngie#define	MESSAGE_TEXT_LEN	256
75272343Sngie
76330731Sasomersstruct testmsg {
77272343Sngie	long	mtype;
78272343Sngie	char	mtext[MESSAGE_TEXT_LEN];
79272343Sngie};
80272343Sngie
81272343Sngieconst char *m1_str = "California is overrated.";
82272343Sngieconst char *m2_str = "The quick brown fox jumped over the lazy dog.";
83272343Sngie
84272343Sngiesize_t	pgsize;
85272343Sngie
86272343Sngie#define	MTYPE_1		1
87272343Sngie#define	MTYPE_1_ACK	2
88272343Sngie
89272343Sngie#define	MTYPE_2		3
90272343Sngie#define	MTYPE_2_ACK	4
91272343Sngie
92272343Sngiepid_t	child_pid;
93272343Sngie
94272343Sngiekey_t	msgkey, semkey, shmkey;
95272343Sngie
96272343Sngieint	maxloop = 1;
97272343Sngie
98330731Sasomers#ifndef __FreeBSD__
99272343Sngieunion semun {
100272343Sngie	int	val;		/* value for SETVAL */
101272343Sngie	struct	semid_ds *buf;	/* buffer for IPC_{STAT,SET} */
102272343Sngie	u_short	*array;		/* array for GETALL & SETALL */
103272343Sngie};
104330731Sasomers#endif
105272343Sngie
106272343Sngie
107272343Sngie/* Writes an integer to a file.  To be used from the body of the test
108272343Sngie * cases below to pass any global identifiers to the cleanup routine. */
109272343Sngiestatic void
110272343Sngiewrite_int(const char *path, const int value)
111272343Sngie{
112272343Sngie	int output;
113272343Sngie
114272343Sngie	output = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
115272343Sngie	ATF_REQUIRE_MSG(output != -1, "Failed to create %s", path);
116272343Sngie	write(output, &value, sizeof(value));
117272343Sngie	close(output);
118272343Sngie}
119272343Sngie
120272343Sngie
121272343Sngie/* Reads an integer from a file.  To be used from the cleanup routines
122272343Sngie * of the test cases below. */
123272343Sngiestatic int
124272343Sngieread_int(const char *path)
125272343Sngie{
126272343Sngie	int input;
127272343Sngie
128272343Sngie	input = open(path, O_RDONLY);
129272343Sngie	if (input == -1)
130272343Sngie		return -1;
131272343Sngie	else {
132272343Sngie		int value;
133330731Sasomers		ATF_REQUIRE_EQ(read(input, &value, sizeof(value)), sizeof(value));
134330731Sasomers		close(input);
135272343Sngie		return value;
136272343Sngie	}
137272343Sngie}
138272343Sngie
139272343Sngie
140272343Sngievoid
141272343Sngiesigsys_handler(int signo)
142272343Sngie{
143272343Sngie
144272343Sngie	did_sigsys = 1;
145272343Sngie}
146272343Sngie
147272343Sngievoid
148272343Sngiesigchld_handler(int signo)
149272343Sngie{
150272343Sngie	int c_status;
151272343Sngie
152272343Sngie	did_sigchild = 1;
153272343Sngie	/*
154272343Sngie	 * Reap the child and return its status
155272343Sngie	 */
156272343Sngie	if (wait(&c_status) == -1)
157272343Sngie		child_status = -errno;
158272343Sngie	else
159272343Sngie		child_status = c_status;
160272343Sngie
161272343Sngie	child_count--;
162272343Sngie}
163272343Sngie
164272343Sngiekey_t get_ftok(int id)
165272343Sngie{
166272343Sngie	int fd;
167272343Sngie	char token_key[64], token_dir[64];
168272343Sngie	char *tmpdir;
169272343Sngie	key_t key;
170272343Sngie
171272343Sngie	strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key));
172272343Sngie	tmpdir = mkdtemp(token_key);
173272343Sngie	ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno);
174272343Sngie
175272343Sngie	strlcpy(token_dir, tmpdir, sizeof(token_dir));
176272343Sngie	strlcpy(token_key, tmpdir, sizeof(token_key));
177272343Sngie	strlcat(token_key, "/token_key", sizeof(token_key));
178272343Sngie
179272343Sngie	/* Create the file, since ftok() requires it to exist! */
180272343Sngie
181330731Sasomers	fd = open(token_key, O_RDWR | O_CREAT | O_EXCL, 0600);
182272343Sngie	if (fd == -1) {
183272343Sngie		rmdir(tmpdir);
184272343Sngie		atf_tc_fail("open() of temp file failed: %d", errno);
185272343Sngie		return (key_t)-1;
186272343Sngie	} else
187272343Sngie		close(fd);
188272343Sngie
189272343Sngie	key = ftok(token_key, id);
190272343Sngie
191272343Sngie	ATF_REQUIRE_MSG(unlink(token_key) != -1, "unlink() failed: %d", errno);
192272343Sngie	ATF_REQUIRE_MSG(rmdir(token_dir) != -1, "rmdir() failed: %d", errno);
193272343Sngie
194272343Sngie	return key;
195272343Sngie}
196272343Sngie
197272343SngieATF_TC_WITH_CLEANUP(msg);
198272343SngieATF_TC_HEAD(msg, tc)
199272343Sngie{
200272343Sngie
201272343Sngie	atf_tc_set_md_var(tc, "timeout", "3");
202272343Sngie	atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
203272343Sngie}
204272343Sngie
205272343SngieATF_TC_BODY(msg, tc)
206272343Sngie{
207272343Sngie	struct sigaction sa;
208272343Sngie	struct msqid_ds m_ds;
209330731Sasomers	struct testmsg m;
210272343Sngie	sigset_t sigmask;
211272343Sngie	int sender_msqid;
212272343Sngie	int loop;
213272343Sngie	int c_status;
214272343Sngie
215362658Slwhsu	if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false))
216362658Slwhsu		atf_tc_skip("https://bugs.freebsd.org/233649");
217362658Slwhsu
218272343Sngie	/*
219272343Sngie	 * Install a SIGSYS handler so that we can exit gracefully if
220272343Sngie	 * System V Message Queue support isn't in the kernel.
221272343Sngie	 */
222272343Sngie	did_sigsys = 0;
223272343Sngie	sa.sa_handler = sigsys_handler;
224272343Sngie	sigemptyset(&sa.sa_mask);
225272343Sngie	sa.sa_flags = 0;
226272343Sngie	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
227272343Sngie	    "sigaction SIGSYS: %d", errno);
228272343Sngie
229272343Sngie	/*
230272343Sngie	 * Install a SIGCHLD handler to deal with all possible exit
231272343Sngie	 * conditions of the receiver.
232272343Sngie	 */
233272343Sngie	did_sigchild = 0;
234272343Sngie	child_count = 0;
235272343Sngie	sa.sa_handler = sigchld_handler;
236272343Sngie	sigemptyset(&sa.sa_mask);
237272343Sngie	sa.sa_flags = 0;
238272343Sngie	ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
239272343Sngie	    "sigaction SIGCHLD: %d", errno);
240272343Sngie
241272343Sngie	msgkey = get_ftok(4160);
242272343Sngie	ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed");
243272343Sngie
244272343Sngie	sender_msqid = msgget(msgkey, IPC_CREAT | 0640);
245272343Sngie	ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno);
246272343Sngie	write_int("sender_msqid", sender_msqid);
247272343Sngie
248272343Sngie	if (did_sigsys) {
249272343Sngie		atf_tc_skip("SYSV Message Queue not supported");
250272343Sngie		return;
251272343Sngie	}
252272343Sngie
253272343Sngie	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
254272343Sngie	"msgctl IPC_STAT 1: %d", errno);
255272343Sngie
256272343Sngie	print_msqid_ds(&m_ds, 0640);
257272343Sngie
258272343Sngie	m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600;
259272343Sngie
260272343Sngie	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1,
261272343Sngie	    "msgctl IPC_SET: %d", errno);
262272343Sngie
263272343Sngie	memset(&m_ds, 0, sizeof(m_ds));
264272343Sngie
265272343Sngie	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
266272343Sngie	    "msgctl IPC_STAT 2: %d", errno);
267272343Sngie
268272343Sngie	ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600,
269272343Sngie	    "IPC_SET of mode didn't hold");
270272343Sngie
271272343Sngie	print_msqid_ds(&m_ds, 0600);
272272343Sngie
273272343Sngie	switch ((child_pid = fork())) {
274272343Sngie	case -1:
275272343Sngie		atf_tc_fail("fork: %d", errno);
276272343Sngie		return;
277272343Sngie
278272343Sngie	case 0:
279272343Sngie		child_count++;
280272343Sngie		receiver();
281272343Sngie		break;
282272343Sngie
283272343Sngie	default:
284272343Sngie		break;
285272343Sngie	}
286272343Sngie
287272343Sngie	for (loop = 0; loop < maxloop; loop++) {
288272343Sngie		/*
289272343Sngie		 * Send the first message to the receiver and wait for the ACK.
290272343Sngie		 */
291272343Sngie		m.mtype = MTYPE_1;
292330731Sasomers		strlcpy(m.mtext, m1_str, sizeof(m.mtext));
293272343Sngie		ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN,
294272343Sngie		    0) != -1, "sender: msgsnd 1: %d", errno);
295272343Sngie
296272343Sngie		ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
297272343Sngie				       MTYPE_1_ACK, 0) == MESSAGE_TEXT_LEN,
298272343Sngie		    "sender: msgrcv 1 ack: %d", errno);
299272343Sngie
300272343Sngie		print_msqid_ds(&m_ds, 0600);
301272343Sngie
302272343Sngie		/*
303272343Sngie		 * Send the second message to the receiver and wait for the ACK.
304272343Sngie		 */
305272343Sngie		m.mtype = MTYPE_2;
306330731Sasomers		strlcpy(m.mtext, m2_str, sizeof(m.mtext));
307272343Sngie		ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 0) != -1,
308272343Sngie		    "sender: msgsnd 2: %d", errno);
309272343Sngie
310272343Sngie		ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
311272343Sngie				       MTYPE_2_ACK, 0) == MESSAGE_TEXT_LEN,
312272343Sngie		    "sender: msgrcv 2 ack: %d", errno);
313272343Sngie	}
314272343Sngie
315272343Sngie	/*
316272343Sngie	 * Wait for child to finish
317272343Sngie	 */
318272343Sngie	sigemptyset(&sigmask);
319272343Sngie	(void) sigsuspend(&sigmask);
320272343Sngie
321272343Sngie	/*
322272343Sngie	 * ...and any other signal is an unexpected error.
323272343Sngie	 */
324272343Sngie	if (did_sigchild) {
325272343Sngie		c_status = child_status;
326272343Sngie		if (c_status < 0)
327272343Sngie			atf_tc_fail("waitpid: %d", -c_status);
328272343Sngie		else if (WIFEXITED(c_status) == 0)
329272343Sngie			atf_tc_fail("child abnormal exit: %d", c_status);
330272343Sngie		else if (WEXITSTATUS(c_status) != 0)
331272343Sngie			atf_tc_fail("c status: %d", WEXITSTATUS(c_status));
332272343Sngie		else {
333272343Sngie			ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds)
334272343Sngie			    != -1, "msgctl IPC_STAT: %d", errno);
335272343Sngie
336272343Sngie			print_msqid_ds(&m_ds, 0600);
337272343Sngie			atf_tc_pass();
338272343Sngie		}
339272343Sngie	} else
340272343Sngie		atf_tc_fail("sender: received unexpected signal");
341272343Sngie}
342272343Sngie
343272343SngieATF_TC_CLEANUP(msg, tc)
344272343Sngie{
345272343Sngie	int sender_msqid;
346272343Sngie
347272343Sngie	/*
348272343Sngie	 * Remove the message queue if it exists.
349272343Sngie	 */
350272343Sngie	sender_msqid = read_int("sender_msqid");
351272343Sngie	if (sender_msqid != -1)
352272343Sngie		if (msgctl(sender_msqid, IPC_RMID, NULL) == -1)
353272343Sngie			err(1, "msgctl IPC_RMID");
354272343Sngie}
355272343Sngie
356272343Sngievoid
357330731Sasomersprint_msqid_ds(struct msqid_ds *mp, mode_t mode)
358272343Sngie{
359272343Sngie	uid_t uid = geteuid();
360272343Sngie	gid_t gid = getegid();
361272343Sngie
362272343Sngie	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
363272343Sngie	    mp->msg_perm.uid, mp->msg_perm.gid,
364272343Sngie	    mp->msg_perm.cuid, mp->msg_perm.cgid,
365272343Sngie	    mp->msg_perm.mode & 0777);
366272343Sngie
367272343Sngie	printf("qnum %lu, qbytes %lu, lspid %d, lrpid %d\n",
368272343Sngie	    mp->msg_qnum, (u_long)mp->msg_qbytes, mp->msg_lspid,
369272343Sngie	    mp->msg_lrpid);
370272343Sngie
371272343Sngie	printf("stime: %s", ctime(&mp->msg_stime));
372272343Sngie	printf("rtime: %s", ctime(&mp->msg_rtime));
373272343Sngie	printf("ctime: %s", ctime(&mp->msg_ctime));
374272343Sngie
375272343Sngie	/*
376272343Sngie	 * Sanity check a few things.
377272343Sngie	 */
378272343Sngie
379272343Sngie	ATF_REQUIRE_MSG(mp->msg_perm.uid == uid && mp->msg_perm.cuid == uid,
380272343Sngie	    "uid mismatch");
381272343Sngie
382272343Sngie	ATF_REQUIRE_MSG(mp->msg_perm.gid == gid && mp->msg_perm.cgid == gid,
383272343Sngie	    "gid mismatch");
384272343Sngie
385272343Sngie	ATF_REQUIRE_MSG((mp->msg_perm.mode & 0777) == mode, "mode mismatch");
386272343Sngie}
387272343Sngie
388272343Sngievoid
389330731Sasomersreceiver(void)
390272343Sngie{
391330731Sasomers	struct testmsg m;
392272343Sngie	int msqid, loop;
393272343Sngie
394272343Sngie	if ((msqid = msgget(msgkey, 0)) == -1)
395272343Sngie		err(1, "receiver: msgget");
396272343Sngie
397272343Sngie	for (loop = 0; loop < maxloop; loop++) {
398272343Sngie		/*
399272343Sngie		 * Receive the first message, print it, and send an ACK.
400272343Sngie		 */
401272343Sngie		if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_1, 0) != MESSAGE_TEXT_LEN)
402272343Sngie			err(1, "receiver: msgrcv 1");
403272343Sngie
404272343Sngie		printf("%s\n", m.mtext);
405272343Sngie		if (strcmp(m.mtext, m1_str) != 0)
406272343Sngie			err(1, "receiver: message 1 data isn't correct");
407272343Sngie
408272343Sngie		m.mtype = MTYPE_1_ACK;
409272343Sngie
410272343Sngie		if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
411272343Sngie			err(1, "receiver: msgsnd ack 1");
412272343Sngie
413272343Sngie		/*
414272343Sngie		 * Receive the second message, print it, and send an ACK.
415272343Sngie		 */
416272343Sngie
417272343Sngie		if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_2, 0) != MESSAGE_TEXT_LEN)
418272343Sngie			err(1, "receiver: msgrcv 2");
419272343Sngie
420272343Sngie		printf("%s\n", m.mtext);
421272343Sngie		if (strcmp(m.mtext, m2_str) != 0)
422272343Sngie			err(1, "receiver: message 2 data isn't correct");
423272343Sngie
424272343Sngie		m.mtype = MTYPE_2_ACK;
425272343Sngie
426272343Sngie		if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
427272343Sngie			err(1, "receiver: msgsnd ack 2");
428272343Sngie	}
429272343Sngie
430272343Sngie	exit(0);
431272343Sngie}
432272343Sngie
433272343Sngie/*
434272343Sngie * Test the SVID-compatible Semaphore facility.
435272343Sngie */
436272343Sngie
437272343SngieATF_TC_WITH_CLEANUP(sem);
438272343SngieATF_TC_HEAD(sem, tc)
439272343Sngie{
440272343Sngie
441272343Sngie	atf_tc_set_md_var(tc, "timeout", "3");
442272343Sngie	atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
443272343Sngie}
444272343Sngie
445272343SngieATF_TC_BODY(sem, tc)
446272343Sngie{
447272343Sngie	struct sigaction sa;
448272343Sngie	union semun sun;
449272343Sngie	struct semid_ds s_ds;
450272343Sngie	sigset_t sigmask;
451272343Sngie	int sender_semid;
452272343Sngie	int i;
453272343Sngie	int c_status;
454272343Sngie
455272343Sngie	/*
456272343Sngie	 * Install a SIGSYS handler so that we can exit gracefully if
457272343Sngie	 * System V Semaphore support isn't in the kernel.
458272343Sngie	 */
459272343Sngie	did_sigsys = 0;
460272343Sngie	sa.sa_handler = sigsys_handler;
461272343Sngie	sigemptyset(&sa.sa_mask);
462272343Sngie	sa.sa_flags = 0;
463272343Sngie	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
464272343Sngie	    "sigaction SIGSYS: %d", errno);
465272343Sngie
466272343Sngie	/*
467272343Sngie	 * Install a SIGCHLD handler to deal with all possible exit
468272343Sngie	 * conditions of the receiver.
469272343Sngie	 */
470272343Sngie	did_sigchild = 0;
471272343Sngie	child_count = 0;
472272343Sngie	sa.sa_handler = sigchld_handler;
473272343Sngie	sigemptyset(&sa.sa_mask);
474272343Sngie	sa.sa_flags = 0;
475272343Sngie	ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
476272343Sngie	    "sigaction SIGCHLD: %d", errno);
477272343Sngie
478272343Sngie	semkey = get_ftok(4160);
479272343Sngie	ATF_REQUIRE_MSG(semkey != (key_t)-1, "get_ftok failed");
480272343Sngie
481272343Sngie	sender_semid = semget(semkey, 1, IPC_CREAT | 0640);
482272343Sngie	ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno);
483272343Sngie	write_int("sender_semid", sender_semid);
484272343Sngie
485272343Sngie	if (did_sigsys) {
486272343Sngie		atf_tc_skip("SYSV Semaphore not supported");
487272343Sngie		return;
488272343Sngie	}
489272343Sngie
490272343Sngie	sun.buf = &s_ds;
491272343Sngie	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
492272343Sngie	    "semctl IPC_STAT: %d", errno);
493272343Sngie
494272343Sngie	print_semid_ds(&s_ds, 0640);
495272343Sngie
496272343Sngie	s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600;
497272343Sngie
498272343Sngie	sun.buf = &s_ds;
499272343Sngie	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1,
500272343Sngie	    "semctl IPC_SET: %d", errno);
501272343Sngie
502272343Sngie	memset(&s_ds, 0, sizeof(s_ds));
503272343Sngie
504272343Sngie	sun.buf = &s_ds;
505272343Sngie	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
506272343Sngie	    "semctl IPC_STAT: %d", errno);
507272343Sngie
508272343Sngie	ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600,
509272343Sngie	    "IPC_SET of mode didn't hold");
510272343Sngie
511272343Sngie	print_semid_ds(&s_ds, 0600);
512272343Sngie
513272343Sngie	for (child_count = 0; child_count < 5; child_count++) {
514272343Sngie		switch ((child_pid = fork())) {
515272343Sngie		case -1:
516272343Sngie			atf_tc_fail("fork: %d", errno);
517272343Sngie			return;
518272343Sngie
519272343Sngie		case 0:
520272343Sngie			waiter();
521272343Sngie			break;
522272343Sngie
523272343Sngie		default:
524272343Sngie			break;
525272343Sngie		}
526272343Sngie	}
527272343Sngie
528272343Sngie	/*
529272343Sngie	 * Wait for all of the waiters to be attempting to acquire the
530272343Sngie	 * semaphore.
531272343Sngie	 */
532272343Sngie	for (;;) {
533272343Sngie		i = semctl(sender_semid, 0, GETNCNT);
534272343Sngie		if (i == -1)
535272343Sngie			atf_tc_fail("semctl GETNCNT: %d", i);
536272343Sngie		if (i == 5)
537272343Sngie			break;
538272343Sngie	}
539272343Sngie
540272343Sngie	/*
541272343Sngie	 * Now set the thundering herd in motion by initializing the
542272343Sngie	 * semaphore to the value 1.
543272343Sngie	 */
544272343Sngie	sun.val = 1;
545272343Sngie	ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1,
546272343Sngie	    "sender: semctl SETVAL to 1: %d", errno);
547272343Sngie
548272343Sngie	/*
549272343Sngie	 * Wait for all children to finish
550272343Sngie	 */
551272343Sngie	sigemptyset(&sigmask);
552272343Sngie	for (;;) {
553272343Sngie		(void) sigsuspend(&sigmask);
554272343Sngie		if (did_sigchild) {
555272343Sngie			c_status = child_status;
556272343Sngie			if (c_status < 0)
557272343Sngie				atf_tc_fail("waitpid: %d", -c_status);
558272343Sngie			else if (WIFEXITED(c_status) == 0)
559272343Sngie				atf_tc_fail("c abnormal exit: %d", c_status);
560272343Sngie			else if (WEXITSTATUS(c_status) != 0)
561272343Sngie				atf_tc_fail("c status: %d",
562272343Sngie				    WEXITSTATUS(c_status));
563272343Sngie			else {
564272343Sngie				sun.buf = &s_ds;
565272343Sngie				ATF_REQUIRE_MSG(semctl(sender_semid, 0,
566272343Sngie						    IPC_STAT, sun) != -1,
567272343Sngie				    "semctl IPC_STAT: %d", errno);
568272343Sngie
569272343Sngie				print_semid_ds(&s_ds, 0600);
570272343Sngie				atf_tc_pass();
571272343Sngie			}
572272343Sngie			if (child_count <= 0)
573272343Sngie				break;
574272343Sngie			did_sigchild = 0;
575272343Sngie		} else {
576272343Sngie			atf_tc_fail("sender: received unexpected signal");
577272343Sngie			break;
578272343Sngie		}
579272343Sngie	}
580272343Sngie}
581272343Sngie
582272343SngieATF_TC_CLEANUP(sem, tc)
583272343Sngie{
584272343Sngie	int sender_semid;
585272343Sngie
586272343Sngie	/*
587272343Sngie	 * Remove the semaphore if it exists
588272343Sngie	 */
589272343Sngie	sender_semid = read_int("sender_semid");
590272343Sngie	if (sender_semid != -1)
591272343Sngie		if (semctl(sender_semid, 0, IPC_RMID) == -1)
592272343Sngie			err(1, "semctl IPC_RMID");
593272343Sngie}
594272343Sngie
595272343Sngievoid
596330731Sasomersprint_semid_ds(struct semid_ds *sp, mode_t mode)
597272343Sngie{
598272343Sngie	uid_t uid = geteuid();
599272343Sngie	gid_t gid = getegid();
600272343Sngie
601272343Sngie	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
602272343Sngie	    sp->sem_perm.uid, sp->sem_perm.gid,
603272343Sngie	    sp->sem_perm.cuid, sp->sem_perm.cgid,
604272343Sngie	    sp->sem_perm.mode & 0777);
605272343Sngie
606272343Sngie	printf("nsems %u\n", sp->sem_nsems);
607272343Sngie
608272343Sngie	printf("otime: %s", ctime(&sp->sem_otime));
609272343Sngie	printf("ctime: %s", ctime(&sp->sem_ctime));
610272343Sngie
611272343Sngie	/*
612272343Sngie	 * Sanity check a few things.
613272343Sngie	 */
614272343Sngie
615272343Sngie	ATF_REQUIRE_MSG(sp->sem_perm.uid == uid && sp->sem_perm.cuid == uid,
616272343Sngie	    "uid mismatch");
617272343Sngie
618272343Sngie	ATF_REQUIRE_MSG(sp->sem_perm.gid == gid && sp->sem_perm.cgid == gid,
619272343Sngie	    "gid mismatch");
620272343Sngie
621272343Sngie	ATF_REQUIRE_MSG((sp->sem_perm.mode & 0777) == mode,
622272343Sngie	    "mode mismatch %o != %o", (sp->sem_perm.mode & 0777), mode);
623272343Sngie}
624272343Sngie
625272343Sngievoid
626330731Sasomerswaiter(void)
627272343Sngie{
628272343Sngie	struct sembuf s;
629272343Sngie	int semid;
630272343Sngie
631272343Sngie	if ((semid = semget(semkey, 1, 0)) == -1)
632272343Sngie		err(1, "waiter: semget");
633272343Sngie
634272343Sngie	/*
635272343Sngie	 * Attempt to acquire the semaphore.
636272343Sngie	 */
637272343Sngie	s.sem_num = 0;
638272343Sngie	s.sem_op = -1;
639272343Sngie	s.sem_flg = SEM_UNDO;
640272343Sngie
641272343Sngie	if (semop(semid, &s, 1) == -1)
642272343Sngie		err(1, "waiter: semop -1");
643272343Sngie
644272343Sngie	printf("WOO!  GOT THE SEMAPHORE!\n");
645272343Sngie	sleep(1);
646272343Sngie
647272343Sngie	/*
648272343Sngie	 * Release the semaphore and exit.
649272343Sngie	 */
650272343Sngie	s.sem_num = 0;
651272343Sngie	s.sem_op = 1;
652272343Sngie	s.sem_flg = SEM_UNDO;
653272343Sngie
654272343Sngie	if (semop(semid, &s, 1) == -1)
655272343Sngie		err(1, "waiter: semop +1");
656272343Sngie
657272343Sngie	exit(0);
658272343Sngie}
659272343Sngie
660272343Sngie/*
661272343Sngie * Test the SVID-compatible Shared Memory facility.
662272343Sngie */
663272343Sngie
664272343SngieATF_TC_WITH_CLEANUP(shm);
665272343SngieATF_TC_HEAD(shm, tc)
666272343Sngie{
667272343Sngie
668272343Sngie	atf_tc_set_md_var(tc, "timeout", "3");
669272343Sngie	atf_tc_set_md_var(tc, "descr", "Checks sysv shared memory");
670272343Sngie}
671272343Sngie
672272343SngieATF_TC_BODY(shm, tc)
673272343Sngie{
674272343Sngie	struct sigaction sa;
675272343Sngie	struct shmid_ds s_ds;
676272343Sngie	sigset_t sigmask;
677272343Sngie	char *shm_buf;
678272343Sngie	int sender_shmid;
679272343Sngie	int c_status;
680272343Sngie
681272343Sngie	/*
682272343Sngie	 * Install a SIGSYS handler so that we can exit gracefully if
683272343Sngie	 * System V Shared Memory support isn't in the kernel.
684272343Sngie	 */
685272343Sngie	did_sigsys = 0;
686272343Sngie	sa.sa_handler = sigsys_handler;
687272343Sngie	sigemptyset(&sa.sa_mask);
688272343Sngie	sa.sa_flags = 0;
689272343Sngie	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
690272343Sngie	    "sigaction SIGSYS: %d", errno);
691272343Sngie
692272343Sngie	/*
693272343Sngie	 * Install a SIGCHLD handler to deal with all possible exit
694272343Sngie	 * conditions of the sharer.
695272343Sngie	 */
696272343Sngie	did_sigchild = 0;
697272343Sngie	child_count = 0;
698272343Sngie	sa.sa_handler = sigchld_handler;
699272343Sngie	sigemptyset(&sa.sa_mask);
700272343Sngie	sa.sa_flags = 0;
701272343Sngie	ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
702272343Sngie	    "sigaction SIGCHLD: %d", errno);
703272343Sngie
704272343Sngie	pgsize = sysconf(_SC_PAGESIZE);
705272343Sngie
706272343Sngie	shmkey = get_ftok(4160);
707272343Sngie	ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed");
708272343Sngie
709272343Sngie	ATF_REQUIRE_MSG((sender_shmid = shmget(shmkey, pgsize,
710272343Sngie					       IPC_CREAT | 0640)) != -1,
711272343Sngie	    "shmget: %d", errno);
712272343Sngie	write_int("sender_shmid", sender_shmid);
713272343Sngie
714272343Sngie	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
715272343Sngie	    "shmctl IPC_STAT: %d", errno);
716272343Sngie
717272343Sngie	print_shmid_ds(&s_ds, 0640);
718272343Sngie
719272343Sngie	s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600;
720272343Sngie
721272343Sngie	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_SET, &s_ds) != -1,
722272343Sngie	    "shmctl IPC_SET: %d", errno);
723272343Sngie
724272343Sngie	memset(&s_ds, 0, sizeof(s_ds));
725272343Sngie
726272343Sngie	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
727272343Sngie	    "shmctl IPC_STAT: %d", errno);
728272343Sngie
729272343Sngie	ATF_REQUIRE_MSG((s_ds.shm_perm.mode & 0777) == 0600,
730272343Sngie	    "IPC_SET of mode didn't hold");
731272343Sngie
732272343Sngie	print_shmid_ds(&s_ds, 0600);
733272343Sngie
734272343Sngie	shm_buf = shmat(sender_shmid, NULL, 0);
735272343Sngie	ATF_REQUIRE_MSG(shm_buf != (void *) -1, "sender: shmat: %d", errno);
736272343Sngie
737272343Sngie	/*
738272343Sngie	 * Write the test pattern into the shared memory buffer.
739272343Sngie	 */
740272343Sngie	strcpy(shm_buf, m2_str);
741272343Sngie
742272343Sngie	switch ((child_pid = fork())) {
743272343Sngie	case -1:
744272343Sngie		atf_tc_fail("fork: %d", errno);
745272343Sngie		return;
746272343Sngie
747272343Sngie	case 0:
748272343Sngie		sharer();
749272343Sngie		break;
750272343Sngie
751272343Sngie	default:
752272343Sngie		break;
753272343Sngie	}
754272343Sngie
755272343Sngie	/*
756272343Sngie	 * Wait for child to finish
757272343Sngie	 */
758272343Sngie	sigemptyset(&sigmask);
759272343Sngie	(void) sigsuspend(&sigmask);
760272343Sngie
761272343Sngie	if (did_sigchild) {
762272343Sngie		c_status = child_status;
763272343Sngie		if (c_status < 0)
764272343Sngie			atf_tc_fail("waitpid: %d", -c_status);
765272343Sngie		else if (WIFEXITED(c_status) == 0)
766272343Sngie			atf_tc_fail("c abnormal exit: %d", c_status);
767272343Sngie		else if (WEXITSTATUS(c_status) != 0)
768272343Sngie			atf_tc_fail("c status: %d", WEXITSTATUS(c_status));
769272343Sngie		else {
770272343Sngie			ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT,
771272343Sngie					       &s_ds) != -1,
772272343Sngie			    "shmctl IPC_STAT: %d", errno);
773272343Sngie
774272343Sngie			print_shmid_ds(&s_ds, 0600);
775272343Sngie			atf_tc_pass();
776272343Sngie		}
777272343Sngie	} else
778272343Sngie		atf_tc_fail("sender: received unexpected signal");
779272343Sngie}
780272343Sngie
781343426Skibstatic void
782343426Skibshmid_cleanup(const char *name)
783272343Sngie{
784343426Skib	int shmid;
785272343Sngie
786272343Sngie	/*
787272343Sngie	 * Remove the shared memory area if it exists.
788272343Sngie	 */
789343426Skib	shmid = read_int(name);
790343426Skib	if (shmid != -1) {
791343426Skib		if (shmctl(shmid, IPC_RMID, NULL) == -1)
792272343Sngie			err(1, "shmctl IPC_RMID");
793343426Skib	}
794272343Sngie}
795272343Sngie
796343426SkibATF_TC_CLEANUP(shm, tc)
797343426Skib{
798343426Skib
799343426Skib	shmid_cleanup("sender_shmid");
800343426Skib}
801343426Skib
802272343Sngievoid
803330731Sasomersprint_shmid_ds(struct shmid_ds *sp, mode_t mode)
804272343Sngie{
805272343Sngie	uid_t uid = geteuid();
806272343Sngie	gid_t gid = getegid();
807272343Sngie
808272343Sngie	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
809272343Sngie	    sp->shm_perm.uid, sp->shm_perm.gid,
810272343Sngie	    sp->shm_perm.cuid, sp->shm_perm.cgid,
811272343Sngie	    sp->shm_perm.mode & 0777);
812272343Sngie
813272343Sngie	printf("segsz %lu, lpid %d, cpid %d, nattch %u\n",
814272343Sngie	    (u_long)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid,
815272343Sngie	    sp->shm_nattch);
816272343Sngie
817272343Sngie	printf("atime: %s", ctime(&sp->shm_atime));
818272343Sngie	printf("dtime: %s", ctime(&sp->shm_dtime));
819272343Sngie	printf("ctime: %s", ctime(&sp->shm_ctime));
820272343Sngie
821272343Sngie	/*
822272343Sngie	 * Sanity check a few things.
823272343Sngie	 */
824272343Sngie
825272343Sngie	ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid,
826272343Sngie	    "uid mismatch");
827272343Sngie
828272343Sngie	ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid,
829272343Sngie	    "gid mismatch");
830272343Sngie
831272343Sngie	ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode, "mode mismatch");
832272343Sngie}
833272343Sngie
834272343Sngievoid
835330731Sasomerssharer(void)
836272343Sngie{
837272343Sngie	int shmid;
838272343Sngie	void *shm_buf;
839272343Sngie
840272343Sngie	shmid = shmget(shmkey, pgsize, 0);
841272343Sngie	ATF_REQUIRE_MSG(shmid != -1, "receiver: shmget:%d", errno);
842272343Sngie
843272343Sngie	shm_buf = shmat(shmid, NULL, 0);
844272343Sngie	ATF_REQUIRE_MSG(shm_buf != (void *) -1, "receiver: shmat: %d", errno);
845272343Sngie
846272343Sngie	printf("%s\n", (const char *)shm_buf);
847272343Sngie
848272343Sngie	ATF_REQUIRE_MSG(strcmp((const char *)shm_buf, m2_str) == 0,
849272343Sngie	    "receiver: data isn't correct");
850272343Sngie
851272343Sngie	exit(0);
852272343Sngie}
853272343Sngie
854343426Skib#ifdef SHM_REMAP
855343426SkibATF_TC_WITH_CLEANUP(shm_remap);
856343426SkibATF_TC_HEAD(shm_remap, tc)
857343426Skib{
858343426Skib
859343426Skib	atf_tc_set_md_var(tc, "descr", "Checks SHM_REMAP");
860343426Skib}
861343426Skib
862343426SkibATF_TC_BODY(shm_remap, tc)
863343426Skib{
864343426Skib	char *shm_buf;
865343426Skib	int shmid_remap;
866343426Skib
867343426Skib	pgsize = sysconf(_SC_PAGESIZE);
868343426Skib
869343426Skib	shmkey = get_ftok(4160);
870343426Skib	ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed");
871343426Skib
872343426Skib	ATF_REQUIRE_MSG((shmid_remap = shmget(shmkey, pgsize,
873343426Skib	    IPC_CREAT | 0640)) != -1, "shmget: %d", errno);
874343426Skib	write_int("shmid_remap", shmid_remap);
875343426Skib
876343426Skib	ATF_REQUIRE_MSG((shm_buf = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
877343426Skib	    MAP_ANON | MAP_PRIVATE, -1, 0)) != MAP_FAILED, "mmap: %d", errno);
878343426Skib
879343426Skib	ATF_REQUIRE_MSG(shmat(shmid_remap, shm_buf, 0) == (void *)-1,
880343426Skib	    "shmat without MAP_REMAP succeeded");
881343426Skib	ATF_REQUIRE_MSG(shmat(shmid_remap, shm_buf, SHM_REMAP) == shm_buf,
882343426Skib	    "shmat(SHM_REMAP): %d", errno);
883343426Skib}
884343426Skib
885343426SkibATF_TC_CLEANUP(shm_remap, tc)
886343426Skib{
887343426Skib
888343426Skib	shmid_cleanup("shmid_remap");
889343426Skib}
890343426Skib#endif	/* SHM_REMAP */
891343426Skib
892272343SngieATF_TP_ADD_TCS(tp)
893272343Sngie{
894272343Sngie
895343357Skib	ATF_TP_ADD_TC(tp, msg);
896343357Skib	ATF_TP_ADD_TC(tp, sem);
897343357Skib	ATF_TP_ADD_TC(tp, shm);
898343426Skib#ifdef SHM_REMAP
899343426Skib	ATF_TP_ADD_TC(tp, shm_remap);
900343426Skib#endif
901272343Sngie
902272343Sngie	return atf_no_error();
903272343Sngie}
904272343Sngie
905