t_msgrcv.c revision 1.2
1/* $NetBSD: t_msgrcv.c,v 1.2 2011/11/11 05:06:01 jruoho 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.2 2011/11/11 05:06:01 jruoho 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#define MSG_KEY		1234
51#define MSG_MTYPE_1	0x41
52#define	MSG_MTYPE_2	0x42
53#define MSG_MTYPE_3	0x43
54
55struct msg {
56	long		 mtype;
57	char		 buf[3];
58};
59
60static void		clean(void);
61
62static void
63clean(void)
64{
65	int id;
66
67	if ((id = msgget(MSG_KEY, 0)) != -1)
68		(void)msgctl(id, IPC_RMID, 0);
69}
70
71ATF_TC_WITH_CLEANUP(msgrcv_basic);
72ATF_TC_HEAD(msgrcv_basic, tc)
73{
74	atf_tc_set_md_var(tc, "descr", "A basic test of msgrcv(2)");
75}
76
77ATF_TC_BODY(msgrcv_basic, tc)
78{
79	struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
80	struct msg msg2 = { MSG_MTYPE_1, { 'x', 'y', 'z' } };
81	int id;
82
83	id = msgget(MSG_KEY, IPC_CREAT | 0600);
84	ATF_REQUIRE(id != -1);
85
86	(void)msgsnd(id, &msg1, sizeof(struct msg), IPC_NOWAIT);
87	(void)msgrcv(id, &msg2, sizeof(struct msg), MSG_MTYPE_1, IPC_NOWAIT);
88
89	ATF_CHECK(msg1.buf[0] == msg2.buf[0]);
90	ATF_CHECK(msg1.buf[1] == msg2.buf[1]);
91	ATF_CHECK(msg1.buf[2] == msg2.buf[2]);
92
93	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
94}
95
96ATF_TC_CLEANUP(msgrcv_basic, tc)
97{
98	clean();
99}
100
101ATF_TC_WITH_CLEANUP(msgrcv_block);
102ATF_TC_HEAD(msgrcv_block, tc)
103{
104	atf_tc_set_md_var(tc, "descr", "Test that msgrcv(2) blocks");
105}
106
107ATF_TC_BODY(msgrcv_block, tc)
108{
109	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
110	int id, sta;
111	pid_t pid;
112
113	id = msgget(MSG_KEY, IPC_CREAT | 0600);
114	ATF_REQUIRE(id != -1);
115
116	pid = fork();
117	ATF_REQUIRE(pid >= 0);
118
119	if (pid == 0) {
120
121		if (msgrcv(id, &msg, sizeof(struct msg), MSG_MTYPE_1, 0) < 0)
122			_exit(EXIT_FAILURE);
123
124		_exit(EXIT_SUCCESS);
125	}
126
127	/*
128	 * Below msgsnd(2) should unblock the child,
129	 * and hence kill(2) should fail with ESRCH.
130	 */
131	(void)sleep(1);
132	(void)msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT);
133	(void)sleep(1);
134	(void)kill(pid, SIGKILL);
135	(void)wait(&sta);
136
137	if (WIFEXITED(sta) == 0 || WIFSIGNALED(sta) != 0)
138		atf_tc_fail("msgrcv(2) did not block");
139
140	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
141}
142
143ATF_TC_CLEANUP(msgrcv_block, tc)
144{
145	clean();
146}
147
148ATF_TC_WITH_CLEANUP(msgrcv_err);
149ATF_TC_HEAD(msgrcv_err, tc)
150{
151	atf_tc_set_md_var(tc, "descr", "Test errors from msgrcv(2)");
152}
153
154ATF_TC_BODY(msgrcv_err, tc)
155{
156	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
157	int id, r = 0;
158
159	id = msgget(MSG_KEY, IPC_CREAT | 0600);
160	ATF_REQUIRE(id != -1);
161
162	errno = 0;
163
164	ATF_REQUIRE_ERRNO(ENOMSG, msgrcv(id, &msg,
165		sizeof(struct msg), MSG_MTYPE_1, IPC_NOWAIT) == -1);
166
167	ATF_REQUIRE(msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT) == 0);
168
169	errno = 0;
170
171	ATF_REQUIRE_ERRNO(EFAULT, msgrcv(id, (void *)-1,
172		sizeof(struct msg), MSG_MTYPE_1, IPC_NOWAIT) == -1);
173
174	errno = 0;
175
176	ATF_REQUIRE_ERRNO(EINVAL, msgrcv(-1, &msg,
177		sizeof(struct msg), MSG_MTYPE_1, IPC_NOWAIT) == -1);
178
179	errno = 0;
180
181	ATF_REQUIRE_ERRNO(EINVAL, msgrcv(-1, &msg,
182		SSIZE_MAX, MSG_MTYPE_1, IPC_NOWAIT) == -1);
183
184	ATF_REQUIRE(msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT) == 0);
185
186	errno = 0;
187
188	ATF_REQUIRE_ERRNO(E2BIG, msgrcv(id, &r,
189		sizeof(int), MSG_MTYPE_1, IPC_NOWAIT) == -1);
190
191	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
192}
193
194ATF_TC_CLEANUP(msgrcv_err, tc)
195{
196	clean();
197}
198
199
200ATF_TC_WITH_CLEANUP(msgrcv_mtype);
201ATF_TC_HEAD(msgrcv_mtype, tc)
202{
203	atf_tc_set_md_var(tc, "descr", "Test message types with msgrcv(2)");
204}
205
206ATF_TC_BODY(msgrcv_mtype, tc)
207{
208	struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
209	struct msg msg2 = { MSG_MTYPE_3, { 'x', 'y', 'z' } };
210	int id;
211
212	id = msgget(MSG_KEY, IPC_CREAT | 0600);
213	ATF_REQUIRE(id != -1);
214
215	(void)msgsnd(id, &msg1, sizeof(struct msg), IPC_NOWAIT);
216	(void)msgrcv(id, &msg2, sizeof(struct msg), MSG_MTYPE_2, IPC_NOWAIT);
217
218	ATF_CHECK(msg1.buf[0] != msg2.buf[0]);	/* Different mtype. */
219	ATF_CHECK(msg1.buf[1] != msg2.buf[1]);
220	ATF_CHECK(msg1.buf[2] != msg2.buf[2]);
221
222	(void)msgrcv(id, &msg2, sizeof(struct msg), MSG_MTYPE_1, IPC_NOWAIT);
223
224	ATF_CHECK(msg1.buf[0] == msg2.buf[0]);	/* Same mtype. */
225	ATF_CHECK(msg1.buf[1] == msg2.buf[1]);
226	ATF_CHECK(msg1.buf[2] == msg2.buf[2]);
227
228	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
229}
230
231ATF_TC_CLEANUP(msgrcv_mtype, tc)
232{
233	clean();
234}
235
236ATF_TC_WITH_CLEANUP(msgrcv_nonblock);
237ATF_TC_HEAD(msgrcv_nonblock, tc)
238{
239	atf_tc_set_md_var(tc, "descr", "Test msgrcv(2) with IPC_NOWAIT");
240	atf_tc_set_md_var(tc, "timeout", "10");
241}
242
243ATF_TC_BODY(msgrcv_nonblock, tc)
244{
245	struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
246	const ssize_t n = 10;
247	int id, sta;
248	ssize_t i;
249	pid_t pid;
250
251	id = msgget(MSG_KEY, IPC_CREAT | 0600);
252	ATF_REQUIRE(id != -1);
253
254	for (i = 0; i < n; i++) {
255
256		ATF_REQUIRE(msgsnd(id, &msg,
257			sizeof(struct msg), IPC_NOWAIT) == 0);
258	}
259
260	pid = fork();
261	ATF_REQUIRE(pid >= 0);
262
263	if (pid == 0) {
264
265		while (i != 0) {
266
267			if (msgrcv(id, &msg, sizeof(struct msg),
268				MSG_MTYPE_1, IPC_NOWAIT) == -1)
269				_exit(EXIT_FAILURE);
270
271			i--;
272		}
273
274		_exit(EXIT_SUCCESS);
275	}
276
277	(void)sleep(2);
278	(void)kill(pid, SIGKILL);
279	(void)wait(&sta);
280
281	if (WIFSIGNALED(sta) != 0 || WTERMSIG(sta) == SIGKILL)
282		atf_tc_fail("msgrcv(2) blocked with IPC_NOWAIT");
283
284	if (WIFEXITED(sta) == 0 && WEXITSTATUS(sta) != EXIT_SUCCESS)
285		atf_tc_fail("msgrcv(2) failed");
286
287	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
288}
289
290ATF_TC_CLEANUP(msgrcv_nonblock, tc)
291{
292	clean();
293}
294
295ATF_TC_WITH_CLEANUP(msgrcv_truncate);
296ATF_TC_HEAD(msgrcv_truncate, tc)
297{
298	atf_tc_set_md_var(tc, "descr", "Test msgrcv(2) with MSG_NOERROR");
299}
300
301ATF_TC_BODY(msgrcv_truncate, tc)
302{
303	struct msgsmall {
304		long		 mtype;
305		char		 buf[2];
306	};
307
308	struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
309	struct msgsmall msg2 = { MSG_MTYPE_1, { 'x', 'y' } };
310	int id;
311
312	id = msgget(MSG_KEY, IPC_CREAT | 0600);
313	ATF_REQUIRE(id != -1);
314
315	(void)msgsnd(id, &msg1, sizeof(struct msg), IPC_NOWAIT);
316	(void)msgrcv(id, &msg2, sizeof(struct msgsmall),
317	    MSG_MTYPE_1, IPC_NOWAIT | MSG_NOERROR);
318
319	ATF_CHECK(msg1.buf[0] == msg2.buf[0]);
320	ATF_CHECK(msg1.buf[1] == msg2.buf[1]);
321
322	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
323}
324
325ATF_TC_CLEANUP(msgrcv_truncate, tc)
326{
327	clean();
328}
329
330ATF_TP_ADD_TCS(tp)
331{
332
333	ATF_TP_ADD_TC(tp, msgrcv_basic);
334	ATF_TP_ADD_TC(tp, msgrcv_block);
335	ATF_TP_ADD_TC(tp, msgrcv_err);
336	ATF_TP_ADD_TC(tp, msgrcv_mtype);
337	ATF_TP_ADD_TC(tp, msgrcv_nonblock);
338	ATF_TP_ADD_TC(tp, msgrcv_truncate);
339
340	return atf_no_error();
341}
342