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