1 /*-
2  * Copyright (c) 2013 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Pawel Jakub Dawidek under sponsorship from
6  * the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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.
16  *
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
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/wait.h>
35 #include <sys/nv.h>
36 
37 #include <err.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <unistd.h>
43 
44 static int ntest = 1;
45 
46 #define	CHECK(expr)	do {						\
47 	if ((expr))							\
48 		printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__);	\
49 	else								\
50 		printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
51 	ntest++;							\
52 } while (0)
53 
54 #define	fd_is_valid(fd)	(fcntl((fd), F_GETFL) != -1 || errno != EBADF)
55 
56 static void
57 child(int sock)
58 {
59 	nvlist_t *nvl;
60 	nvlist_t *empty;
61 
62 	nvl = nvlist_create(0);
63 	empty = nvlist_create(0);
64 
65 	nvlist_add_bool(nvl, "nvlist/bool/true", true);
66 	nvlist_add_bool(nvl, "nvlist/bool/false", false);
67 	nvlist_add_number(nvl, "nvlist/number/0", 0);
68 	nvlist_add_number(nvl, "nvlist/number/1", 1);
69 	nvlist_add_number(nvl, "nvlist/number/-1", -1);
70 	nvlist_add_number(nvl, "nvlist/number/UINT64_MAX", UINT64_MAX);
71 	nvlist_add_number(nvl, "nvlist/number/INT64_MIN", INT64_MIN);
72 	nvlist_add_number(nvl, "nvlist/number/INT64_MAX", INT64_MAX);
73 	nvlist_add_string(nvl, "nvlist/string/", "");
74 	nvlist_add_string(nvl, "nvlist/string/x", "x");
75 	nvlist_add_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz");
76 	nvlist_add_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO", STDERR_FILENO);
77 	nvlist_add_binary(nvl, "nvlist/binary/x", "x", 1);
78 	nvlist_add_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz"));
79 	nvlist_move_nvlist(nvl, "nvlist/nvlist/empty", empty);
80 	nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
81 
82 	nvlist_send(sock, nvl);
83 
84 	nvlist_destroy(nvl);
85 }
86 
87 static void
88 parent(int sock)
89 {
90 	nvlist_t *nvl;
91 	const nvlist_t *cnvl, *empty;
92 	const char *name, *cname;
93 	void *cookie, *ccookie;
94 	int type, ctype;
95 	size_t size;
96 
97 	nvl = nvlist_recv(sock, 0);
98 	CHECK(nvlist_error(nvl) == 0);
99 	if (nvlist_error(nvl) != 0)
100 		err(1, "nvlist_recv() failed");
101 
102 	cookie = NULL;
103 
104 	name = nvlist_next(nvl, &type, &cookie);
105 	CHECK(name != NULL);
106 	CHECK(type == NV_TYPE_BOOL);
107 	CHECK(strcmp(name, "nvlist/bool/true") == 0);
108 	CHECK(nvlist_get_bool(nvl, name) == true);
109 
110 	name = nvlist_next(nvl, &type, &cookie);
111 	CHECK(name != NULL);
112 	CHECK(type == NV_TYPE_BOOL);
113 	CHECK(strcmp(name, "nvlist/bool/false") == 0);
114 	CHECK(nvlist_get_bool(nvl, name) == false);
115 
116 	name = nvlist_next(nvl, &type, &cookie);
117 	CHECK(name != NULL);
118 	CHECK(type == NV_TYPE_NUMBER);
119 	CHECK(strcmp(name, "nvlist/number/0") == 0);
120 	CHECK(nvlist_get_number(nvl, name) == 0);
121 
122 	name = nvlist_next(nvl, &type, &cookie);
123 	CHECK(name != NULL);
124 	CHECK(type == NV_TYPE_NUMBER);
125 	CHECK(strcmp(name, "nvlist/number/1") == 0);
126 	CHECK(nvlist_get_number(nvl, name) == 1);
127 
128 	name = nvlist_next(nvl, &type, &cookie);
129 	CHECK(name != NULL);
130 	CHECK(type == NV_TYPE_NUMBER);
131 	CHECK(strcmp(name, "nvlist/number/-1") == 0);
132 	CHECK((int)nvlist_get_number(nvl, name) == -1);
133 
134 	name = nvlist_next(nvl, &type, &cookie);
135 	CHECK(name != NULL);
136 	CHECK(type == NV_TYPE_NUMBER);
137 	CHECK(strcmp(name, "nvlist/number/UINT64_MAX") == 0);
138 	CHECK(nvlist_get_number(nvl, name) == UINT64_MAX);
139 
140 	name = nvlist_next(nvl, &type, &cookie);
141 	CHECK(name != NULL);
142 	CHECK(type == NV_TYPE_NUMBER);
143 	CHECK(strcmp(name, "nvlist/number/INT64_MIN") == 0);
144 	CHECK((int64_t)nvlist_get_number(nvl, name) == INT64_MIN);
145 
146 	name = nvlist_next(nvl, &type, &cookie);
147 	CHECK(name != NULL);
148 	CHECK(type == NV_TYPE_NUMBER);
149 	CHECK(strcmp(name, "nvlist/number/INT64_MAX") == 0);
150 	CHECK((int64_t)nvlist_get_number(nvl, name) == INT64_MAX);
151 
152 	name = nvlist_next(nvl, &type, &cookie);
153 	CHECK(name != NULL);
154 	CHECK(type == NV_TYPE_STRING);
155 	CHECK(strcmp(name, "nvlist/string/") == 0);
156 	CHECK(strcmp(nvlist_get_string(nvl, name), "") == 0);
157 
158 	name = nvlist_next(nvl, &type, &cookie);
159 	CHECK(name != NULL);
160 	CHECK(type == NV_TYPE_STRING);
161 	CHECK(strcmp(name, "nvlist/string/x") == 0);
162 	CHECK(strcmp(nvlist_get_string(nvl, name), "x") == 0);
163 
164 	name = nvlist_next(nvl, &type, &cookie);
165 	CHECK(name != NULL);
166 	CHECK(type == NV_TYPE_STRING);
167 	CHECK(strcmp(name, "nvlist/string/abcdefghijklmnopqrstuvwxyz") == 0);
168 	CHECK(strcmp(nvlist_get_string(nvl, name), "abcdefghijklmnopqrstuvwxyz") == 0);
169 
170 	name = nvlist_next(nvl, &type, &cookie);
171 	CHECK(name != NULL);
172 	CHECK(type == NV_TYPE_DESCRIPTOR);
173 	CHECK(strcmp(name, "nvlist/descriptor/STDERR_FILENO") == 0);
174 	CHECK(fd_is_valid(nvlist_get_descriptor(nvl, name)));
175 
176 	name = nvlist_next(nvl, &type, &cookie);
177 	CHECK(name != NULL);
178 	CHECK(type == NV_TYPE_BINARY);
179 	CHECK(strcmp(name, "nvlist/binary/x") == 0);
180 	CHECK(memcmp(nvlist_get_binary(nvl, name, NULL), "x", 1) == 0);
181 	CHECK(memcmp(nvlist_get_binary(nvl, name, &size), "x", 1) == 0);
182 	CHECK(size == 1);
183 
184 	name = nvlist_next(nvl, &type, &cookie);
185 	CHECK(name != NULL);
186 	CHECK(type == NV_TYPE_BINARY);
187 	CHECK(strcmp(name, "nvlist/binary/abcdefghijklmnopqrstuvwxyz") == 0);
188 	CHECK(memcmp(nvlist_get_binary(nvl, name, NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
189 	CHECK(memcmp(nvlist_get_binary(nvl, name, &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
190 	CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
191 
192 	name = nvlist_next(nvl, &type, &cookie);
193 	CHECK(name != NULL);
194 	CHECK(type == NV_TYPE_NVLIST);
195 	CHECK(strcmp(name, "nvlist/nvlist/empty") == 0);
196 	cnvl = nvlist_get_nvlist(nvl, name);
197 	CHECK(nvlist_empty(cnvl));
198 
199 	name = nvlist_next(nvl, &type, &cookie);
200 	CHECK(name != NULL);
201 	CHECK(type == NV_TYPE_NVLIST);
202 	CHECK(strcmp(name, "nvlist/nvlist") == 0);
203 	cnvl = nvlist_get_nvlist(nvl, name);
204 
205 	ccookie = NULL;
206 
207 	cname = nvlist_next(cnvl, &ctype, &ccookie);
208 	CHECK(cname != NULL);
209 	CHECK(ctype == NV_TYPE_BOOL);
210 	CHECK(strcmp(cname, "nvlist/bool/true") == 0);
211 	CHECK(nvlist_get_bool(cnvl, cname) == true);
212 
213 	cname = nvlist_next(cnvl, &ctype, &ccookie);
214 	CHECK(cname != NULL);
215 	CHECK(ctype == NV_TYPE_BOOL);
216 	CHECK(strcmp(cname, "nvlist/bool/false") == 0);
217 	CHECK(nvlist_get_bool(cnvl, cname) == false);
218 
219 	cname = nvlist_next(cnvl, &ctype, &ccookie);
220 	CHECK(cname != NULL);
221 	CHECK(ctype == NV_TYPE_NUMBER);
222 	CHECK(strcmp(cname, "nvlist/number/0") == 0);
223 	CHECK(nvlist_get_number(cnvl, cname) == 0);
224 
225 	cname = nvlist_next(cnvl, &ctype, &ccookie);
226 	CHECK(cname != NULL);
227 	CHECK(ctype == NV_TYPE_NUMBER);
228 	CHECK(strcmp(cname, "nvlist/number/1") == 0);
229 	CHECK(nvlist_get_number(cnvl, cname) == 1);
230 
231 	cname = nvlist_next(cnvl, &ctype, &ccookie);
232 	CHECK(cname != NULL);
233 	CHECK(ctype == NV_TYPE_NUMBER);
234 	CHECK(strcmp(cname, "nvlist/number/-1") == 0);
235 	CHECK((int)nvlist_get_number(cnvl, cname) == -1);
236 
237 	cname = nvlist_next(cnvl, &ctype, &ccookie);
238 	CHECK(cname != NULL);
239 	CHECK(ctype == NV_TYPE_NUMBER);
240 	CHECK(strcmp(cname, "nvlist/number/UINT64_MAX") == 0);
241 	CHECK(nvlist_get_number(cnvl, cname) == UINT64_MAX);
242 
243 	cname = nvlist_next(cnvl, &ctype, &ccookie);
244 	CHECK(cname != NULL);
245 	CHECK(ctype == NV_TYPE_NUMBER);
246 	CHECK(strcmp(cname, "nvlist/number/INT64_MIN") == 0);
247 	CHECK((int64_t)nvlist_get_number(cnvl, cname) == INT64_MIN);
248 
249 	cname = nvlist_next(cnvl, &ctype, &ccookie);
250 	CHECK(cname != NULL);
251 	CHECK(ctype == NV_TYPE_NUMBER);
252 	CHECK(strcmp(cname, "nvlist/number/INT64_MAX") == 0);
253 	CHECK((int64_t)nvlist_get_number(cnvl, cname) == INT64_MAX);
254 
255 	cname = nvlist_next(cnvl, &ctype, &ccookie);
256 	CHECK(cname != NULL);
257 	CHECK(ctype == NV_TYPE_STRING);
258 	CHECK(strcmp(cname, "nvlist/string/") == 0);
259 	CHECK(strcmp(nvlist_get_string(cnvl, cname), "") == 0);
260 
261 	cname = nvlist_next(cnvl, &ctype, &ccookie);
262 	CHECK(cname != NULL);
263 	CHECK(ctype == NV_TYPE_STRING);
264 	CHECK(strcmp(cname, "nvlist/string/x") == 0);
265 	CHECK(strcmp(nvlist_get_string(cnvl, cname), "x") == 0);
266 
267 	cname = nvlist_next(cnvl, &ctype, &ccookie);
268 	CHECK(cname != NULL);
269 	CHECK(ctype == NV_TYPE_STRING);
270 	CHECK(strcmp(cname, "nvlist/string/abcdefghijklmnopqrstuvwxyz") == 0);
271 	CHECK(strcmp(nvlist_get_string(cnvl, cname), "abcdefghijklmnopqrstuvwxyz") == 0);
272 
273 	cname = nvlist_next(cnvl, &ctype, &ccookie);
274 	CHECK(cname != NULL);
275 	CHECK(ctype == NV_TYPE_DESCRIPTOR);
276 	CHECK(strcmp(cname, "nvlist/descriptor/STDERR_FILENO") == 0);
277 	CHECK(fd_is_valid(nvlist_get_descriptor(cnvl, cname)));
278 
279 	cname = nvlist_next(cnvl, &ctype, &ccookie);
280 	CHECK(cname != NULL);
281 	CHECK(ctype == NV_TYPE_BINARY);
282 	CHECK(strcmp(cname, "nvlist/binary/x") == 0);
283 	CHECK(memcmp(nvlist_get_binary(cnvl, cname, NULL), "x", 1) == 0);
284 	CHECK(memcmp(nvlist_get_binary(cnvl, cname, &size), "x", 1) == 0);
285 	CHECK(size == 1);
286 
287 	cname = nvlist_next(cnvl, &ctype, &ccookie);
288 	CHECK(cname != NULL);
289 	CHECK(ctype == NV_TYPE_BINARY);
290 	CHECK(strcmp(cname, "nvlist/binary/abcdefghijklmnopqrstuvwxyz") == 0);
291 	CHECK(memcmp(nvlist_get_binary(cnvl, cname, NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
292 	CHECK(memcmp(nvlist_get_binary(cnvl, cname, &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
293 	CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
294 
295 	cname = nvlist_next(cnvl, &ctype, &ccookie);
296 	CHECK(cname != NULL);
297 	CHECK(ctype == NV_TYPE_NVLIST);
298 	CHECK(strcmp(cname, "nvlist/nvlist/empty") == 0);
299 	empty = nvlist_get_nvlist(cnvl, cname);
300 	CHECK(nvlist_empty(empty));
301 
302 	cname = nvlist_next(cnvl, &ctype, &ccookie);
303 	CHECK(cname == NULL);
304 
305 	name = nvlist_next(nvl, &type, &cookie);
306 	CHECK(name == NULL);
307 
308 	nvlist_destroy(nvl);
309 }
310 
311 static void
312 send_nvlist(void)
313 {
314 	int status, socks[2];
315 	pid_t pid;
316 
317 	if (socketpair(PF_UNIX, SOCK_STREAM, 0, socks) < 0)
318 		err(1, "socketpair() failed");
319 	pid = fork();
320 	switch (pid) {
321 	case -1:
322 		/* Failure. */
323 		err(1, "unable to fork");
324 	case 0:
325 		/* Child. */
326 		close(socks[0]);
327 		child(socks[1]);
328 		_exit(0);
329 	default:
330 		/* Parent. */
331 		close(socks[1]);
332 		parent(socks[0]);
333 		break;
334 	}
335 
336 	if (waitpid(pid, &status, 0) < 0)
337 		err(1, "waitpid() failed");
338 }
339 
340 static void
341 send_closed_fd(void)
342 {
343 	nvlist_t *nvl;
344 	int error, socks[2];
345 
346 	if (socketpair(PF_UNIX, SOCK_STREAM, 0, socks) < 0)
347 		err(1, "socketpair() failed");
348 
349 	nvl = nvlist_create(0);
350 	nvlist_add_descriptor(nvl, "fd", 12345);
351 	error = nvlist_error(nvl);
352 	CHECK(error == EBADF);
353 
354 	error = nvlist_send(socks[1], nvl);
355 	CHECK(error != 0 && errno == EBADF);
356 }
357 
358 int
359 main(void)
360 {
361 
362 	printf("1..136\n");
363 	fflush(stdout);
364 
365 	send_nvlist();
366 	send_closed_fd();
367 
368 	return (0);
369 }
370