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>
50272343Sngie#include <sys/msg.h>
51272343Sngie#include <sys/param.h>
52272343Sngie#include <sys/sem.h>
53272343Sngie#include <sys/shm.h>
54272343Sngie#include <sys/wait.h>
55272343Sngie
56272343Sngievolatile int did_sigsys, did_sigchild;
57272343Sngievolatile int child_status, child_count;
58272343Sngie
59272343Sngievoid	sigsys_handler(int);
60272343Sngievoid	sigchld_handler(int);
61272343Sngie
62272343Sngiekey_t	get_ftok(int);
63272343Sngie
64272343Sngievoid	print_msqid_ds(struct msqid_ds *, mode_t);
65272343Sngievoid	receiver(void);
66272343Sngie
67272343Sngievoid	print_semid_ds(struct semid_ds *, mode_t);
68272343Sngievoid	waiter(void);
69272343Sngie
70272343Sngievoid	print_shmid_ds(struct shmid_ds *, mode_t);
71272343Sngievoid	sharer(void);
72272343Sngie
73272343Sngie#define	MESSAGE_TEXT_LEN	256
74272343Sngie
75272343Sngiestruct mymsg {
76272343Sngie	long	mtype;
77272343Sngie	char	mtext[MESSAGE_TEXT_LEN];
78272343Sngie};
79272343Sngie
80272343Sngieconst char *m1_str = "California is overrated.";
81272343Sngieconst char *m2_str = "The quick brown fox jumped over the lazy dog.";
82272343Sngie
83272343Sngiesize_t	pgsize;
84272343Sngie
85272343Sngie#define	MTYPE_1		1
86272343Sngie#define	MTYPE_1_ACK	2
87272343Sngie
88272343Sngie#define	MTYPE_2		3
89272343Sngie#define	MTYPE_2_ACK	4
90272343Sngie
91272343Sngiepid_t	child_pid;
92272343Sngie
93272343Sngiekey_t	msgkey, semkey, shmkey;
94272343Sngie
95272343Sngieint	maxloop = 1;
96272343Sngie
97272343Sngieunion semun {
98272343Sngie	int	val;		/* value for SETVAL */
99272343Sngie	struct	semid_ds *buf;	/* buffer for IPC_{STAT,SET} */
100272343Sngie	u_short	*array;		/* array for GETALL & SETALL */
101272343Sngie};
102272343Sngie
103272343Sngie
104272343Sngie/* Writes an integer to a file.  To be used from the body of the test
105272343Sngie * cases below to pass any global identifiers to the cleanup routine. */
106272343Sngiestatic void
107272343Sngiewrite_int(const char *path, const int value)
108272343Sngie{
109272343Sngie	int output;
110272343Sngie
111272343Sngie	output = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
112272343Sngie	ATF_REQUIRE_MSG(output != -1, "Failed to create %s", path);
113272343Sngie	write(output, &value, sizeof(value));
114272343Sngie	close(output);
115272343Sngie}
116272343Sngie
117272343Sngie
118272343Sngie/* Reads an integer from a file.  To be used from the cleanup routines
119272343Sngie * of the test cases below. */
120272343Sngiestatic int
121272343Sngieread_int(const char *path)
122272343Sngie{
123272343Sngie	int input;
124272343Sngie
125272343Sngie	input = open(path, O_RDONLY);
126272343Sngie	if (input == -1)
127272343Sngie		return -1;
128272343Sngie	else {
129272343Sngie		int value;
130272343Sngie		read(input, &value, sizeof(value));
131272343Sngie		return value;
132272343Sngie	}
133272343Sngie}
134272343Sngie
135272343Sngie
136272343Sngievoid
137272343Sngiesigsys_handler(int signo)
138272343Sngie{
139272343Sngie
140272343Sngie	did_sigsys = 1;
141272343Sngie}
142272343Sngie
143272343Sngievoid
144272343Sngiesigchld_handler(int signo)
145272343Sngie{
146272343Sngie	int c_status;
147272343Sngie
148272343Sngie	did_sigchild = 1;
149272343Sngie	/*
150272343Sngie	 * Reap the child and return its status
151272343Sngie	 */
152272343Sngie	if (wait(&c_status) == -1)
153272343Sngie		child_status = -errno;
154272343Sngie	else
155272343Sngie		child_status = c_status;
156272343Sngie
157272343Sngie	child_count--;
158272343Sngie}
159272343Sngie
160272343Sngiekey_t get_ftok(int id)
161272343Sngie{
162272343Sngie	int fd;
163272343Sngie	char token_key[64], token_dir[64];
164272343Sngie	char *tmpdir;
165272343Sngie	key_t key;
166272343Sngie
167272343Sngie	strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key));
168272343Sngie	tmpdir = mkdtemp(token_key);
169272343Sngie	ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno);
170272343Sngie
171272343Sngie	strlcpy(token_dir, tmpdir, sizeof(token_dir));
172272343Sngie	strlcpy(token_key, tmpdir, sizeof(token_key));
173272343Sngie	strlcat(token_key, "/token_key", sizeof(token_key));
174272343Sngie
175272343Sngie	/* Create the file, since ftok() requires it to exist! */
176272343Sngie
177272343Sngie	fd = open(token_key, O_RDWR | O_CREAT | O_EXCL);
178272343Sngie	if (fd == -1) {
179272343Sngie		rmdir(tmpdir);
180272343Sngie		atf_tc_fail("open() of temp file failed: %d", errno);
181272343Sngie		return (key_t)-1;
182272343Sngie	} else
183272343Sngie		close(fd);
184272343Sngie
185272343Sngie	key = ftok(token_key, id);
186272343Sngie
187272343Sngie	ATF_REQUIRE_MSG(unlink(token_key) != -1, "unlink() failed: %d", errno);
188272343Sngie	ATF_REQUIRE_MSG(rmdir(token_dir) != -1, "rmdir() failed: %d", errno);
189272343Sngie
190272343Sngie	return key;
191272343Sngie}
192272343Sngie
193272343SngieATF_TC_WITH_CLEANUP(msg);
194272343SngieATF_TC_HEAD(msg, tc)
195272343Sngie{
196272343Sngie
197272343Sngie	atf_tc_set_md_var(tc, "timeout", "3");
198272343Sngie	atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
199272343Sngie}
200272343Sngie
201272343SngieATF_TC_BODY(msg, tc)
202272343Sngie{
203272343Sngie	struct sigaction sa;
204272343Sngie	struct msqid_ds m_ds;
205272343Sngie	struct mymsg m;
206272343Sngie	sigset_t sigmask;
207272343Sngie	int sender_msqid;
208272343Sngie	int loop;
209272343Sngie	int c_status;
210272343Sngie
211272343Sngie	/*
212272343Sngie	 * Install a SIGSYS handler so that we can exit gracefully if
213272343Sngie	 * System V Message Queue support isn't in the kernel.
214272343Sngie	 */
215272343Sngie	did_sigsys = 0;
216272343Sngie	sa.sa_handler = sigsys_handler;
217272343Sngie	sigemptyset(&sa.sa_mask);
218272343Sngie	sa.sa_flags = 0;
219272343Sngie	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
220272343Sngie	    "sigaction SIGSYS: %d", errno);
221272343Sngie
222272343Sngie	/*
223272343Sngie	 * Install a SIGCHLD handler to deal with all possible exit
224272343Sngie	 * conditions of the receiver.
225272343Sngie	 */
226272343Sngie	did_sigchild = 0;
227272343Sngie	child_count = 0;
228272343Sngie	sa.sa_handler = sigchld_handler;
229272343Sngie	sigemptyset(&sa.sa_mask);
230272343Sngie	sa.sa_flags = 0;
231272343Sngie	ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
232272343Sngie	    "sigaction SIGCHLD: %d", errno);
233272343Sngie
234272343Sngie	msgkey = get_ftok(4160);
235272343Sngie	ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed");
236272343Sngie
237272343Sngie	sender_msqid = msgget(msgkey, IPC_CREAT | 0640);
238272343Sngie	ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno);
239272343Sngie	write_int("sender_msqid", sender_msqid);
240272343Sngie
241272343Sngie	if (did_sigsys) {
242272343Sngie		atf_tc_skip("SYSV Message Queue not supported");
243272343Sngie		return;
244272343Sngie	}
245272343Sngie
246272343Sngie	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
247272343Sngie	"msgctl IPC_STAT 1: %d", errno);
248272343Sngie
249272343Sngie	print_msqid_ds(&m_ds, 0640);
250272343Sngie
251272343Sngie	m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600;
252272343Sngie
253272343Sngie	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1,
254272343Sngie	    "msgctl IPC_SET: %d", errno);
255272343Sngie
256272343Sngie	memset(&m_ds, 0, sizeof(m_ds));
257272343Sngie
258272343Sngie	ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
259272343Sngie	    "msgctl IPC_STAT 2: %d", errno);
260272343Sngie
261272343Sngie	ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600,
262272343Sngie	    "IPC_SET of mode didn't hold");
263272343Sngie
264272343Sngie	print_msqid_ds(&m_ds, 0600);
265272343Sngie
266272343Sngie	switch ((child_pid = fork())) {
267272343Sngie	case -1:
268272343Sngie		atf_tc_fail("fork: %d", errno);
269272343Sngie		return;
270272343Sngie
271272343Sngie	case 0:
272272343Sngie		child_count++;
273272343Sngie		receiver();
274272343Sngie		break;
275272343Sngie
276272343Sngie	default:
277272343Sngie		break;
278272343Sngie	}
279272343Sngie
280272343Sngie	for (loop = 0; loop < maxloop; loop++) {
281272343Sngie		/*
282272343Sngie		 * Send the first message to the receiver and wait for the ACK.
283272343Sngie		 */
284272343Sngie		m.mtype = MTYPE_1;
285272343Sngie		strcpy(m.mtext, m1_str);
286272343Sngie		ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN,
287272343Sngie		    0) != -1, "sender: msgsnd 1: %d", errno);
288272343Sngie
289272343Sngie		ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
290272343Sngie				       MTYPE_1_ACK, 0) == MESSAGE_TEXT_LEN,
291272343Sngie		    "sender: msgrcv 1 ack: %d", errno);
292272343Sngie
293272343Sngie		print_msqid_ds(&m_ds, 0600);
294272343Sngie
295272343Sngie		/*
296272343Sngie		 * Send the second message to the receiver and wait for the ACK.
297272343Sngie		 */
298272343Sngie		m.mtype = MTYPE_2;
299272343Sngie		strcpy(m.mtext, m2_str);
300272343Sngie		ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 0) != -1,
301272343Sngie		    "sender: msgsnd 2: %d", errno);
302272343Sngie
303272343Sngie		ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
304272343Sngie				       MTYPE_2_ACK, 0) == MESSAGE_TEXT_LEN,
305272343Sngie		    "sender: msgrcv 2 ack: %d", errno);
306272343Sngie	}
307272343Sngie
308272343Sngie	/*
309272343Sngie	 * Wait for child to finish
310272343Sngie	 */
311272343Sngie	sigemptyset(&sigmask);
312272343Sngie	(void) sigsuspend(&sigmask);
313272343Sngie
314272343Sngie	/*
315272343Sngie	 * ...and any other signal is an unexpected error.
316272343Sngie	 */
317272343Sngie	if (did_sigchild) {
318272343Sngie		c_status = child_status;
319272343Sngie		if (c_status < 0)
320272343Sngie			atf_tc_fail("waitpid: %d", -c_status);
321272343Sngie		else if (WIFEXITED(c_status) == 0)
322272343Sngie			atf_tc_fail("child abnormal exit: %d", c_status);
323272343Sngie		else if (WEXITSTATUS(c_status) != 0)
324272343Sngie			atf_tc_fail("c status: %d", WEXITSTATUS(c_status));
325272343Sngie		else {
326272343Sngie			ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds)
327272343Sngie			    != -1, "msgctl IPC_STAT: %d", errno);
328272343Sngie
329272343Sngie			print_msqid_ds(&m_ds, 0600);
330272343Sngie			atf_tc_pass();
331272343Sngie		}
332272343Sngie	} else
333272343Sngie		atf_tc_fail("sender: received unexpected signal");
334272343Sngie}
335272343Sngie
336272343SngieATF_TC_CLEANUP(msg, tc)
337272343Sngie{
338272343Sngie	int sender_msqid;
339272343Sngie
340272343Sngie	/*
341272343Sngie	 * Remove the message queue if it exists.
342272343Sngie	 */
343272343Sngie	sender_msqid = read_int("sender_msqid");
344272343Sngie	if (sender_msqid != -1)
345272343Sngie		if (msgctl(sender_msqid, IPC_RMID, NULL) == -1)
346272343Sngie			err(1, "msgctl IPC_RMID");
347272343Sngie}
348272343Sngie
349272343Sngievoid
350272343Sngieprint_msqid_ds(mp, mode)
351272343Sngie	struct msqid_ds *mp;
352272343Sngie	mode_t mode;
353272343Sngie{
354272343Sngie	uid_t uid = geteuid();
355272343Sngie	gid_t gid = getegid();
356272343Sngie
357272343Sngie	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
358272343Sngie	    mp->msg_perm.uid, mp->msg_perm.gid,
359272343Sngie	    mp->msg_perm.cuid, mp->msg_perm.cgid,
360272343Sngie	    mp->msg_perm.mode & 0777);
361272343Sngie
362272343Sngie	printf("qnum %lu, qbytes %lu, lspid %d, lrpid %d\n",
363272343Sngie	    mp->msg_qnum, (u_long)mp->msg_qbytes, mp->msg_lspid,
364272343Sngie	    mp->msg_lrpid);
365272343Sngie
366272343Sngie	printf("stime: %s", ctime(&mp->msg_stime));
367272343Sngie	printf("rtime: %s", ctime(&mp->msg_rtime));
368272343Sngie	printf("ctime: %s", ctime(&mp->msg_ctime));
369272343Sngie
370272343Sngie	/*
371272343Sngie	 * Sanity check a few things.
372272343Sngie	 */
373272343Sngie
374272343Sngie	ATF_REQUIRE_MSG(mp->msg_perm.uid == uid && mp->msg_perm.cuid == uid,
375272343Sngie	    "uid mismatch");
376272343Sngie
377272343Sngie	ATF_REQUIRE_MSG(mp->msg_perm.gid == gid && mp->msg_perm.cgid == gid,
378272343Sngie	    "gid mismatch");
379272343Sngie
380272343Sngie	ATF_REQUIRE_MSG((mp->msg_perm.mode & 0777) == mode, "mode mismatch");
381272343Sngie}
382272343Sngie
383272343Sngievoid
384272343Sngiereceiver()
385272343Sngie{
386272343Sngie	struct mymsg m;
387272343Sngie	int msqid, loop;
388272343Sngie
389272343Sngie	if ((msqid = msgget(msgkey, 0)) == -1)
390272343Sngie		err(1, "receiver: msgget");
391272343Sngie
392272343Sngie	for (loop = 0; loop < maxloop; loop++) {
393272343Sngie		/*
394272343Sngie		 * Receive the first message, print it, and send an ACK.
395272343Sngie		 */
396272343Sngie		if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_1, 0) != MESSAGE_TEXT_LEN)
397272343Sngie			err(1, "receiver: msgrcv 1");
398272343Sngie
399272343Sngie		printf("%s\n", m.mtext);
400272343Sngie		if (strcmp(m.mtext, m1_str) != 0)
401272343Sngie			err(1, "receiver: message 1 data isn't correct");
402272343Sngie
403272343Sngie		m.mtype = MTYPE_1_ACK;
404272343Sngie
405272343Sngie		if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
406272343Sngie			err(1, "receiver: msgsnd ack 1");
407272343Sngie
408272343Sngie		/*
409272343Sngie		 * Receive the second message, print it, and send an ACK.
410272343Sngie		 */
411272343Sngie
412272343Sngie		if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_2, 0) != MESSAGE_TEXT_LEN)
413272343Sngie			err(1, "receiver: msgrcv 2");
414272343Sngie
415272343Sngie		printf("%s\n", m.mtext);
416272343Sngie		if (strcmp(m.mtext, m2_str) != 0)
417272343Sngie			err(1, "receiver: message 2 data isn't correct");
418272343Sngie
419272343Sngie		m.mtype = MTYPE_2_ACK;
420272343Sngie
421272343Sngie		if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
422272343Sngie			err(1, "receiver: msgsnd ack 2");
423272343Sngie	}
424272343Sngie
425272343Sngie	exit(0);
426272343Sngie}
427272343Sngie
428272343Sngie/*
429272343Sngie * Test the SVID-compatible Semaphore facility.
430272343Sngie */
431272343Sngie
432272343SngieATF_TC_WITH_CLEANUP(sem);
433272343SngieATF_TC_HEAD(sem, tc)
434272343Sngie{
435272343Sngie
436272343Sngie	atf_tc_set_md_var(tc, "timeout", "3");
437272343Sngie	atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
438272343Sngie}
439272343Sngie
440272343SngieATF_TC_BODY(sem, tc)
441272343Sngie{
442272343Sngie	struct sigaction sa;
443272343Sngie	union semun sun;
444272343Sngie	struct semid_ds s_ds;
445272343Sngie	sigset_t sigmask;
446272343Sngie	int sender_semid;
447272343Sngie	int i;
448272343Sngie	int c_status;
449272343Sngie
450272343Sngie	/*
451272343Sngie	 * Install a SIGSYS handler so that we can exit gracefully if
452272343Sngie	 * System V Semaphore support isn't in the kernel.
453272343Sngie	 */
454272343Sngie	did_sigsys = 0;
455272343Sngie	sa.sa_handler = sigsys_handler;
456272343Sngie	sigemptyset(&sa.sa_mask);
457272343Sngie	sa.sa_flags = 0;
458272343Sngie	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
459272343Sngie	    "sigaction SIGSYS: %d", errno);
460272343Sngie
461272343Sngie	/*
462272343Sngie	 * Install a SIGCHLD handler to deal with all possible exit
463272343Sngie	 * conditions of the receiver.
464272343Sngie	 */
465272343Sngie	did_sigchild = 0;
466272343Sngie	child_count = 0;
467272343Sngie	sa.sa_handler = sigchld_handler;
468272343Sngie	sigemptyset(&sa.sa_mask);
469272343Sngie	sa.sa_flags = 0;
470272343Sngie	ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
471272343Sngie	    "sigaction SIGCHLD: %d", errno);
472272343Sngie
473272343Sngie	semkey = get_ftok(4160);
474272343Sngie	ATF_REQUIRE_MSG(semkey != (key_t)-1, "get_ftok failed");
475272343Sngie
476272343Sngie	sender_semid = semget(semkey, 1, IPC_CREAT | 0640);
477272343Sngie	ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno);
478272343Sngie	write_int("sender_semid", sender_semid);
479272343Sngie
480272343Sngie	if (did_sigsys) {
481272343Sngie		atf_tc_skip("SYSV Semaphore not supported");
482272343Sngie		return;
483272343Sngie	}
484272343Sngie
485272343Sngie	sun.buf = &s_ds;
486272343Sngie	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
487272343Sngie	    "semctl IPC_STAT: %d", errno);
488272343Sngie
489272343Sngie	print_semid_ds(&s_ds, 0640);
490272343Sngie
491272343Sngie	s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600;
492272343Sngie
493272343Sngie	sun.buf = &s_ds;
494272343Sngie	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1,
495272343Sngie	    "semctl IPC_SET: %d", errno);
496272343Sngie
497272343Sngie	memset(&s_ds, 0, sizeof(s_ds));
498272343Sngie
499272343Sngie	sun.buf = &s_ds;
500272343Sngie	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
501272343Sngie	    "semctl IPC_STAT: %d", errno);
502272343Sngie
503272343Sngie	ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600,
504272343Sngie	    "IPC_SET of mode didn't hold");
505272343Sngie
506272343Sngie	print_semid_ds(&s_ds, 0600);
507272343Sngie
508272343Sngie	for (child_count = 0; child_count < 5; child_count++) {
509272343Sngie		switch ((child_pid = fork())) {
510272343Sngie		case -1:
511272343Sngie			atf_tc_fail("fork: %d", errno);
512272343Sngie			return;
513272343Sngie
514272343Sngie		case 0:
515272343Sngie			waiter();
516272343Sngie			break;
517272343Sngie
518272343Sngie		default:
519272343Sngie			break;
520272343Sngie		}
521272343Sngie	}
522272343Sngie
523272343Sngie	/*
524272343Sngie	 * Wait for all of the waiters to be attempting to acquire the
525272343Sngie	 * semaphore.
526272343Sngie	 */
527272343Sngie	for (;;) {
528272343Sngie		i = semctl(sender_semid, 0, GETNCNT);
529272343Sngie		if (i == -1)
530272343Sngie			atf_tc_fail("semctl GETNCNT: %d", i);
531272343Sngie		if (i == 5)
532272343Sngie			break;
533272343Sngie	}
534272343Sngie
535272343Sngie	/*
536272343Sngie	 * Now set the thundering herd in motion by initializing the
537272343Sngie	 * semaphore to the value 1.
538272343Sngie	 */
539272343Sngie	sun.val = 1;
540272343Sngie	ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1,
541272343Sngie	    "sender: semctl SETVAL to 1: %d", errno);
542272343Sngie
543272343Sngie	/*
544272343Sngie	 * Wait for all children to finish
545272343Sngie	 */
546272343Sngie	sigemptyset(&sigmask);
547272343Sngie	for (;;) {
548272343Sngie		(void) sigsuspend(&sigmask);
549272343Sngie		if (did_sigchild) {
550272343Sngie			c_status = child_status;
551272343Sngie			if (c_status < 0)
552272343Sngie				atf_tc_fail("waitpid: %d", -c_status);
553272343Sngie			else if (WIFEXITED(c_status) == 0)
554272343Sngie				atf_tc_fail("c abnormal exit: %d", c_status);
555272343Sngie			else if (WEXITSTATUS(c_status) != 0)
556272343Sngie				atf_tc_fail("c status: %d",
557272343Sngie				    WEXITSTATUS(c_status));
558272343Sngie			else {
559272343Sngie				sun.buf = &s_ds;
560272343Sngie				ATF_REQUIRE_MSG(semctl(sender_semid, 0,
561272343Sngie						    IPC_STAT, sun) != -1,
562272343Sngie				    "semctl IPC_STAT: %d", errno);
563272343Sngie
564272343Sngie				print_semid_ds(&s_ds, 0600);
565272343Sngie				atf_tc_pass();
566272343Sngie			}
567272343Sngie			if (child_count <= 0)
568272343Sngie				break;
569272343Sngie			did_sigchild = 0;
570272343Sngie		} else {
571272343Sngie			atf_tc_fail("sender: received unexpected signal");
572272343Sngie			break;
573272343Sngie		}
574272343Sngie	}
575272343Sngie}
576272343Sngie
577272343SngieATF_TC_CLEANUP(sem, tc)
578272343Sngie{
579272343Sngie	int sender_semid;
580272343Sngie
581272343Sngie	/*
582272343Sngie	 * Remove the semaphore if it exists
583272343Sngie	 */
584272343Sngie	sender_semid = read_int("sender_semid");
585272343Sngie	if (sender_semid != -1)
586272343Sngie		if (semctl(sender_semid, 0, IPC_RMID) == -1)
587272343Sngie			err(1, "semctl IPC_RMID");
588272343Sngie}
589272343Sngie
590272343Sngievoid
591272343Sngieprint_semid_ds(sp, mode)
592272343Sngie	struct semid_ds *sp;
593272343Sngie	mode_t mode;
594272343Sngie{
595272343Sngie	uid_t uid = geteuid();
596272343Sngie	gid_t gid = getegid();
597272343Sngie
598272343Sngie	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
599272343Sngie	    sp->sem_perm.uid, sp->sem_perm.gid,
600272343Sngie	    sp->sem_perm.cuid, sp->sem_perm.cgid,
601272343Sngie	    sp->sem_perm.mode & 0777);
602272343Sngie
603272343Sngie	printf("nsems %u\n", sp->sem_nsems);
604272343Sngie
605272343Sngie	printf("otime: %s", ctime(&sp->sem_otime));
606272343Sngie	printf("ctime: %s", ctime(&sp->sem_ctime));
607272343Sngie
608272343Sngie	/*
609272343Sngie	 * Sanity check a few things.
610272343Sngie	 */
611272343Sngie
612272343Sngie	ATF_REQUIRE_MSG(sp->sem_perm.uid == uid && sp->sem_perm.cuid == uid,
613272343Sngie	    "uid mismatch");
614272343Sngie
615272343Sngie	ATF_REQUIRE_MSG(sp->sem_perm.gid == gid && sp->sem_perm.cgid == gid,
616272343Sngie	    "gid mismatch");
617272343Sngie
618272343Sngie	ATF_REQUIRE_MSG((sp->sem_perm.mode & 0777) == mode,
619272343Sngie	    "mode mismatch %o != %o", (sp->sem_perm.mode & 0777), mode);
620272343Sngie}
621272343Sngie
622272343Sngievoid
623272343Sngiewaiter()
624272343Sngie{
625272343Sngie	struct sembuf s;
626272343Sngie	int semid;
627272343Sngie
628272343Sngie	if ((semid = semget(semkey, 1, 0)) == -1)
629272343Sngie		err(1, "waiter: semget");
630272343Sngie
631272343Sngie	/*
632272343Sngie	 * Attempt to acquire the semaphore.
633272343Sngie	 */
634272343Sngie	s.sem_num = 0;
635272343Sngie	s.sem_op = -1;
636272343Sngie	s.sem_flg = SEM_UNDO;
637272343Sngie
638272343Sngie	if (semop(semid, &s, 1) == -1)
639272343Sngie		err(1, "waiter: semop -1");
640272343Sngie
641272343Sngie	printf("WOO!  GOT THE SEMAPHORE!\n");
642272343Sngie	sleep(1);
643272343Sngie
644272343Sngie	/*
645272343Sngie	 * Release the semaphore and exit.
646272343Sngie	 */
647272343Sngie	s.sem_num = 0;
648272343Sngie	s.sem_op = 1;
649272343Sngie	s.sem_flg = SEM_UNDO;
650272343Sngie
651272343Sngie	if (semop(semid, &s, 1) == -1)
652272343Sngie		err(1, "waiter: semop +1");
653272343Sngie
654272343Sngie	exit(0);
655272343Sngie}
656272343Sngie
657272343Sngie/*
658272343Sngie * Test the SVID-compatible Shared Memory facility.
659272343Sngie */
660272343Sngie
661272343SngieATF_TC_WITH_CLEANUP(shm);
662272343SngieATF_TC_HEAD(shm, tc)
663272343Sngie{
664272343Sngie
665272343Sngie	atf_tc_set_md_var(tc, "timeout", "3");
666272343Sngie	atf_tc_set_md_var(tc, "descr", "Checks sysv shared memory");
667272343Sngie}
668272343Sngie
669272343SngieATF_TC_BODY(shm, tc)
670272343Sngie{
671272343Sngie	struct sigaction sa;
672272343Sngie	struct shmid_ds s_ds;
673272343Sngie	sigset_t sigmask;
674272343Sngie	char *shm_buf;
675272343Sngie	int sender_shmid;
676272343Sngie	int c_status;
677272343Sngie
678272343Sngie	/*
679272343Sngie	 * Install a SIGSYS handler so that we can exit gracefully if
680272343Sngie	 * System V Shared Memory support isn't in the kernel.
681272343Sngie	 */
682272343Sngie	did_sigsys = 0;
683272343Sngie	sa.sa_handler = sigsys_handler;
684272343Sngie	sigemptyset(&sa.sa_mask);
685272343Sngie	sa.sa_flags = 0;
686272343Sngie	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
687272343Sngie	    "sigaction SIGSYS: %d", errno);
688272343Sngie
689272343Sngie	/*
690272343Sngie	 * Install a SIGCHLD handler to deal with all possible exit
691272343Sngie	 * conditions of the sharer.
692272343Sngie	 */
693272343Sngie	did_sigchild = 0;
694272343Sngie	child_count = 0;
695272343Sngie	sa.sa_handler = sigchld_handler;
696272343Sngie	sigemptyset(&sa.sa_mask);
697272343Sngie	sa.sa_flags = 0;
698272343Sngie	ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
699272343Sngie	    "sigaction SIGCHLD: %d", errno);
700272343Sngie
701272343Sngie	pgsize = sysconf(_SC_PAGESIZE);
702272343Sngie
703272343Sngie	shmkey = get_ftok(4160);
704272343Sngie	ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed");
705272343Sngie
706272343Sngie	ATF_REQUIRE_MSG((sender_shmid = shmget(shmkey, pgsize,
707272343Sngie					       IPC_CREAT | 0640)) != -1,
708272343Sngie	    "shmget: %d", errno);
709272343Sngie	write_int("sender_shmid", sender_shmid);
710272343Sngie
711272343Sngie	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
712272343Sngie	    "shmctl IPC_STAT: %d", errno);
713272343Sngie
714272343Sngie	print_shmid_ds(&s_ds, 0640);
715272343Sngie
716272343Sngie	s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600;
717272343Sngie
718272343Sngie	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_SET, &s_ds) != -1,
719272343Sngie	    "shmctl IPC_SET: %d", errno);
720272343Sngie
721272343Sngie	memset(&s_ds, 0, sizeof(s_ds));
722272343Sngie
723272343Sngie	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
724272343Sngie	    "shmctl IPC_STAT: %d", errno);
725272343Sngie
726272343Sngie	ATF_REQUIRE_MSG((s_ds.shm_perm.mode & 0777) == 0600,
727272343Sngie	    "IPC_SET of mode didn't hold");
728272343Sngie
729272343Sngie	print_shmid_ds(&s_ds, 0600);
730272343Sngie
731272343Sngie	shm_buf = shmat(sender_shmid, NULL, 0);
732272343Sngie	ATF_REQUIRE_MSG(shm_buf != (void *) -1, "sender: shmat: %d", errno);
733272343Sngie
734272343Sngie	/*
735272343Sngie	 * Write the test pattern into the shared memory buffer.
736272343Sngie	 */
737272343Sngie	strcpy(shm_buf, m2_str);
738272343Sngie
739272343Sngie	switch ((child_pid = fork())) {
740272343Sngie	case -1:
741272343Sngie		atf_tc_fail("fork: %d", errno);
742272343Sngie		return;
743272343Sngie
744272343Sngie	case 0:
745272343Sngie		sharer();
746272343Sngie		break;
747272343Sngie
748272343Sngie	default:
749272343Sngie		break;
750272343Sngie	}
751272343Sngie
752272343Sngie	/*
753272343Sngie	 * Wait for child to finish
754272343Sngie	 */
755272343Sngie	sigemptyset(&sigmask);
756272343Sngie	(void) sigsuspend(&sigmask);
757272343Sngie
758272343Sngie	if (did_sigchild) {
759272343Sngie		c_status = child_status;
760272343Sngie		if (c_status < 0)
761272343Sngie			atf_tc_fail("waitpid: %d", -c_status);
762272343Sngie		else if (WIFEXITED(c_status) == 0)
763272343Sngie			atf_tc_fail("c abnormal exit: %d", c_status);
764272343Sngie		else if (WEXITSTATUS(c_status) != 0)
765272343Sngie			atf_tc_fail("c status: %d", WEXITSTATUS(c_status));
766272343Sngie		else {
767272343Sngie			ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT,
768272343Sngie					       &s_ds) != -1,
769272343Sngie			    "shmctl IPC_STAT: %d", errno);
770272343Sngie
771272343Sngie			print_shmid_ds(&s_ds, 0600);
772272343Sngie			atf_tc_pass();
773272343Sngie		}
774272343Sngie	} else
775272343Sngie		atf_tc_fail("sender: received unexpected signal");
776272343Sngie}
777272343Sngie
778272343SngieATF_TC_CLEANUP(shm, tc)
779272343Sngie{
780272343Sngie	int sender_shmid;
781272343Sngie
782272343Sngie	/*
783272343Sngie	 * Remove the shared memory area if it exists.
784272343Sngie	 */
785272343Sngie	sender_shmid = read_int("sender_shmid");
786272343Sngie	if (sender_shmid != -1)
787272343Sngie		if (shmctl(sender_shmid, IPC_RMID, NULL) == -1)
788272343Sngie			err(1, "shmctl IPC_RMID");
789272343Sngie}
790272343Sngie
791272343Sngievoid
792272343Sngieprint_shmid_ds(sp, mode)
793272343Sngie	struct shmid_ds *sp;
794272343Sngie	mode_t mode;
795272343Sngie{
796272343Sngie	uid_t uid = geteuid();
797272343Sngie	gid_t gid = getegid();
798272343Sngie
799272343Sngie	printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
800272343Sngie	    sp->shm_perm.uid, sp->shm_perm.gid,
801272343Sngie	    sp->shm_perm.cuid, sp->shm_perm.cgid,
802272343Sngie	    sp->shm_perm.mode & 0777);
803272343Sngie
804272343Sngie	printf("segsz %lu, lpid %d, cpid %d, nattch %u\n",
805272343Sngie	    (u_long)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid,
806272343Sngie	    sp->shm_nattch);
807272343Sngie
808272343Sngie	printf("atime: %s", ctime(&sp->shm_atime));
809272343Sngie	printf("dtime: %s", ctime(&sp->shm_dtime));
810272343Sngie	printf("ctime: %s", ctime(&sp->shm_ctime));
811272343Sngie
812272343Sngie	/*
813272343Sngie	 * Sanity check a few things.
814272343Sngie	 */
815272343Sngie
816272343Sngie	ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid,
817272343Sngie	    "uid mismatch");
818272343Sngie
819272343Sngie	ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid,
820272343Sngie	    "gid mismatch");
821272343Sngie
822272343Sngie	ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode, "mode mismatch");
823272343Sngie}
824272343Sngie
825272343Sngievoid
826272343Sngiesharer()
827272343Sngie{
828272343Sngie	int shmid;
829272343Sngie	void *shm_buf;
830272343Sngie
831272343Sngie	shmid = shmget(shmkey, pgsize, 0);
832272343Sngie	ATF_REQUIRE_MSG(shmid != -1, "receiver: shmget:%d", errno);
833272343Sngie
834272343Sngie	shm_buf = shmat(shmid, NULL, 0);
835272343Sngie	ATF_REQUIRE_MSG(shm_buf != (void *) -1, "receiver: shmat: %d", errno);
836272343Sngie
837272343Sngie	printf("%s\n", (const char *)shm_buf);
838272343Sngie
839272343Sngie	ATF_REQUIRE_MSG(strcmp((const char *)shm_buf, m2_str) == 0,
840272343Sngie	    "receiver: data isn't correct");
841272343Sngie
842272343Sngie	exit(0);
843272343Sngie}
844272343Sngie
845272343SngieATF_TP_ADD_TCS(tp)
846272343Sngie{
847272343Sngie
848272343Sngie	ATF_TP_ADD_TC(tp, msg);
849272343Sngie	ATF_TP_ADD_TC(tp, sem);
850272343Sngie	ATF_TP_ADD_TC(tp, shm);
851272343Sngie
852272343Sngie	return atf_no_error();
853272343Sngie}
854272343Sngie
855