1272343Sngie/* $NetBSD: t_msgrcv.c,v 1.3 2013/07/24 11:44:10 skrll Exp $ */
2272343Sngie
3272343Sngie/*-
4272343Sngie * Copyright (c) 2011 The NetBSD Foundation, Inc.
5272343Sngie * All rights reserved.
6272343Sngie *
7272343Sngie * This code is derived from software contributed to The NetBSD Foundation
8272343Sngie * by Jukka Ruohonen.
9272343Sngie *
10272343Sngie * Redistribution and use in source and binary forms, with or without
11272343Sngie * modification, are permitted provided that the following conditions
12272343Sngie * are met:
13272343Sngie * 1. Redistributions of source code must retain the above copyright
14272343Sngie *    notice, this list of conditions and the following disclaimer.
15272343Sngie * 2. Redistributions in binary form must reproduce the above copyright
16272343Sngie *    notice, this list of conditions and the following disclaimer in the
17272343Sngie *    documentation and/or other materials provided with the distribution.
18272343Sngie *
19272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21272343Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22272343Sngie * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23272343Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24272343Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25272343Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27272343Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29272343Sngie * POSSIBILITY OF SUCH DAMAGE.
30272343Sngie */
31272343Sngie#include <sys/cdefs.h>
32272343Sngie__RCSID("$NetBSD: t_msgrcv.c,v 1.3 2013/07/24 11:44:10 skrll Exp $");
33272343Sngie
34272343Sngie#include <sys/msg.h>
35272343Sngie#include <sys/stat.h>
36272343Sngie#include <sys/sysctl.h>
37272343Sngie#include <sys/wait.h>
38272343Sngie
39272343Sngie#include <atf-c.h>
40272343Sngie#include <errno.h>
41272343Sngie#include <pwd.h>
42272343Sngie#include <signal.h>
43272343Sngie#include <stdio.h>
44272343Sngie#include <stdlib.h>
45272343Sngie#include <string.h>
46272343Sngie#include <sysexits.h>
47272343Sngie#include <time.h>
48272343Sngie#include <unistd.h>
49272343Sngie
50276478Sngie#ifdef __FreeBSD__
51276478Sngie#include <limits.h>
52276478Sngie#endif
53276478Sngie
54272343Sngie#define MSG_KEY		1234
55272343Sngie#define MSG_MTYPE_1	0x41
56272343Sngie#define	MSG_MTYPE_2	0x42
57272343Sngie#define MSG_MTYPE_3	0x43
58272343Sngie#define MSG_LEN		3
59272343Sngie
60272343Sngiestruct msg {
61272343Sngie	long		 mtype;
62272343Sngie	char		 buf[MSG_LEN];
63272343Sngie};
64272343Sngie
65272343Sngiestatic void		clean(void);
66272343Sngie
67272343Sngiestatic void
68272343Sngieclean(void)
69272343Sngie{
70272343Sngie	int id;
71272343Sngie
72272343Sngie	if ((id = msgget(MSG_KEY, 0)) != -1)
73272343Sngie		(void)msgctl(id, IPC_RMID, 0);
74272343Sngie}
75272343Sngie
76272343SngieATF_TC_WITH_CLEANUP(msgrcv_basic);
77272343SngieATF_TC_HEAD(msgrcv_basic, tc)
78272343Sngie{
79272343Sngie	atf_tc_set_md_var(tc, "descr", "A basic test of msgrcv(2)");
80272343Sngie}
81272343Sngie
82272343SngieATF_TC_BODY(msgrcv_basic, tc)
83272343Sngie{
84272343Sngie	struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
85272343Sngie	struct msg msg2 = { MSG_MTYPE_1, { 'x', 'y', 'z' } };
86272343Sngie	int id;
87272343Sngie
88272343Sngie	id = msgget(MSG_KEY, IPC_CREAT | 0600);
89272343Sngie	ATF_REQUIRE(id != -1);
90272343Sngie
91272343Sngie	(void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT);
92272343Sngie	(void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT);
93272343Sngie
94272343Sngie	ATF_CHECK(msg1.buf[0] == msg2.buf[0]);
95272343Sngie	ATF_CHECK(msg1.buf[1] == msg2.buf[1]);
96272343Sngie	ATF_CHECK(msg1.buf[2] == msg2.buf[2]);
97272343Sngie
98272343Sngie	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
99272343Sngie}
100272343Sngie
101272343SngieATF_TC_CLEANUP(msgrcv_basic, tc)
102272343Sngie{
103272343Sngie	clean();
104272343Sngie}
105272343Sngie
106272343SngieATF_TC_WITH_CLEANUP(msgrcv_block);
107272343SngieATF_TC_HEAD(msgrcv_block, tc)
108272343Sngie{
109272343Sngie	atf_tc_set_md_var(tc, "descr", "Test that msgrcv(2) blocks");
110272343Sngie}
111272343Sngie
112272343SngieATF_TC_BODY(msgrcv_block, tc)
113272343Sngie{
114272343Sngie	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
115272343Sngie	int id, sta;
116272343Sngie	pid_t pid;
117272343Sngie
118272343Sngie	id = msgget(MSG_KEY, IPC_CREAT | 0600);
119272343Sngie	ATF_REQUIRE(id != -1);
120272343Sngie
121272343Sngie	pid = fork();
122272343Sngie	ATF_REQUIRE(pid >= 0);
123272343Sngie
124272343Sngie	if (pid == 0) {
125272343Sngie
126272343Sngie		if (msgrcv(id, &msg, MSG_LEN, MSG_MTYPE_1, 0) < 0)
127272343Sngie			_exit(EXIT_FAILURE);
128272343Sngie
129272343Sngie		_exit(EXIT_SUCCESS);
130272343Sngie	}
131272343Sngie
132272343Sngie	/*
133272343Sngie	 * Below msgsnd(2) should unblock the child,
134272343Sngie	 * and hence kill(2) should fail with ESRCH.
135272343Sngie	 */
136272343Sngie	(void)sleep(1);
137272343Sngie	(void)msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT);
138272343Sngie	(void)sleep(1);
139272343Sngie	(void)kill(pid, SIGKILL);
140272343Sngie	(void)wait(&sta);
141272343Sngie
142272343Sngie	if (WIFEXITED(sta) == 0 || WIFSIGNALED(sta) != 0)
143272343Sngie		atf_tc_fail("msgrcv(2) did not block");
144272343Sngie
145272343Sngie	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
146272343Sngie}
147272343Sngie
148272343SngieATF_TC_CLEANUP(msgrcv_block, tc)
149272343Sngie{
150272343Sngie	clean();
151272343Sngie}
152272343Sngie
153272343SngieATF_TC_WITH_CLEANUP(msgrcv_err);
154272343SngieATF_TC_HEAD(msgrcv_err, tc)
155272343Sngie{
156272343Sngie	atf_tc_set_md_var(tc, "descr", "Test errors from msgrcv(2)");
157272343Sngie}
158272343Sngie
159272343SngieATF_TC_BODY(msgrcv_err, tc)
160272343Sngie{
161272343Sngie	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
162272343Sngie	int id, r = 0;
163272343Sngie
164272343Sngie	id = msgget(MSG_KEY, IPC_CREAT | 0600);
165272343Sngie	ATF_REQUIRE(id != -1);
166272343Sngie
167272343Sngie	errno = 0;
168272343Sngie
169272343Sngie	ATF_REQUIRE_ERRNO(ENOMSG, msgrcv(id, &msg,
170272343Sngie		MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1);
171272343Sngie
172272343Sngie	ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0);
173272343Sngie
174272343Sngie	errno = 0;
175272343Sngie
176272343Sngie	ATF_REQUIRE_ERRNO(EFAULT, msgrcv(id, (void *)-1,
177272343Sngie		MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1);
178272343Sngie
179272343Sngie	errno = 0;
180272343Sngie
181272343Sngie	ATF_REQUIRE_ERRNO(EINVAL, msgrcv(-1, &msg,
182272343Sngie		MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1);
183272343Sngie
184272343Sngie	errno = 0;
185272343Sngie
186272343Sngie	ATF_REQUIRE_ERRNO(EINVAL, msgrcv(-1, &msg,
187272343Sngie		SSIZE_MAX, MSG_MTYPE_1, IPC_NOWAIT) == -1);
188272343Sngie
189272343Sngie	ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0);
190272343Sngie
191272343Sngie	errno = 0;
192272343Sngie
193272343Sngie	ATF_REQUIRE_ERRNO(E2BIG, msgrcv(id, &r,
194272343Sngie		MSG_LEN - 1, MSG_MTYPE_1, IPC_NOWAIT) == -1);
195272343Sngie
196272343Sngie	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
197272343Sngie}
198272343Sngie
199272343SngieATF_TC_CLEANUP(msgrcv_err, tc)
200272343Sngie{
201272343Sngie	clean();
202272343Sngie}
203272343Sngie
204272343Sngie
205272343SngieATF_TC_WITH_CLEANUP(msgrcv_mtype);
206272343SngieATF_TC_HEAD(msgrcv_mtype, tc)
207272343Sngie{
208272343Sngie	atf_tc_set_md_var(tc, "descr", "Test message types with msgrcv(2)");
209272343Sngie}
210272343Sngie
211272343SngieATF_TC_BODY(msgrcv_mtype, tc)
212272343Sngie{
213272343Sngie	struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
214272343Sngie	struct msg msg2 = { MSG_MTYPE_3, { 'x', 'y', 'z' } };
215272343Sngie	int id;
216272343Sngie
217272343Sngie	id = msgget(MSG_KEY, IPC_CREAT | 0600);
218272343Sngie	ATF_REQUIRE(id != -1);
219272343Sngie
220272343Sngie	(void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT);
221272343Sngie	(void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_2, IPC_NOWAIT);
222272343Sngie
223272343Sngie	ATF_CHECK(msg1.buf[0] != msg2.buf[0]);	/* Different mtype. */
224272343Sngie	ATF_CHECK(msg1.buf[1] != msg2.buf[1]);
225272343Sngie	ATF_CHECK(msg1.buf[2] != msg2.buf[2]);
226272343Sngie
227272343Sngie	(void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT);
228272343Sngie
229272343Sngie	ATF_CHECK(msg1.buf[0] == msg2.buf[0]);	/* Same mtype. */
230272343Sngie	ATF_CHECK(msg1.buf[1] == msg2.buf[1]);
231272343Sngie	ATF_CHECK(msg1.buf[2] == msg2.buf[2]);
232272343Sngie
233272343Sngie	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
234272343Sngie}
235272343Sngie
236272343SngieATF_TC_CLEANUP(msgrcv_mtype, tc)
237272343Sngie{
238272343Sngie	clean();
239272343Sngie}
240272343Sngie
241272343SngieATF_TC_WITH_CLEANUP(msgrcv_nonblock);
242272343SngieATF_TC_HEAD(msgrcv_nonblock, tc)
243272343Sngie{
244272343Sngie	atf_tc_set_md_var(tc, "descr", "Test msgrcv(2) with IPC_NOWAIT");
245272343Sngie	atf_tc_set_md_var(tc, "timeout", "10");
246272343Sngie}
247272343Sngie
248272343SngieATF_TC_BODY(msgrcv_nonblock, tc)
249272343Sngie{
250272343Sngie	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
251272343Sngie	const ssize_t n = 10;
252272343Sngie	int id, sta;
253272343Sngie	ssize_t i;
254272343Sngie	pid_t pid;
255272343Sngie
256272343Sngie	id = msgget(MSG_KEY, IPC_CREAT | 0600);
257272343Sngie	ATF_REQUIRE(id != -1);
258272343Sngie
259272343Sngie	for (i = 0; i < n; i++) {
260272343Sngie
261272343Sngie		ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0);
262272343Sngie	}
263272343Sngie
264272343Sngie	pid = fork();
265272343Sngie	ATF_REQUIRE(pid >= 0);
266272343Sngie
267272343Sngie	if (pid == 0) {
268272343Sngie
269272343Sngie		while (i != 0) {
270272343Sngie
271272343Sngie			if (msgrcv(id, &msg, MSG_LEN, MSG_MTYPE_1,
272272343Sngie			    IPC_NOWAIT) == -1)
273272343Sngie				_exit(EXIT_FAILURE);
274272343Sngie
275272343Sngie			i--;
276272343Sngie		}
277272343Sngie
278272343Sngie		_exit(EXIT_SUCCESS);
279272343Sngie	}
280272343Sngie
281272343Sngie	(void)sleep(2);
282272343Sngie	(void)kill(pid, SIGKILL);
283272343Sngie	(void)wait(&sta);
284272343Sngie
285272343Sngie	if (WIFSIGNALED(sta) != 0 || WTERMSIG(sta) == SIGKILL)
286272343Sngie		atf_tc_fail("msgrcv(2) blocked with IPC_NOWAIT");
287272343Sngie
288272343Sngie	if (WIFEXITED(sta) == 0 && WEXITSTATUS(sta) != EXIT_SUCCESS)
289272343Sngie		atf_tc_fail("msgrcv(2) failed");
290272343Sngie
291272343Sngie	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
292272343Sngie}
293272343Sngie
294272343SngieATF_TC_CLEANUP(msgrcv_nonblock, tc)
295272343Sngie{
296272343Sngie	clean();
297272343Sngie}
298272343Sngie
299272343SngieATF_TC_WITH_CLEANUP(msgrcv_truncate);
300272343SngieATF_TC_HEAD(msgrcv_truncate, tc)
301272343Sngie{
302272343Sngie	atf_tc_set_md_var(tc, "descr", "Test msgrcv(2) with MSG_NOERROR");
303272343Sngie}
304272343Sngie
305272343SngieATF_TC_BODY(msgrcv_truncate, tc)
306272343Sngie{
307272343Sngie#define	MSG_SMALLLEN	2
308272343Sngie	struct msgsmall {
309272343Sngie		long		 mtype;
310272343Sngie		char		 buf[MSG_SMALLLEN];
311272343Sngie	};
312272343Sngie
313272343Sngie	struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
314272343Sngie	struct msgsmall msg2 = { MSG_MTYPE_1, { 'x', 'y' } };
315272343Sngie	int id;
316272343Sngie
317272343Sngie	id = msgget(MSG_KEY, IPC_CREAT | 0600);
318272343Sngie	ATF_REQUIRE(id != -1);
319272343Sngie
320272343Sngie	(void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT);
321272343Sngie	(void)msgrcv(id, &msg2, MSG_SMALLLEN,
322272343Sngie	    MSG_MTYPE_1, IPC_NOWAIT | MSG_NOERROR);
323272343Sngie
324272343Sngie	ATF_CHECK(msg1.buf[0] == msg2.buf[0]);
325272343Sngie	ATF_CHECK(msg1.buf[1] == msg2.buf[1]);
326272343Sngie
327272343Sngie	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
328272343Sngie}
329272343Sngie
330272343SngieATF_TC_CLEANUP(msgrcv_truncate, tc)
331272343Sngie{
332272343Sngie	clean();
333272343Sngie}
334272343Sngie
335272343SngieATF_TP_ADD_TCS(tp)
336272343Sngie{
337272343Sngie
338272343Sngie	ATF_TP_ADD_TC(tp, msgrcv_basic);
339272343Sngie	ATF_TP_ADD_TC(tp, msgrcv_block);
340272343Sngie	ATF_TP_ADD_TC(tp, msgrcv_err);
341272343Sngie	ATF_TP_ADD_TC(tp, msgrcv_mtype);
342272343Sngie	ATF_TP_ADD_TC(tp, msgrcv_nonblock);
343272343Sngie	ATF_TP_ADD_TC(tp, msgrcv_truncate);
344272343Sngie
345272343Sngie	return atf_no_error();
346272343Sngie}
347