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