]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/netbsd-tests/lib/libc/sys/t_msgsnd.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / netbsd-tests / lib / libc / sys / t_msgsnd.c
1 /* $NetBSD: t_msgsnd.c,v 1.2 2011/11/05 08:47:54 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_msgsnd.c,v 1.2 2011/11/05 08:47:54 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 #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
59 struct msg {
60         long             mtype;
61         char             buf[3];
62 };
63
64 static void             clean(void);
65
66 static void
67 clean(void)
68 {
69         int id;
70
71         if ((id = msgget(MSG_KEY, 0)) != -1)
72                 (void)msgctl(id, IPC_RMID, 0);
73 }
74
75 ATF_TC_WITH_CLEANUP(msgsnd_block);
76 ATF_TC_HEAD(msgsnd_block, tc)
77 {
78         atf_tc_set_md_var(tc, "descr", "Test that msgsnd(2) blocks");
79         atf_tc_set_md_var(tc, "timeout", "10");
80 }
81
82 ATF_TC_BODY(msgsnd_block, tc)
83 {
84         struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
85         int id, sta;
86         pid_t pid;
87
88         id = msgget(MSG_KEY, IPC_CREAT | 0600);
89         ATF_REQUIRE(id != -1);
90
91         pid = fork();
92         ATF_REQUIRE(pid >= 0);
93
94         if (pid == 0) {
95
96                 /*
97                  * Enqueue messages until some limit (e.g. the maximum
98                  * number of messages in the queue or the maximum number
99                  * of bytes in the queue) is reached. After this the call
100                  * should block when the IPC_NOWAIT is not set.
101                  */
102                 for (;;) {
103
104                         if (msgsnd(id, &msg, sizeof(struct msg), 0) < 0)
105                                 _exit(EXIT_FAILURE);
106                 }
107         }
108
109         (void)sleep(2);
110         (void)kill(pid, SIGKILL);
111         (void)wait(&sta);
112
113         if (WIFEXITED(sta) != 0 || WIFSIGNALED(sta) == 0)
114                 atf_tc_fail("msgsnd(2) did not block");
115
116         ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
117 }
118
119 ATF_TC_CLEANUP(msgsnd_block, tc)
120 {
121         clean();
122 }
123
124 ATF_TC_WITH_CLEANUP(msgsnd_count);
125 ATF_TC_HEAD(msgsnd_count, tc)
126 {
127         atf_tc_set_md_var(tc, "descr",
128             "Test that msgsnd(2) increments the amount of "
129             "message in the queue, as given by msgctl(2)");
130         atf_tc_set_md_var(tc, "timeout", "10");
131 }
132
133 ATF_TC_BODY(msgsnd_count, tc)
134 {
135         struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
136         struct msqid_ds ds;
137         size_t i = 0;
138         int id, rv;
139
140         id = msgget(MSG_KEY, IPC_CREAT | 0600);
141         ATF_REQUIRE(id != -1);
142
143         for (;;) {
144
145                 errno = 0;
146                 rv = msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT);
147
148                 if (rv == 0) {
149                         i++;
150                         continue;
151                 }
152
153                 if (rv == -1 && errno == EAGAIN)
154                         break;
155
156                 atf_tc_fail("failed to enqueue a message");
157         }
158
159         (void)memset(&ds, 0, sizeof(struct msqid_ds));
160         (void)msgctl(id, IPC_STAT, &ds);
161
162         if (ds.msg_qnum != i)
163                 atf_tc_fail("incorrect message count");
164
165         ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
166 }
167
168 ATF_TC_CLEANUP(msgsnd_count, tc)
169 {
170         clean();
171 }
172
173 ATF_TC_WITH_CLEANUP(msgsnd_err);
174 ATF_TC_HEAD(msgsnd_err, tc)
175 {
176         atf_tc_set_md_var(tc, "descr", "Test errors from msgsnd(2)");
177 }
178
179 ATF_TC_BODY(msgsnd_err, tc)
180 {
181         struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
182         int id;
183
184         id = msgget(MSG_KEY, IPC_CREAT | 0600);
185         ATF_REQUIRE(id != -1);
186
187         errno = 0;
188
189         ATF_REQUIRE_ERRNO(EFAULT, msgsnd(id, (void *)-1,
190                 sizeof(struct msg), IPC_NOWAIT) == -1);
191
192         errno = 0;
193
194         ATF_REQUIRE_ERRNO(EINVAL, msgsnd(-1, &msg,
195                 sizeof(struct msg), IPC_NOWAIT) == -1);
196
197         errno = 0;
198
199         ATF_REQUIRE_ERRNO(EINVAL, msgsnd(-1, &msg,
200                 SSIZE_MAX, IPC_NOWAIT) == -1);
201
202         errno = 0;
203         msg.mtype = 0;
204
205         ATF_REQUIRE_ERRNO(EINVAL, msgsnd(id, &msg,
206                 sizeof(struct msg), IPC_NOWAIT) == -1);
207
208         ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
209 }
210
211 ATF_TC_CLEANUP(msgsnd_err, tc)
212 {
213         clean();
214 }
215
216 ATF_TC_WITH_CLEANUP(msgsnd_nonblock);
217 ATF_TC_HEAD(msgsnd_nonblock, tc)
218 {
219         atf_tc_set_md_var(tc, "descr", "Test msgsnd(2) with IPC_NOWAIT");
220         atf_tc_set_md_var(tc, "timeout", "10");
221 }
222
223 ATF_TC_BODY(msgsnd_nonblock, tc)
224 {
225         struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
226         int id, rv, sta;
227         pid_t pid;
228
229         id = msgget(MSG_KEY, IPC_CREAT | 0600);
230         ATF_REQUIRE(id != -1);
231
232         pid = fork();
233         ATF_REQUIRE(pid >= 0);
234
235         if (pid == 0) {
236
237                 for (;;) {
238
239                         errno = 0;
240                         rv = msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT);
241
242                         if (rv == -1 && errno == EAGAIN)
243                                 _exit(EXIT_SUCCESS);
244                 }
245         }
246
247         (void)sleep(2);
248         (void)kill(pid, SIGKILL);
249         (void)wait(&sta);
250
251         if (WIFEXITED(sta) == 0 || WIFSIGNALED(sta) != 0)
252                 atf_tc_fail("msgsnd(2) blocked with IPC_NOWAIT");
253
254         ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
255 }
256
257 ATF_TC_CLEANUP(msgsnd_nonblock, tc)
258 {
259         clean();
260 }
261
262 ATF_TC_WITH_CLEANUP(msgsnd_perm);
263 ATF_TC_HEAD(msgsnd_perm, tc)
264 {
265         atf_tc_set_md_var(tc, "descr", "Test permissions with msgsnd(2)");
266         atf_tc_set_md_var(tc, "require.user", "root");
267 }
268
269 ATF_TC_BODY(msgsnd_perm, tc)
270 {
271         struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } };
272         struct passwd *pw;
273         int id, sta;
274         pid_t pid;
275         uid_t uid;
276
277         pw = getpwnam("nobody");
278         id = msgget(MSG_KEY, IPC_CREAT | 0600);
279
280         ATF_REQUIRE(id != -1);
281         ATF_REQUIRE(pw != NULL);
282
283         uid = pw->pw_uid;
284         ATF_REQUIRE(uid != 0);
285
286         pid = fork();
287         ATF_REQUIRE(pid >= 0);
288
289         if (pid == 0) {
290
291                 /*
292                  * Try to enqueue a message to the queue
293                  * created by root as RW for owner only.
294                  */
295                 if (setuid(uid) != 0)
296                         _exit(EX_OSERR);
297
298                 id = msgget(MSG_KEY, 0);
299
300                 if (id == -1)
301                         _exit(EX_OSERR);
302
303                 errno = 0;
304
305                 if (msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT) == 0)
306                         _exit(EXIT_FAILURE);
307
308                 if (errno != EACCES)
309                         _exit(EXIT_FAILURE);
310
311                 _exit(EXIT_SUCCESS);
312         }
313
314         (void)wait(&sta);
315
316         if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) {
317
318                 if (errno == EX_OSERR)
319                         atf_tc_fail("system call failed");
320
321                 atf_tc_fail("UID %u enqueued message to root's queue", uid);
322         }
323
324         ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
325 }
326
327 ATF_TC_CLEANUP(msgsnd_perm, tc)
328 {
329         clean();
330 }
331
332 ATF_TP_ADD_TCS(tp)
333 {
334
335         ATF_TP_ADD_TC(tp, msgsnd_block);
336         ATF_TP_ADD_TC(tp, msgsnd_count);
337         ATF_TP_ADD_TC(tp, msgsnd_err);
338         ATF_TP_ADD_TC(tp, msgsnd_nonblock);
339         ATF_TP_ADD_TC(tp, msgsnd_perm);
340
341         return atf_no_error();
342 }