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