1314817Sngie/* $NetBSD: t_msgrcv.c,v 1.4 2017/01/13 20:44:45 christos 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>
32314817Sngie__RCSID("$NetBSD: t_msgrcv.c,v 1.4 2017/01/13 20:44:45 christos 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>
41314817Sngie#include <limits.h>
42272343Sngie#include <pwd.h>
43272343Sngie#include <signal.h>
44272343Sngie#include <stdio.h>
45272343Sngie#include <stdlib.h>
46272343Sngie#include <string.h>
47272343Sngie#include <sysexits.h>
48272343Sngie#include <time.h>
49272343Sngie#include <unistd.h>
50272343Sngie
51272343Sngie#define MSG_KEY		1234
52272343Sngie#define MSG_MTYPE_1	0x41
53272343Sngie#define	MSG_MTYPE_2	0x42
54272343Sngie#define MSG_MTYPE_3	0x43
55272343Sngie#define MSG_LEN		3
56272343Sngie
57272343Sngiestruct msg {
58272343Sngie	long		 mtype;
59272343Sngie	char		 buf[MSG_LEN];
60272343Sngie};
61272343Sngie
62272343Sngiestatic void		clean(void);
63272343Sngie
64272343Sngiestatic void
65272343Sngieclean(void)
66272343Sngie{
67272343Sngie	int id;
68272343Sngie
69272343Sngie	if ((id = msgget(MSG_KEY, 0)) != -1)
70272343Sngie		(void)msgctl(id, IPC_RMID, 0);
71272343Sngie}
72272343Sngie
73272343SngieATF_TC_WITH_CLEANUP(msgrcv_basic);
74272343SngieATF_TC_HEAD(msgrcv_basic, tc)
75272343Sngie{
76272343Sngie	atf_tc_set_md_var(tc, "descr", "A basic test of msgrcv(2)");
77272343Sngie}
78272343Sngie
79272343SngieATF_TC_BODY(msgrcv_basic, tc)
80272343Sngie{
81272343Sngie	struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
82272343Sngie	struct msg msg2 = { MSG_MTYPE_1, { 'x', 'y', 'z' } };
83272343Sngie	int id;
84272343Sngie
85272343Sngie	id = msgget(MSG_KEY, IPC_CREAT | 0600);
86272343Sngie	ATF_REQUIRE(id != -1);
87272343Sngie
88272343Sngie	(void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT);
89272343Sngie	(void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT);
90272343Sngie
91272343Sngie	ATF_CHECK(msg1.buf[0] == msg2.buf[0]);
92272343Sngie	ATF_CHECK(msg1.buf[1] == msg2.buf[1]);
93272343Sngie	ATF_CHECK(msg1.buf[2] == msg2.buf[2]);
94272343Sngie
95272343Sngie	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
96272343Sngie}
97272343Sngie
98272343SngieATF_TC_CLEANUP(msgrcv_basic, tc)
99272343Sngie{
100272343Sngie	clean();
101272343Sngie}
102272343Sngie
103272343SngieATF_TC_WITH_CLEANUP(msgrcv_block);
104272343SngieATF_TC_HEAD(msgrcv_block, tc)
105272343Sngie{
106272343Sngie	atf_tc_set_md_var(tc, "descr", "Test that msgrcv(2) blocks");
107272343Sngie}
108272343Sngie
109272343SngieATF_TC_BODY(msgrcv_block, tc)
110272343Sngie{
111272343Sngie	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
112272343Sngie	int id, sta;
113272343Sngie	pid_t pid;
114272343Sngie
115272343Sngie	id = msgget(MSG_KEY, IPC_CREAT | 0600);
116272343Sngie	ATF_REQUIRE(id != -1);
117272343Sngie
118272343Sngie	pid = fork();
119272343Sngie	ATF_REQUIRE(pid >= 0);
120272343Sngie
121272343Sngie	if (pid == 0) {
122272343Sngie
123272343Sngie		if (msgrcv(id, &msg, MSG_LEN, MSG_MTYPE_1, 0) < 0)
124272343Sngie			_exit(EXIT_FAILURE);
125272343Sngie
126272343Sngie		_exit(EXIT_SUCCESS);
127272343Sngie	}
128272343Sngie
129272343Sngie	/*
130272343Sngie	 * Below msgsnd(2) should unblock the child,
131272343Sngie	 * and hence kill(2) should fail with ESRCH.
132272343Sngie	 */
133272343Sngie	(void)sleep(1);
134272343Sngie	(void)msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT);
135272343Sngie	(void)sleep(1);
136272343Sngie	(void)kill(pid, SIGKILL);
137272343Sngie	(void)wait(&sta);
138272343Sngie
139272343Sngie	if (WIFEXITED(sta) == 0 || WIFSIGNALED(sta) != 0)
140272343Sngie		atf_tc_fail("msgrcv(2) did not block");
141272343Sngie
142272343Sngie	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
143272343Sngie}
144272343Sngie
145272343SngieATF_TC_CLEANUP(msgrcv_block, tc)
146272343Sngie{
147272343Sngie	clean();
148272343Sngie}
149272343Sngie
150272343SngieATF_TC_WITH_CLEANUP(msgrcv_err);
151272343SngieATF_TC_HEAD(msgrcv_err, tc)
152272343Sngie{
153272343Sngie	atf_tc_set_md_var(tc, "descr", "Test errors from msgrcv(2)");
154272343Sngie}
155272343Sngie
156272343SngieATF_TC_BODY(msgrcv_err, tc)
157272343Sngie{
158272343Sngie	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
159272343Sngie	int id, r = 0;
160272343Sngie
161272343Sngie	id = msgget(MSG_KEY, IPC_CREAT | 0600);
162272343Sngie	ATF_REQUIRE(id != -1);
163272343Sngie
164272343Sngie	errno = 0;
165272343Sngie
166272343Sngie	ATF_REQUIRE_ERRNO(ENOMSG, msgrcv(id, &msg,
167272343Sngie		MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1);
168272343Sngie
169272343Sngie	ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0);
170272343Sngie
171272343Sngie	errno = 0;
172272343Sngie
173272343Sngie	ATF_REQUIRE_ERRNO(EFAULT, msgrcv(id, (void *)-1,
174272343Sngie		MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1);
175272343Sngie
176272343Sngie	errno = 0;
177272343Sngie
178272343Sngie	ATF_REQUIRE_ERRNO(EINVAL, msgrcv(-1, &msg,
179272343Sngie		MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1);
180272343Sngie
181272343Sngie	errno = 0;
182272343Sngie
183272343Sngie	ATF_REQUIRE_ERRNO(EINVAL, msgrcv(-1, &msg,
184272343Sngie		SSIZE_MAX, MSG_MTYPE_1, IPC_NOWAIT) == -1);
185272343Sngie
186272343Sngie	ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0);
187272343Sngie
188272343Sngie	errno = 0;
189272343Sngie
190272343Sngie	ATF_REQUIRE_ERRNO(E2BIG, msgrcv(id, &r,
191272343Sngie		MSG_LEN - 1, MSG_MTYPE_1, IPC_NOWAIT) == -1);
192272343Sngie
193272343Sngie	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
194272343Sngie}
195272343Sngie
196272343SngieATF_TC_CLEANUP(msgrcv_err, tc)
197272343Sngie{
198272343Sngie	clean();
199272343Sngie}
200272343Sngie
201272343Sngie
202272343SngieATF_TC_WITH_CLEANUP(msgrcv_mtype);
203272343SngieATF_TC_HEAD(msgrcv_mtype, tc)
204272343Sngie{
205272343Sngie	atf_tc_set_md_var(tc, "descr", "Test message types with msgrcv(2)");
206272343Sngie}
207272343Sngie
208272343SngieATF_TC_BODY(msgrcv_mtype, tc)
209272343Sngie{
210272343Sngie	struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
211272343Sngie	struct msg msg2 = { MSG_MTYPE_3, { 'x', 'y', 'z' } };
212272343Sngie	int id;
213272343Sngie
214272343Sngie	id = msgget(MSG_KEY, IPC_CREAT | 0600);
215272343Sngie	ATF_REQUIRE(id != -1);
216272343Sngie
217272343Sngie	(void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT);
218272343Sngie	(void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_2, IPC_NOWAIT);
219272343Sngie
220272343Sngie	ATF_CHECK(msg1.buf[0] != msg2.buf[0]);	/* Different mtype. */
221272343Sngie	ATF_CHECK(msg1.buf[1] != msg2.buf[1]);
222272343Sngie	ATF_CHECK(msg1.buf[2] != msg2.buf[2]);
223272343Sngie
224272343Sngie	(void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT);
225272343Sngie
226272343Sngie	ATF_CHECK(msg1.buf[0] == msg2.buf[0]);	/* Same mtype. */
227272343Sngie	ATF_CHECK(msg1.buf[1] == msg2.buf[1]);
228272343Sngie	ATF_CHECK(msg1.buf[2] == msg2.buf[2]);
229272343Sngie
230272343Sngie	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
231272343Sngie}
232272343Sngie
233272343SngieATF_TC_CLEANUP(msgrcv_mtype, tc)
234272343Sngie{
235272343Sngie	clean();
236272343Sngie}
237272343Sngie
238272343SngieATF_TC_WITH_CLEANUP(msgrcv_nonblock);
239272343SngieATF_TC_HEAD(msgrcv_nonblock, tc)
240272343Sngie{
241272343Sngie	atf_tc_set_md_var(tc, "descr", "Test msgrcv(2) with IPC_NOWAIT");
242272343Sngie	atf_tc_set_md_var(tc, "timeout", "10");
243272343Sngie}
244272343Sngie
245272343SngieATF_TC_BODY(msgrcv_nonblock, tc)
246272343Sngie{
247272343Sngie	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
248272343Sngie	const ssize_t n = 10;
249272343Sngie	int id, sta;
250272343Sngie	ssize_t i;
251272343Sngie	pid_t pid;
252272343Sngie
253272343Sngie	id = msgget(MSG_KEY, IPC_CREAT | 0600);
254272343Sngie	ATF_REQUIRE(id != -1);
255272343Sngie
256272343Sngie	for (i = 0; i < n; i++) {
257272343Sngie
258272343Sngie		ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0);
259272343Sngie	}
260272343Sngie
261272343Sngie	pid = fork();
262272343Sngie	ATF_REQUIRE(pid >= 0);
263272343Sngie
264272343Sngie	if (pid == 0) {
265272343Sngie
266272343Sngie		while (i != 0) {
267272343Sngie
268272343Sngie			if (msgrcv(id, &msg, MSG_LEN, MSG_MTYPE_1,
269272343Sngie			    IPC_NOWAIT) == -1)
270272343Sngie				_exit(EXIT_FAILURE);
271272343Sngie
272272343Sngie			i--;
273272343Sngie		}
274272343Sngie
275272343Sngie		_exit(EXIT_SUCCESS);
276272343Sngie	}
277272343Sngie
278272343Sngie	(void)sleep(2);
279272343Sngie	(void)kill(pid, SIGKILL);
280272343Sngie	(void)wait(&sta);
281272343Sngie
282272343Sngie	if (WIFSIGNALED(sta) != 0 || WTERMSIG(sta) == SIGKILL)
283272343Sngie		atf_tc_fail("msgrcv(2) blocked with IPC_NOWAIT");
284272343Sngie
285272343Sngie	if (WIFEXITED(sta) == 0 && WEXITSTATUS(sta) != EXIT_SUCCESS)
286272343Sngie		atf_tc_fail("msgrcv(2) failed");
287272343Sngie
288272343Sngie	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
289272343Sngie}
290272343Sngie
291272343SngieATF_TC_CLEANUP(msgrcv_nonblock, tc)
292272343Sngie{
293272343Sngie	clean();
294272343Sngie}
295272343Sngie
296272343SngieATF_TC_WITH_CLEANUP(msgrcv_truncate);
297272343SngieATF_TC_HEAD(msgrcv_truncate, tc)
298272343Sngie{
299272343Sngie	atf_tc_set_md_var(tc, "descr", "Test msgrcv(2) with MSG_NOERROR");
300272343Sngie}
301272343Sngie
302272343SngieATF_TC_BODY(msgrcv_truncate, tc)
303272343Sngie{
304272343Sngie#define	MSG_SMALLLEN	2
305272343Sngie	struct msgsmall {
306272343Sngie		long		 mtype;
307272343Sngie		char		 buf[MSG_SMALLLEN];
308272343Sngie	};
309272343Sngie
310272343Sngie	struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
311272343Sngie	struct msgsmall msg2 = { MSG_MTYPE_1, { 'x', 'y' } };
312272343Sngie	int id;
313272343Sngie
314272343Sngie	id = msgget(MSG_KEY, IPC_CREAT | 0600);
315272343Sngie	ATF_REQUIRE(id != -1);
316272343Sngie
317272343Sngie	(void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT);
318272343Sngie	(void)msgrcv(id, &msg2, MSG_SMALLLEN,
319272343Sngie	    MSG_MTYPE_1, IPC_NOWAIT | MSG_NOERROR);
320272343Sngie
321272343Sngie	ATF_CHECK(msg1.buf[0] == msg2.buf[0]);
322272343Sngie	ATF_CHECK(msg1.buf[1] == msg2.buf[1]);
323272343Sngie
324272343Sngie	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
325272343Sngie}
326272343Sngie
327272343SngieATF_TC_CLEANUP(msgrcv_truncate, tc)
328272343Sngie{
329272343Sngie	clean();
330272343Sngie}
331272343Sngie
332272343SngieATF_TP_ADD_TCS(tp)
333272343Sngie{
334272343Sngie
335272343Sngie	ATF_TP_ADD_TC(tp, msgrcv_basic);
336272343Sngie	ATF_TP_ADD_TC(tp, msgrcv_block);
337272343Sngie	ATF_TP_ADD_TC(tp, msgrcv_err);
338272343Sngie	ATF_TP_ADD_TC(tp, msgrcv_mtype);
339272343Sngie	ATF_TP_ADD_TC(tp, msgrcv_nonblock);
340272343Sngie	ATF_TP_ADD_TC(tp, msgrcv_truncate);
341272343Sngie
342272343Sngie	return atf_no_error();
343272343Sngie}
344