2 * Copyright (c) 2013 The FreeBSD Foundation
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/socket.h>
35 #include <sys/sysctl.h>
50 #define ALPHABET "abcdefghijklmnopqrstuvwxyz"
51 #define fd_is_valid(fd) (fcntl((fd), F_GETFL) != -1 || errno != EBADF)
54 send_nvlist_child(int sock)
60 nvl = nvlist_create(0);
61 empty = nvlist_create(0);
63 nvlist_add_bool(nvl, "nvlist/bool/true", true);
64 nvlist_add_bool(nvl, "nvlist/bool/false", false);
65 nvlist_add_number(nvl, "nvlist/number/0", 0);
66 nvlist_add_number(nvl, "nvlist/number/1", 1);
67 nvlist_add_number(nvl, "nvlist/number/-1", -1);
68 nvlist_add_number(nvl, "nvlist/number/UINT64_MAX", UINT64_MAX);
69 nvlist_add_number(nvl, "nvlist/number/INT64_MIN", INT64_MIN);
70 nvlist_add_number(nvl, "nvlist/number/INT64_MAX", INT64_MAX);
71 nvlist_add_string(nvl, "nvlist/string/", "");
72 nvlist_add_string(nvl, "nvlist/string/x", "x");
73 nvlist_add_string(nvl, "nvlist/string/" ALPHABET, ALPHABET);
75 nvlist_add_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO",
78 err(EXIT_FAILURE, "pipe");
79 if (write(pfd[1], "test", 4) != 4)
80 err(EXIT_FAILURE, "write");
82 nvlist_add_descriptor(nvl, "nvlist/descriptor/pipe_rd", pfd[0]);
85 nvlist_add_binary(nvl, "nvlist/binary/x", "x", 1);
86 nvlist_add_binary(nvl, "nvlist/binary/" ALPHABET, ALPHABET,
88 nvlist_move_nvlist(nvl, "nvlist/nvlist/empty", empty);
89 nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
91 nvlist_send(sock, nvl);
97 send_nvlist_parent(int sock)
100 const nvlist_t *cnvl, *empty;
101 const char *name, *cname;
102 void *cookie, *ccookie;
107 nvl = nvlist_recv(sock, 0);
108 ATF_REQUIRE(nvlist_error(nvl) == 0);
109 if (nvlist_error(nvl) != 0)
110 err(1, "nvlist_recv() failed");
114 name = nvlist_next(nvl, &type, &cookie);
115 ATF_REQUIRE(name != NULL);
116 ATF_REQUIRE(type == NV_TYPE_BOOL);
117 ATF_REQUIRE(strcmp(name, "nvlist/bool/true") == 0);
118 ATF_REQUIRE(nvlist_get_bool(nvl, name) == true);
120 name = nvlist_next(nvl, &type, &cookie);
121 ATF_REQUIRE(name != NULL);
122 ATF_REQUIRE(type == NV_TYPE_BOOL);
123 ATF_REQUIRE(strcmp(name, "nvlist/bool/false") == 0);
124 ATF_REQUIRE(nvlist_get_bool(nvl, name) == false);
126 name = nvlist_next(nvl, &type, &cookie);
127 ATF_REQUIRE(name != NULL);
128 ATF_REQUIRE(type == NV_TYPE_NUMBER);
129 ATF_REQUIRE(strcmp(name, "nvlist/number/0") == 0);
130 ATF_REQUIRE(nvlist_get_number(nvl, name) == 0);
132 name = nvlist_next(nvl, &type, &cookie);
133 ATF_REQUIRE(name != NULL);
134 ATF_REQUIRE(type == NV_TYPE_NUMBER);
135 ATF_REQUIRE(strcmp(name, "nvlist/number/1") == 0);
136 ATF_REQUIRE(nvlist_get_number(nvl, name) == 1);
138 name = nvlist_next(nvl, &type, &cookie);
139 ATF_REQUIRE(name != NULL);
140 ATF_REQUIRE(type == NV_TYPE_NUMBER);
141 ATF_REQUIRE(strcmp(name, "nvlist/number/-1") == 0);
142 ATF_REQUIRE((int)nvlist_get_number(nvl, name) == -1);
144 name = nvlist_next(nvl, &type, &cookie);
145 ATF_REQUIRE(name != NULL);
146 ATF_REQUIRE(type == NV_TYPE_NUMBER);
147 ATF_REQUIRE(strcmp(name, "nvlist/number/UINT64_MAX") == 0);
148 ATF_REQUIRE(nvlist_get_number(nvl, name) == UINT64_MAX);
150 name = nvlist_next(nvl, &type, &cookie);
151 ATF_REQUIRE(name != NULL);
152 ATF_REQUIRE(type == NV_TYPE_NUMBER);
153 ATF_REQUIRE(strcmp(name, "nvlist/number/INT64_MIN") == 0);
154 ATF_REQUIRE((int64_t)nvlist_get_number(nvl, name) == INT64_MIN);
156 name = nvlist_next(nvl, &type, &cookie);
157 ATF_REQUIRE(name != NULL);
158 ATF_REQUIRE(type == NV_TYPE_NUMBER);
159 ATF_REQUIRE(strcmp(name, "nvlist/number/INT64_MAX") == 0);
160 ATF_REQUIRE((int64_t)nvlist_get_number(nvl, name) == INT64_MAX);
162 name = nvlist_next(nvl, &type, &cookie);
163 ATF_REQUIRE(name != NULL);
164 ATF_REQUIRE(type == NV_TYPE_STRING);
165 ATF_REQUIRE(strcmp(name, "nvlist/string/") == 0);
166 ATF_REQUIRE(strcmp(nvlist_get_string(nvl, name), "") == 0);
168 name = nvlist_next(nvl, &type, &cookie);
169 ATF_REQUIRE(name != NULL);
170 ATF_REQUIRE(type == NV_TYPE_STRING);
171 ATF_REQUIRE(strcmp(name, "nvlist/string/x") == 0);
172 ATF_REQUIRE(strcmp(nvlist_get_string(nvl, name), "x") == 0);
174 name = nvlist_next(nvl, &type, &cookie);
175 ATF_REQUIRE(name != NULL);
176 ATF_REQUIRE(type == NV_TYPE_STRING);
177 ATF_REQUIRE(strcmp(name, "nvlist/string/" ALPHABET) == 0);
178 ATF_REQUIRE(strcmp(nvlist_get_string(nvl, name), ALPHABET) == 0);
180 name = nvlist_next(nvl, &type, &cookie);
181 ATF_REQUIRE(name != NULL);
182 ATF_REQUIRE(type == NV_TYPE_DESCRIPTOR);
183 ATF_REQUIRE(strcmp(name, "nvlist/descriptor/STDERR_FILENO") == 0);
184 ATF_REQUIRE(fd_is_valid(nvlist_get_descriptor(nvl, name)));
186 name = nvlist_next(nvl, &type, &cookie);
187 ATF_REQUIRE(name != NULL);
188 ATF_REQUIRE(type == NV_TYPE_DESCRIPTOR);
189 ATF_REQUIRE(strcmp(name, "nvlist/descriptor/pipe_rd") == 0);
190 fd = nvlist_get_descriptor(nvl, name);
191 ATF_REQUIRE(fd_is_valid(fd));
192 ATF_REQUIRE(read(fd, buf, sizeof(buf)) == 4);
193 ATF_REQUIRE(strncmp(buf, "test", sizeof(buf)) == 0);
195 name = nvlist_next(nvl, &type, &cookie);
196 ATF_REQUIRE(name != NULL);
197 ATF_REQUIRE(type == NV_TYPE_BINARY);
198 ATF_REQUIRE(strcmp(name, "nvlist/binary/x") == 0);
199 ATF_REQUIRE(memcmp(nvlist_get_binary(nvl, name, NULL), "x", 1) == 0);
200 ATF_REQUIRE(memcmp(nvlist_get_binary(nvl, name, &size), "x", 1) == 0);
201 ATF_REQUIRE(size == 1);
203 name = nvlist_next(nvl, &type, &cookie);
204 ATF_REQUIRE(name != NULL);
205 ATF_REQUIRE(type == NV_TYPE_BINARY);
206 ATF_REQUIRE(strcmp(name, "nvlist/binary/" ALPHABET) == 0);
207 ATF_REQUIRE(memcmp(nvlist_get_binary(nvl, name, NULL), ALPHABET,
208 sizeof(ALPHABET)) == 0);
209 ATF_REQUIRE(memcmp(nvlist_get_binary(nvl, name, &size), ALPHABET,
210 sizeof(ALPHABET)) == 0);
211 ATF_REQUIRE(size == sizeof(ALPHABET));
213 name = nvlist_next(nvl, &type, &cookie);
214 ATF_REQUIRE(name != NULL);
215 ATF_REQUIRE(type == NV_TYPE_NVLIST);
216 ATF_REQUIRE(strcmp(name, "nvlist/nvlist/empty") == 0);
217 cnvl = nvlist_get_nvlist(nvl, name);
218 ATF_REQUIRE(nvlist_empty(cnvl));
220 name = nvlist_next(nvl, &type, &cookie);
221 ATF_REQUIRE(name != NULL);
222 ATF_REQUIRE(type == NV_TYPE_NVLIST);
223 ATF_REQUIRE(strcmp(name, "nvlist/nvlist") == 0);
224 cnvl = nvlist_get_nvlist(nvl, name);
228 cname = nvlist_next(cnvl, &ctype, &ccookie);
229 ATF_REQUIRE(cname != NULL);
230 ATF_REQUIRE(ctype == NV_TYPE_BOOL);
231 ATF_REQUIRE(strcmp(cname, "nvlist/bool/true") == 0);
232 ATF_REQUIRE(nvlist_get_bool(cnvl, cname) == true);
234 cname = nvlist_next(cnvl, &ctype, &ccookie);
235 ATF_REQUIRE(cname != NULL);
236 ATF_REQUIRE(ctype == NV_TYPE_BOOL);
237 ATF_REQUIRE(strcmp(cname, "nvlist/bool/false") == 0);
238 ATF_REQUIRE(nvlist_get_bool(cnvl, cname) == false);
240 cname = nvlist_next(cnvl, &ctype, &ccookie);
241 ATF_REQUIRE(cname != NULL);
242 ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
243 ATF_REQUIRE(strcmp(cname, "nvlist/number/0") == 0);
244 ATF_REQUIRE(nvlist_get_number(cnvl, cname) == 0);
246 cname = nvlist_next(cnvl, &ctype, &ccookie);
247 ATF_REQUIRE(cname != NULL);
248 ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
249 ATF_REQUIRE(strcmp(cname, "nvlist/number/1") == 0);
250 ATF_REQUIRE(nvlist_get_number(cnvl, cname) == 1);
252 cname = nvlist_next(cnvl, &ctype, &ccookie);
253 ATF_REQUIRE(cname != NULL);
254 ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
255 ATF_REQUIRE(strcmp(cname, "nvlist/number/-1") == 0);
256 ATF_REQUIRE((int)nvlist_get_number(cnvl, cname) == -1);
258 cname = nvlist_next(cnvl, &ctype, &ccookie);
259 ATF_REQUIRE(cname != NULL);
260 ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
261 ATF_REQUIRE(strcmp(cname, "nvlist/number/UINT64_MAX") == 0);
262 ATF_REQUIRE(nvlist_get_number(cnvl, cname) == UINT64_MAX);
264 cname = nvlist_next(cnvl, &ctype, &ccookie);
265 ATF_REQUIRE(cname != NULL);
266 ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
267 ATF_REQUIRE(strcmp(cname, "nvlist/number/INT64_MIN") == 0);
268 ATF_REQUIRE((int64_t)nvlist_get_number(cnvl, cname) == INT64_MIN);
270 cname = nvlist_next(cnvl, &ctype, &ccookie);
271 ATF_REQUIRE(cname != NULL);
272 ATF_REQUIRE(ctype == NV_TYPE_NUMBER);
273 ATF_REQUIRE(strcmp(cname, "nvlist/number/INT64_MAX") == 0);
274 ATF_REQUIRE((int64_t)nvlist_get_number(cnvl, cname) == INT64_MAX);
276 cname = nvlist_next(cnvl, &ctype, &ccookie);
277 ATF_REQUIRE(cname != NULL);
278 ATF_REQUIRE(ctype == NV_TYPE_STRING);
279 ATF_REQUIRE(strcmp(cname, "nvlist/string/") == 0);
280 ATF_REQUIRE(strcmp(nvlist_get_string(cnvl, cname), "") == 0);
282 cname = nvlist_next(cnvl, &ctype, &ccookie);
283 ATF_REQUIRE(cname != NULL);
284 ATF_REQUIRE(ctype == NV_TYPE_STRING);
285 ATF_REQUIRE(strcmp(cname, "nvlist/string/x") == 0);
286 ATF_REQUIRE(strcmp(nvlist_get_string(cnvl, cname), "x") == 0);
288 cname = nvlist_next(cnvl, &ctype, &ccookie);
289 ATF_REQUIRE(cname != NULL);
290 ATF_REQUIRE(ctype == NV_TYPE_STRING);
291 ATF_REQUIRE(strcmp(cname, "nvlist/string/" ALPHABET) == 0);
292 ATF_REQUIRE(strcmp(nvlist_get_string(cnvl, cname), ALPHABET) == 0);
294 cname = nvlist_next(cnvl, &ctype, &ccookie);
295 ATF_REQUIRE(cname != NULL);
296 ATF_REQUIRE(ctype == NV_TYPE_DESCRIPTOR);
297 ATF_REQUIRE(strcmp(cname, "nvlist/descriptor/STDERR_FILENO") == 0);
298 ATF_REQUIRE(fd_is_valid(nvlist_get_descriptor(cnvl, cname)));
300 cname = nvlist_next(cnvl, &ctype, &ccookie);
301 ATF_REQUIRE(cname != NULL);
302 ATF_REQUIRE(ctype == NV_TYPE_DESCRIPTOR);
303 ATF_REQUIRE(strcmp(cname, "nvlist/descriptor/pipe_rd") == 0);
304 ATF_REQUIRE(fd_is_valid(nvlist_get_descriptor(cnvl, cname)));
306 cname = nvlist_next(cnvl, &ctype, &ccookie);
307 ATF_REQUIRE(cname != NULL);
308 ATF_REQUIRE(ctype == NV_TYPE_BINARY);
309 ATF_REQUIRE(strcmp(cname, "nvlist/binary/x") == 0);
310 ATF_REQUIRE(memcmp(nvlist_get_binary(cnvl, cname, NULL), "x", 1) == 0);
311 ATF_REQUIRE(memcmp(nvlist_get_binary(cnvl, cname, &size), "x", 1) == 0);
312 ATF_REQUIRE(size == 1);
314 cname = nvlist_next(cnvl, &ctype, &ccookie);
315 ATF_REQUIRE(cname != NULL);
316 ATF_REQUIRE(ctype == NV_TYPE_BINARY);
317 ATF_REQUIRE(strcmp(cname, "nvlist/binary/" ALPHABET) == 0);
318 ATF_REQUIRE(memcmp(nvlist_get_binary(cnvl, cname, NULL), ALPHABET,
319 sizeof(ALPHABET)) == 0);
320 ATF_REQUIRE(memcmp(nvlist_get_binary(cnvl, cname, &size), ALPHABET,
321 sizeof(ALPHABET)) == 0);
322 ATF_REQUIRE(size == sizeof(ALPHABET));
324 cname = nvlist_next(cnvl, &ctype, &ccookie);
325 ATF_REQUIRE(cname != NULL);
326 ATF_REQUIRE(ctype == NV_TYPE_NVLIST);
327 ATF_REQUIRE(strcmp(cname, "nvlist/nvlist/empty") == 0);
328 empty = nvlist_get_nvlist(cnvl, cname);
329 ATF_REQUIRE(nvlist_empty(empty));
331 cname = nvlist_next(cnvl, &ctype, &ccookie);
332 ATF_REQUIRE(cname == NULL);
334 name = nvlist_next(nvl, &type, &cookie);
335 ATF_REQUIRE(name == NULL);
340 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__send_nvlist);
341 ATF_TC_BODY(nvlist_send_recv__send_nvlist, tc)
343 int socks[2], status;
346 ATF_REQUIRE(socketpair(PF_UNIX, SOCK_STREAM, 0, socks) == 0);
349 ATF_REQUIRE(pid >= 0);
352 (void)close(socks[0]);
353 send_nvlist_child(socks[1]);
357 (void)close(socks[1]);
358 send_nvlist_parent(socks[0]);
360 ATF_REQUIRE(waitpid(pid, &status, 0) == pid);
361 ATF_REQUIRE(status == 0);
364 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__send_closed_fd);
365 ATF_TC_BODY(nvlist_send_recv__send_closed_fd, tc)
370 ATF_REQUIRE(socketpair(PF_UNIX, SOCK_STREAM, 0, socks) == 0);
372 nvl = nvlist_create(0);
373 ATF_REQUIRE(nvl != NULL);
374 nvlist_add_descriptor(nvl, "fd", 12345);
375 ATF_REQUIRE(nvlist_error(nvl) == EBADF);
377 ATF_REQUIRE_ERRNO(EBADF, nvlist_send(socks[1], nvl) != 0);
384 int error, mib[4], n;
388 mib[2] = KERN_PROC_NFDS;
392 error = sysctl(mib, nitems(mib), &n, &len, NULL, 0);
401 send_many_fds_child(int sock)
405 int anfds, bnfds, fd, i, j;
407 fd = open(_PATH_DEVNULL, O_RDONLY);
408 ATF_REQUIRE(fd >= 0);
410 for (i = 1; i < NFDS; i++) {
411 nvl = nvlist_create(0);
414 err(EXIT_FAILURE, "sysctl");
416 for (j = 0; j < i; j++) {
417 snprintf(name, sizeof(name), "fd%d", j);
418 nvlist_add_descriptor(nvl, name, fd);
420 nvlist_send(sock, nvl);
425 err(EXIT_FAILURE, "sysctl");
427 errx(EXIT_FAILURE, "fd count mismatch");
431 ATF_TC_WITHOUT_HEAD(nvlist_send_recv__send_many_fds);
432 ATF_TC_BODY(nvlist_send_recv__send_many_fds, tc)
436 int anfds, bnfds, fd, i, j, socks[2], status;
439 ATF_REQUIRE(socketpair(PF_UNIX, SOCK_STREAM, 0, socks) == 0);
442 ATF_REQUIRE(pid >= 0);
445 (void)close(socks[0]);
446 send_many_fds_child(socks[1]);
450 (void)close(socks[1]);
452 for (i = 1; i < NFDS; i++) {
454 ATF_REQUIRE(bnfds != -1);
456 nvl = nvlist_recv(socks[0], 0);
457 ATF_REQUIRE(nvl != NULL);
458 for (j = 0; j < i; j++) {
459 snprintf(name, sizeof(name), "fd%d", j);
460 fd = nvlist_take_descriptor(nvl, name);
461 ATF_REQUIRE(close(fd) == 0);
466 ATF_REQUIRE(anfds != -1);
467 ATF_REQUIRE(anfds == bnfds);
470 ATF_REQUIRE(waitpid(pid, &status, 0) == pid);
471 ATF_REQUIRE(status == 0);
477 ATF_TP_ADD_TC(tp, nvlist_send_recv__send_nvlist);
478 ATF_TP_ADD_TC(tp, nvlist_send_recv__send_closed_fd);
479 ATF_TP_ADD_TC(tp, nvlist_send_recv__send_many_fds);
481 return (atf_no_error());