t_msgrcv.c revision 276478
1/* $NetBSD: t_msgrcv.c,v 1.3 2013/07/24 11:44:10 skrll Exp $ */
2
3/*-
4 * Copyright (c) 2011 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jukka Ruohonen.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31#include <sys/cdefs.h>
32__RCSID("$NetBSD: t_msgrcv.c,v 1.3 2013/07/24 11:44:10 skrll Exp $");
33
34#include <sys/msg.h>
35#include <sys/stat.h>
36#include <sys/sysctl.h>
37#include <sys/wait.h>
38
39#include <atf-c.h>
40#include <errno.h>
41#include <pwd.h>
42#include <signal.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <sysexits.h>
47#include <time.h>
48#include <unistd.h>
49
50#ifdef __FreeBSD__
51#include <limits.h>
52#endif
53
54#define MSG_KEY		1234
55#define MSG_MTYPE_1	0x41
56#define	MSG_MTYPE_2	0x42
57#define MSG_MTYPE_3	0x43
58#define MSG_LEN		3
59
60struct msg {
61	long		 mtype;
62	char		 buf[MSG_LEN];
63};
64
65static void		clean(void);
66
67static void
68clean(void)
69{
70	int id;
71
72	if ((id = msgget(MSG_KEY, 0)) != -1)
73		(void)msgctl(id, IPC_RMID, 0);
74}
75
76ATF_TC_WITH_CLEANUP(msgrcv_basic);
77ATF_TC_HEAD(msgrcv_basic, tc)
78{
79	atf_tc_set_md_var(tc, "descr", "A basic test of msgrcv(2)");
80}
81
82ATF_TC_BODY(msgrcv_basic, tc)
83{
84	struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
85	struct msg msg2 = { MSG_MTYPE_1, { 'x', 'y', 'z' } };
86	int id;
87
88	id = msgget(MSG_KEY, IPC_CREAT | 0600);
89	ATF_REQUIRE(id != -1);
90
91	(void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT);
92	(void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT);
93
94	ATF_CHECK(msg1.buf[0] == msg2.buf[0]);
95	ATF_CHECK(msg1.buf[1] == msg2.buf[1]);
96	ATF_CHECK(msg1.buf[2] == msg2.buf[2]);
97
98	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
99}
100
101ATF_TC_CLEANUP(msgrcv_basic, tc)
102{
103	clean();
104}
105
106ATF_TC_WITH_CLEANUP(msgrcv_block);
107ATF_TC_HEAD(msgrcv_block, tc)
108{
109	atf_tc_set_md_var(tc, "descr", "Test that msgrcv(2) blocks");
110}
111
112ATF_TC_BODY(msgrcv_block, tc)
113{
114	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
115	int id, sta;
116	pid_t pid;
117
118	id = msgget(MSG_KEY, IPC_CREAT | 0600);
119	ATF_REQUIRE(id != -1);
120
121	pid = fork();
122	ATF_REQUIRE(pid >= 0);
123
124	if (pid == 0) {
125
126		if (msgrcv(id, &msg, MSG_LEN, MSG_MTYPE_1, 0) < 0)
127			_exit(EXIT_FAILURE);
128
129		_exit(EXIT_SUCCESS);
130	}
131
132	/*
133	 * Below msgsnd(2) should unblock the child,
134	 * and hence kill(2) should fail with ESRCH.
135	 */
136	(void)sleep(1);
137	(void)msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT);
138	(void)sleep(1);
139	(void)kill(pid, SIGKILL);
140	(void)wait(&sta);
141
142	if (WIFEXITED(sta) == 0 || WIFSIGNALED(sta) != 0)
143		atf_tc_fail("msgrcv(2) did not block");
144
145	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
146}
147
148ATF_TC_CLEANUP(msgrcv_block, tc)
149{
150	clean();
151}
152
153ATF_TC_WITH_CLEANUP(msgrcv_err);
154ATF_TC_HEAD(msgrcv_err, tc)
155{
156	atf_tc_set_md_var(tc, "descr", "Test errors from msgrcv(2)");
157}
158
159ATF_TC_BODY(msgrcv_err, tc)
160{
161	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
162	int id, r = 0;
163
164	id = msgget(MSG_KEY, IPC_CREAT | 0600);
165	ATF_REQUIRE(id != -1);
166
167	errno = 0;
168
169	ATF_REQUIRE_ERRNO(ENOMSG, msgrcv(id, &msg,
170		MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1);
171
172	ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0);
173
174	errno = 0;
175
176	ATF_REQUIRE_ERRNO(EFAULT, msgrcv(id, (void *)-1,
177		MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1);
178
179	errno = 0;
180
181	ATF_REQUIRE_ERRNO(EINVAL, msgrcv(-1, &msg,
182		MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1);
183
184	errno = 0;
185
186	ATF_REQUIRE_ERRNO(EINVAL, msgrcv(-1, &msg,
187		SSIZE_MAX, MSG_MTYPE_1, IPC_NOWAIT) == -1);
188
189	ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0);
190
191	errno = 0;
192
193	ATF_REQUIRE_ERRNO(E2BIG, msgrcv(id, &r,
194		MSG_LEN - 1, MSG_MTYPE_1, IPC_NOWAIT) == -1);
195
196	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
197}
198
199ATF_TC_CLEANUP(msgrcv_err, tc)
200{
201	clean();
202}
203
204
205ATF_TC_WITH_CLEANUP(msgrcv_mtype);
206ATF_TC_HEAD(msgrcv_mtype, tc)
207{
208	atf_tc_set_md_var(tc, "descr", "Test message types with msgrcv(2)");
209}
210
211ATF_TC_BODY(msgrcv_mtype, tc)
212{
213	struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
214	struct msg msg2 = { MSG_MTYPE_3, { 'x', 'y', 'z' } };
215	int id;
216
217	id = msgget(MSG_KEY, IPC_CREAT | 0600);
218	ATF_REQUIRE(id != -1);
219
220	(void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT);
221	(void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_2, IPC_NOWAIT);
222
223	ATF_CHECK(msg1.buf[0] != msg2.buf[0]);	/* Different mtype. */
224	ATF_CHECK(msg1.buf[1] != msg2.buf[1]);
225	ATF_CHECK(msg1.buf[2] != msg2.buf[2]);
226
227	(void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT);
228
229	ATF_CHECK(msg1.buf[0] == msg2.buf[0]);	/* Same mtype. */
230	ATF_CHECK(msg1.buf[1] == msg2.buf[1]);
231	ATF_CHECK(msg1.buf[2] == msg2.buf[2]);
232
233	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
234}
235
236ATF_TC_CLEANUP(msgrcv_mtype, tc)
237{
238	clean();
239}
240
241ATF_TC_WITH_CLEANUP(msgrcv_nonblock);
242ATF_TC_HEAD(msgrcv_nonblock, tc)
243{
244	atf_tc_set_md_var(tc, "descr", "Test msgrcv(2) with IPC_NOWAIT");
245	atf_tc_set_md_var(tc, "timeout", "10");
246}
247
248ATF_TC_BODY(msgrcv_nonblock, tc)
249{
250	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
251	const ssize_t n = 10;
252	int id, sta;
253	ssize_t i;
254	pid_t pid;
255
256	id = msgget(MSG_KEY, IPC_CREAT | 0600);
257	ATF_REQUIRE(id != -1);
258
259	for (i = 0; i < n; i++) {
260
261		ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0);
262	}
263
264	pid = fork();
265	ATF_REQUIRE(pid >= 0);
266
267	if (pid == 0) {
268
269		while (i != 0) {
270
271			if (msgrcv(id, &msg, MSG_LEN, MSG_MTYPE_1,
272			    IPC_NOWAIT) == -1)
273				_exit(EXIT_FAILURE);
274
275			i--;
276		}
277
278		_exit(EXIT_SUCCESS);
279	}
280
281	(void)sleep(2);
282	(void)kill(pid, SIGKILL);
283	(void)wait(&sta);
284
285	if (WIFSIGNALED(sta) != 0 || WTERMSIG(sta) == SIGKILL)
286		atf_tc_fail("msgrcv(2) blocked with IPC_NOWAIT");
287
288	if (WIFEXITED(sta) == 0 && WEXITSTATUS(sta) != EXIT_SUCCESS)
289		atf_tc_fail("msgrcv(2) failed");
290
291	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
292}
293
294ATF_TC_CLEANUP(msgrcv_nonblock, tc)
295{
296	clean();
297}
298
299ATF_TC_WITH_CLEANUP(msgrcv_truncate);
300ATF_TC_HEAD(msgrcv_truncate, tc)
301{
302	atf_tc_set_md_var(tc, "descr", "Test msgrcv(2) with MSG_NOERROR");
303}
304
305ATF_TC_BODY(msgrcv_truncate, tc)
306{
307#define	MSG_SMALLLEN	2
308	struct msgsmall {
309		long		 mtype;
310		char		 buf[MSG_SMALLLEN];
311	};
312
313	struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
314	struct msgsmall msg2 = { MSG_MTYPE_1, { 'x', 'y' } };
315	int id;
316
317	id = msgget(MSG_KEY, IPC_CREAT | 0600);
318	ATF_REQUIRE(id != -1);
319
320	(void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT);
321	(void)msgrcv(id, &msg2, MSG_SMALLLEN,
322	    MSG_MTYPE_1, IPC_NOWAIT | MSG_NOERROR);
323
324	ATF_CHECK(msg1.buf[0] == msg2.buf[0]);
325	ATF_CHECK(msg1.buf[1] == msg2.buf[1]);
326
327	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
328}
329
330ATF_TC_CLEANUP(msgrcv_truncate, tc)
331{
332	clean();
333}
334
335ATF_TP_ADD_TCS(tp)
336{
337
338	ATF_TP_ADD_TC(tp, msgrcv_basic);
339	ATF_TP_ADD_TC(tp, msgrcv_block);
340	ATF_TP_ADD_TC(tp, msgrcv_err);
341	ATF_TP_ADD_TC(tp, msgrcv_mtype);
342	ATF_TP_ADD_TC(tp, msgrcv_nonblock);
343	ATF_TP_ADD_TC(tp, msgrcv_truncate);
344
345	return atf_no_error();
346}
347