summaryrefslogtreecommitdiff
path: root/src/regress/lib/libc/sys/t_msgrcv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/regress/lib/libc/sys/t_msgrcv.c')
-rw-r--r--src/regress/lib/libc/sys/t_msgrcv.c388
1 files changed, 388 insertions, 0 deletions
diff --git a/src/regress/lib/libc/sys/t_msgrcv.c b/src/regress/lib/libc/sys/t_msgrcv.c
new file mode 100644
index 0000000000..1fbcd41695
--- /dev/null
+++ b/src/regress/lib/libc/sys/t_msgrcv.c
@@ -0,0 +1,388 @@
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
61struct msg {
62 long mtype;
63 char buf[MSG_LEN];
64};
65
66static void clean(void);
67
68static void
69clean(void)
70{
71 int id;
72
73 if ((id = msgget(MSG_KEY, 0)) != -1)
74 (void)msgctl(id, IPC_RMID, 0);
75}
76
77ATF_TC_WITH_CLEANUP(msgrcv_basic);
78ATF_TC_HEAD(msgrcv_basic, tc)
79{
80 atf_tc_set_md_var(tc, "descr", "A basic test of msgrcv(2)");
81}
82
83ATF_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
102ATF_TC_CLEANUP(msgrcv_basic, tc)
103{
104 clean();
105}
106
107ATF_TC_WITH_CLEANUP(msgrcv_block);
108ATF_TC_HEAD(msgrcv_block, tc)
109{
110 atf_tc_set_md_var(tc, "descr", "Test that msgrcv(2) blocks");
111}
112
113ATF_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
149ATF_TC_CLEANUP(msgrcv_block, tc)
150{
151 clean();
152}
153
154ATF_TC_WITH_CLEANUP(msgrcv_err);
155ATF_TC_HEAD(msgrcv_err, tc)
156{
157 atf_tc_set_md_var(tc, "descr", "Test errors from msgrcv(2)");
158}
159
160ATF_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
200ATF_TC_CLEANUP(msgrcv_err, tc)
201{
202 clean();
203}
204
205
206ATF_TC_WITH_CLEANUP(msgrcv_mtype);
207ATF_TC_HEAD(msgrcv_mtype, tc)
208{
209 atf_tc_set_md_var(tc, "descr", "Test message types with msgrcv(2)");
210}
211
212ATF_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
237ATF_TC_CLEANUP(msgrcv_mtype, tc)
238{
239 clean();
240}
241
242ATF_TC_WITH_CLEANUP(msgrcv_nonblock);
243ATF_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
249ATF_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
295ATF_TC_CLEANUP(msgrcv_nonblock, tc)
296{
297 clean();
298}
299
300ATF_TC_WITH_CLEANUP(msgrcv_truncate);
301ATF_TC_HEAD(msgrcv_truncate, tc)
302{
303 atf_tc_set_md_var(tc, "descr", "Test msgrcv(2) with MSG_NOERROR");
304}
305
306ATF_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
331ATF_TC_CLEANUP(msgrcv_truncate, tc)
332{
333 clean();
334}
335
336static volatile int sig_caught;
337
338static void
339sigsys_handler(int signum)
340{
341
342 sig_caught = signum;
343}
344
345static int
346no_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
363ATF_TC(msgrcv_query);
364ATF_TC_HEAD(msgrcv_query, tc)
365{
366 atf_tc_set_md_var(tc, "descr", "Skip msgrcv_* tests - no SYSVMSG");
367}
368ATF_TC_BODY(msgrcv_query, tc)
369{
370 atf_tc_skip("No SYSVMSG in kernel");
371}
372
373ATF_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}