1 /*- 2 * Copyright (c) 2007 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 /* 28 * A few regression tests for UNIX domain sockets. Run from single-user mode 29 * as it checks the openfiles sysctl to look for leaks, and we don't want that 30 * changing due to other processes doing stuff. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/signal.h> 35 #include <sys/socket.h> 36 #include <sys/sysctl.h> 37 #include <sys/un.h> 38 #include <sys/wait.h> 39 40 #include <netinet/in.h> 41 42 #include <err.h> 43 #include <errno.h> 44 #include <fcntl.h> 45 #include <limits.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <unistd.h> 50 51 static int forcegc = 1; 52 static char dpath[PATH_MAX]; 53 static const char *test; 54 55 static int 56 getsysctl(const char *name) 57 { 58 size_t len; 59 int i; 60 61 len = sizeof(i); 62 if (sysctlbyname(name, &i, &len, NULL, 0) < 0) 63 err(-1, "%s", name); 64 return (i); 65 } 66 67 static int 68 getopenfiles(void) 69 { 70 71 return (getsysctl("kern.openfiles")); 72 } 73 74 static int 75 getinflight(void) 76 { 77 78 return (getsysctl("net.local.inflight")); 79 } 80 81 static int 82 getdeferred(void) 83 { 84 85 return (getsysctl("net.local.deferred")); 86 } 87 88 static void 89 sendfd(int fd, int fdtosend) 90 { 91 struct msghdr mh; 92 struct message { struct cmsghdr msg_hdr; int fd; } m; 93 ssize_t len; 94 int after_inflight, before_inflight; 95 96 before_inflight = getinflight(); 97 98 bzero(&mh, sizeof(mh)); 99 bzero(&m, sizeof(m)); 100 mh.msg_control = &m; 101 mh.msg_controllen = sizeof(m); 102 m.msg_hdr.cmsg_len = sizeof(m); 103 m.msg_hdr.cmsg_level = SOL_SOCKET; 104 m.msg_hdr.cmsg_type = SCM_RIGHTS; 105 m.fd = fdtosend; 106 len = sendmsg(fd, &mh, 0); 107 if (len < 0) 108 err(-1, "%s: sendmsg", test); 109 after_inflight = getinflight(); 110 if (after_inflight != before_inflight + 1) 111 errx(-1, "%s: sendfd: before %d after %d\n", test, 112 before_inflight, after_inflight); 113 } 114 115 static void 116 close2(int fd1, int fd2) 117 { 118 119 close(fd1); 120 close(fd2); 121 } 122 123 static void 124 close3(int fd1, int fd2, int fd3) 125 { 126 127 close2(fd1, fd2); 128 close(fd3); 129 } 130 131 static void 132 close4(int fd1, int fd2, int fd3, int fd4) 133 { 134 135 close2(fd1, fd2); 136 close2(fd3, fd4); 137 } 138 139 static void 140 close5(int fd1, int fd2, int fd3, int fd4, int fd5) 141 { 142 143 close3(fd1, fd2, fd3); 144 close2(fd4, fd5); 145 } 146 147 static int 148 my_socket(int domain, int type, int proto) 149 { 150 int sock; 151 152 sock = socket(domain, type, proto); 153 if (sock < 0) 154 err(-1, "%s: socket", test); 155 return (sock); 156 } 157 158 static void 159 my_bind(int sock, struct sockaddr *sa, socklen_t len) 160 { 161 162 if (bind(sock, sa, len) < 0) 163 err(-1, "%s: bind", test); 164 } 165 166 static void 167 my_connect(int sock, struct sockaddr *sa, socklen_t len) 168 { 169 170 if (connect(sock, sa, len) < 0 && errno != EINPROGRESS) 171 err(-1, "%s: connect", test); 172 } 173 174 static void 175 my_listen(int sock, int backlog) 176 { 177 178 if (listen(sock, backlog) < 0) 179 err(-1, "%s: listen", test); 180 } 181 182 static void 183 my_socketpair(int *sv) 184 { 185 186 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) 187 err(-1, "%s: socketpair", test); 188 } 189 190 static void 191 my_getsockname(int s, struct sockaddr *sa, socklen_t *salen) 192 { 193 194 if (getsockname(s, sa, salen) < 0) 195 err(-1, "%s: getsockname", test); 196 } 197 198 static void 199 setnonblock(int s) 200 { 201 202 if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) 203 err(-1, "%s: fcntl(F_SETFL, O_NONBLOCK)", test); 204 } 205 206 static void 207 alloc3fds(int *s, int *sv) 208 { 209 210 if ((*s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) 211 err(-1, "%s: socket", test); 212 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) 213 err(-1, "%s: socketpair", test); 214 } 215 216 static void 217 alloc5fds(int *s, int *sva, int *svb) 218 { 219 220 if ((*s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) 221 err(-1, "%s: socket", test); 222 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sva) < 0) 223 err(-1, "%s: socketpair", test); 224 if (socketpair(PF_UNIX, SOCK_STREAM, 0, svb) < 0) 225 err(-1, "%s: socketpair", test); 226 } 227 228 static void 229 save_sysctls(int *before_inflight, int *before_openfiles) 230 { 231 232 *before_inflight = getinflight(); 233 *before_openfiles = getopenfiles(); 234 } 235 236 /* 237 * Try hard to make sure that the GC does in fact run before we test the 238 * condition of things. 239 */ 240 static void 241 trigger_gc(void) 242 { 243 int s; 244 245 if (forcegc) { 246 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) 247 err(-1, "trigger_gc: socket"); 248 close(s); 249 } 250 sleep(1); 251 } 252 253 static void 254 test_sysctls(int before_inflight, int before_openfiles) 255 { 256 int after_inflight, after_openfiles; 257 258 trigger_gc(); 259 after_inflight = getinflight(); 260 if (after_inflight != before_inflight) 261 warnx("%s: before inflight: %d, after inflight: %d", 262 test, before_inflight, after_inflight); 263 264 after_openfiles = getopenfiles(); 265 if (after_openfiles != before_openfiles) 266 warnx("%s: before: %d, after: %d", test, before_openfiles, 267 after_openfiles); 268 } 269 270 static void 271 twosome_nothing(void) 272 { 273 int inflight, openfiles; 274 int sv[2]; 275 276 /* 277 * Create a pair, close in one order. 278 */ 279 test = "twosome_nothing1"; 280 printf("%s\n", test); 281 save_sysctls(&inflight, &openfiles); 282 my_socketpair(sv); 283 close2(sv[0], sv[1]); 284 test_sysctls(inflight, openfiles); 285 286 /* 287 * Create a pair, close in the other order. 288 */ 289 test = "twosome_nothing2"; 290 printf("%s\n", test); 291 save_sysctls(&inflight, &openfiles); 292 my_socketpair(sv); 293 close2(sv[0], sv[1]); 294 test_sysctls(inflight, openfiles); 295 } 296 297 /* 298 * Using a socket pair, send various endpoints over the pair and close in 299 * various orders. 300 */ 301 static void 302 twosome_drop_work(const char *testname, int sendvia, int tosend, int closefirst) 303 { 304 int inflight, openfiles; 305 int sv[2]; 306 307 printf("%s\n", testname); 308 test = testname; 309 save_sysctls(&inflight, &openfiles); 310 my_socketpair(sv); 311 sendfd(sv[sendvia], sv[tosend]); 312 if (closefirst == 0) 313 close2(sv[0], sv[1]); 314 else 315 close2(sv[1], sv[0]); 316 test_sysctls(inflight, openfiles); 317 } 318 319 static void 320 twosome_drop(void) 321 { 322 323 /* 324 * In various combations, some wastefully symmetric, create socket 325 * pairs and send one or another endpoint over one or another 326 * endpoint, closing the endpoints in various orders. 327 */ 328 twosome_drop_work("twosome_drop1", 0, 0, 0); 329 twosome_drop_work("twosome_drop2", 0, 0, 1); 330 twosome_drop_work("twosome_drop3", 0, 1, 0); 331 twosome_drop_work("twosome_drop4", 0, 1, 1); 332 twosome_drop_work("twosome_drop5", 1, 0, 0); 333 twosome_drop_work("twosome_drop6", 1, 0, 1); 334 twosome_drop_work("twosome_drop7", 1, 1, 0); 335 twosome_drop_work("twosome_drop8", 1, 1, 1); 336 } 337 338 static void 339 threesome_nothing(void) 340 { 341 int inflight, openfiles; 342 int s, sv[2]; 343 344 test = "threesome_nothing"; 345 printf("%s\n", test); 346 save_sysctls(&inflight, &openfiles); 347 alloc3fds(&s, sv); 348 close3(s, sv[0], sv[1]); 349 test_sysctls(inflight, openfiles); 350 } 351 352 /* 353 * threesome_drop: create a pair and a spare, send the spare over the pair, and 354 * close in various orders and make sure all the fds went away. 355 */ 356 static void 357 threesome_drop(void) 358 { 359 int inflight, openfiles; 360 int s, sv[2]; 361 362 /* 363 * threesome_drop1: close sent send receive 364 */ 365 test = "threesome_drop1"; 366 printf("%s\n", test); 367 save_sysctls(&inflight, &openfiles); 368 alloc3fds(&s, sv); 369 sendfd(sv[0], s); 370 close3(s, sv[0], sv[1]); 371 test_sysctls(inflight, openfiles); 372 373 /* 374 * threesome_drop2: close sent receive send 375 */ 376 test = "threesome_drop2"; 377 printf("%s\n", test); 378 save_sysctls(&inflight, &openfiles); 379 alloc3fds(&s, sv); 380 sendfd(sv[0], s); 381 close3(s, sv[1], sv[0]); 382 test_sysctls(inflight, openfiles); 383 384 /* 385 * threesome_drop3: close receive sent send 386 */ 387 test = "threesome_drop3"; 388 printf("%s\n", test); 389 save_sysctls(&inflight, &openfiles); 390 alloc3fds(&s, sv); 391 sendfd(sv[0], s); 392 close3(sv[1], s, sv[0]); 393 test_sysctls(inflight, openfiles); 394 395 /* 396 * threesome_drop4: close receive send sent 397 */ 398 test = "threesome_drop4"; 399 printf("%s\n", test); 400 save_sysctls(&inflight, &openfiles); 401 alloc3fds(&s, sv); 402 sendfd(sv[0], s); 403 close3(sv[1], sv[0], s); 404 test_sysctls(inflight, openfiles); 405 406 /* 407 * threesome_drop5: close send receive sent 408 */ 409 test = "threesome_drop5"; 410 printf("%s\n", test); 411 save_sysctls(&inflight, &openfiles); 412 alloc3fds(&s, sv); 413 sendfd(sv[0], s); 414 close3(sv[0], sv[1], s); 415 test_sysctls(inflight, openfiles); 416 417 /* 418 * threesome_drop6: close send sent receive 419 */ 420 test = "threesome_drop6"; 421 printf("%s\n", test); 422 save_sysctls(&inflight, &openfiles); 423 alloc3fds(&s, sv); 424 close3(sv[0], s, sv[1]); 425 test_sysctls(inflight, openfiles); 426 } 427 428 /* 429 * Fivesome tests: create two socket pairs and a spare, send the spare over 430 * the first socket pair, then send the first socket pair over the second 431 * socket pair, and GC. Do various closes at various points to exercise 432 * various cases. 433 */ 434 static void 435 fivesome_nothing(void) 436 { 437 int inflight, openfiles; 438 int spare, sva[2], svb[2]; 439 440 test = "fivesome_nothing"; 441 printf("%s\n", test); 442 save_sysctls(&inflight, &openfiles); 443 alloc5fds(&spare, sva, svb); 444 close5(spare, sva[0], sva[1], svb[0], svb[1]); 445 test_sysctls(inflight, openfiles); 446 } 447 448 static void 449 fivesome_drop_work(const char *testname, int close_spare_after_send, 450 int close_sva_after_send) 451 { 452 int inflight, openfiles; 453 int spare, sva[2], svb[2]; 454 455 printf("%s\n", testname); 456 test = testname; 457 save_sysctls(&inflight, &openfiles); 458 alloc5fds(&spare, sva, svb); 459 460 /* 461 * Send spare over sva. 462 */ 463 sendfd(sva[0], spare); 464 if (close_spare_after_send) 465 close(spare); 466 467 /* 468 * Send sva over svb. 469 */ 470 sendfd(svb[0], sva[0]); 471 sendfd(svb[0], sva[1]); 472 if (close_sva_after_send) 473 close2(sva[0], sva[1]); 474 475 close2(svb[0], svb[1]); 476 477 if (!close_sva_after_send) 478 close2(sva[0], sva[1]); 479 if (!close_spare_after_send) 480 close(spare); 481 482 test_sysctls(inflight, openfiles); 483 } 484 485 static void 486 fivesome_drop(void) 487 { 488 489 fivesome_drop_work("fivesome_drop1", 0, 0); 490 fivesome_drop_work("fivesome_drop2", 0, 1); 491 fivesome_drop_work("fivesome_drop3", 1, 0); 492 fivesome_drop_work("fivesome_drop4", 1, 1); 493 } 494 495 /* 496 * Create a somewhat nasty dual-socket socket intended to upset the garbage 497 * collector if mark-and-sweep is wrong. 498 */ 499 static void 500 complex_cycles(void) 501 { 502 int inflight, openfiles; 503 int spare, sva[2], svb[2]; 504 505 test = "complex_cycles"; 506 printf("%s\n", test); 507 save_sysctls(&inflight, &openfiles); 508 alloc5fds(&spare, sva, svb); 509 sendfd(sva[0], svb[0]); 510 sendfd(sva[0], svb[1]); 511 sendfd(svb[0], sva[0]); 512 sendfd(svb[0], sva[1]); 513 sendfd(svb[0], spare); 514 sendfd(sva[0], spare); 515 close5(spare, sva[0], sva[1], svb[0], svb[1]); 516 test_sysctls(inflight, openfiles); 517 } 518 519 /* 520 * Listen sockets can also be passed over UNIX domain sockets, so test 521 * various cases, including ones where listen sockets have waiting sockets 522 * hanging off them... 523 */ 524 static void 525 listen_nothing(void) 526 { 527 struct sockaddr_un sun; 528 struct sockaddr_in sin; 529 int inflight, openfiles; 530 int s; 531 532 test = "listen_nothing_unp"; 533 printf("%s\n", test); 534 bzero(&sun, sizeof(sun)); 535 sun.sun_family = AF_LOCAL; 536 sun.sun_len = sizeof(sun); 537 snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", dpath, test); 538 save_sysctls(&inflight, &openfiles); 539 s = my_socket(PF_LOCAL, SOCK_STREAM, 0); 540 my_bind(s, (struct sockaddr *)&sun, sizeof(sun)); 541 my_listen(s, -1); 542 close(s); 543 (void)unlink(sun.sun_path); 544 test_sysctls(inflight, openfiles); 545 546 test = "listen_nothing_inet"; 547 printf("%s\n", test); 548 bzero(&sin, sizeof(sin)); 549 sin.sin_family = AF_INET; 550 sin.sin_len = sizeof(sin); 551 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 552 sin.sin_port = htons(0); 553 save_sysctls(&inflight, &openfiles); 554 s = my_socket(PF_INET, SOCK_STREAM, 0); 555 my_bind(s, (struct sockaddr *)&sin, sizeof(sin)); 556 my_listen(s, -1); 557 close(s); 558 test_sysctls(inflight, openfiles); 559 } 560 561 /* 562 * Send a listen UDP socket over a UNIX domain socket. 563 * 564 * Send a listen TCP socket over a UNIX domain socket. 565 * 566 * Do each twice, with closing of the listen socket vs. socketpair in 567 * different orders. 568 */ 569 static void 570 listen_drop(void) 571 { 572 struct sockaddr_un sun; 573 struct sockaddr_in sin; 574 int inflight, openfiles; 575 int s, sv[2]; 576 577 bzero(&sun, sizeof(sun)); 578 sun.sun_family = AF_LOCAL; 579 sun.sun_len = sizeof(sun); 580 581 /* 582 * Close listen socket first. 583 */ 584 test = "listen_drop_unp1"; 585 printf("%s\n", test); 586 snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", dpath, test); 587 save_sysctls(&inflight, &openfiles); 588 s = my_socket(PF_LOCAL, SOCK_STREAM, 0); 589 my_bind(s, (struct sockaddr *)&sun, sizeof(sun)); 590 my_listen(s, -1); 591 my_socketpair(sv); 592 sendfd(sv[0], s); 593 close3(s, sv[0], sv[1]); 594 test_sysctls(inflight, openfiles); 595 596 /* 597 * Close socketpair first. 598 */ 599 test = "listen_drop_unp2"; 600 printf("%s\n", test); 601 snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", dpath, test); 602 save_sysctls(&inflight, &openfiles); 603 s = my_socket(PF_LOCAL, SOCK_STREAM, 0); 604 my_bind(s, (struct sockaddr *)&sun, sizeof(sun)); 605 my_listen(s, -1); 606 my_socketpair(sv); 607 sendfd(sv[0], s); 608 close3(sv[0], sv[1], s); 609 test_sysctls(inflight, openfiles); 610 611 sin.sin_family = AF_INET; 612 sin.sin_len = sizeof(sin); 613 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 614 sin.sin_port = htons(0); 615 616 /* 617 * Close listen socket first. 618 */ 619 test = "listen_drop_inet1"; 620 printf("%s\n", test); 621 bzero(&sun, sizeof(sun)); 622 save_sysctls(&inflight, &openfiles); 623 s = my_socket(PF_INET, SOCK_STREAM, 0); 624 my_bind(s, (struct sockaddr *)&sin, sizeof(sin)); 625 my_listen(s, -1); 626 my_socketpair(sv); 627 sendfd(sv[0], s); 628 close3(s, sv[0], sv[1]); 629 test_sysctls(inflight, openfiles); 630 631 /* 632 * Close socketpair first. 633 */ 634 test = "listen_drop_inet2"; 635 printf("%s\n", test); 636 bzero(&sun, sizeof(sun)); 637 save_sysctls(&inflight, &openfiles); 638 s = my_socket(PF_INET, SOCK_STREAM, 0); 639 my_bind(s, (struct sockaddr *)&sin, sizeof(sin)); 640 my_listen(s, -1); 641 my_socketpair(sv); 642 sendfd(sv[0], s); 643 close3(sv[0], sv[1], s); 644 test_sysctls(inflight, openfiles); 645 } 646 647 /* 648 * Up things a notch with listen sockets: add connections that can be 649 * accepted to the listen queues. 650 */ 651 static void 652 listen_connect_nothing(void) 653 { 654 struct sockaddr_in sin; 655 int slisten, sconnect, sv[2]; 656 int inflight, openfiles; 657 socklen_t len; 658 659 test = "listen_connect_nothing"; 660 printf("%s\n", test); 661 save_sysctls(&inflight, &openfiles); 662 663 slisten = my_socket(PF_INET, SOCK_STREAM, 0); 664 my_bind(slisten, (struct sockaddr *)&sin, sizeof(sin)); 665 my_listen(slisten, -1); 666 667 my_socketpair(sv); 668 669 len = sizeof(sin); 670 my_getsockname(slisten, (struct sockaddr *)&sin, &len); 671 672 sconnect = my_socket(PF_INET, SOCK_STREAM, 0); 673 setnonblock(sconnect); 674 my_connect(sconnect, (struct sockaddr *)&sin, len); 675 676 sleep(1); 677 678 close4(slisten, sconnect, sv[0], sv[1]); 679 680 test_sysctls(inflight, openfiles); 681 } 682 683 static void 684 listen_connect_drop(void) 685 { 686 struct sockaddr_in sin; 687 int slisten, sconnect, sv[2]; 688 int inflight, openfiles; 689 socklen_t len; 690 691 test = "listen_connect_drop"; 692 printf("%s\n", test); 693 save_sysctls(&inflight, &openfiles); 694 695 slisten = my_socket(PF_INET, SOCK_STREAM, 0); 696 my_bind(slisten, (struct sockaddr *)&sin, sizeof(sin)); 697 my_listen(slisten, -1); 698 699 my_socketpair(sv); 700 701 len = sizeof(sin); 702 my_getsockname(slisten, (struct sockaddr *)&sin, &len); 703 704 sconnect = my_socket(PF_INET, SOCK_STREAM, 0); 705 setnonblock(sconnect); 706 my_connect(sconnect, (struct sockaddr *)&sin, len); 707 708 sleep(1); 709 sendfd(sv[0], slisten); 710 close3(slisten, sv[0], sv[1]); 711 sleep(1); 712 close(sconnect); 713 714 test_sysctls(inflight, openfiles); 715 } 716 717 static void 718 recursion(void) 719 { 720 int fd[2], ff[2]; 721 int inflight, openfiles, deferred, deferred1; 722 723 test = "recursion"; 724 printf("%s\n", test); 725 save_sysctls(&inflight, &openfiles); 726 deferred = getdeferred(); 727 728 my_socketpair(fd); 729 730 for (;;) { 731 if (socketpair(PF_UNIX, SOCK_STREAM, 0, ff) == -1) { 732 if (errno == EMFILE || errno == ENFILE) 733 break; 734 err(-1, "socketpair"); 735 } 736 sendfd(ff[0], fd[0]); 737 sendfd(ff[0], fd[1]); 738 close2(fd[1], fd[0]); 739 fd[0] = ff[0]; 740 fd[1] = ff[1]; 741 } 742 close2(fd[0], fd[1]); 743 sleep(1); 744 test_sysctls(inflight, openfiles); 745 deferred1 = getdeferred(); 746 if (deferred != deferred1) 747 errx(-1, "recursion: deferred before %d after %d", deferred, 748 deferred1); 749 } 750 751 #define RMDIR "rm -Rf " 752 int 753 main(void) 754 { 755 char cmd[sizeof(RMDIR) + PATH_MAX]; 756 int serrno; 757 pid_t pid; 758 759 strlcpy(dpath, "/tmp/unpgc.XXXXXXXX", sizeof(dpath)); 760 if (mkdtemp(dpath) == NULL) 761 err(-1, "mkdtemp"); 762 763 /* 764 * Set up a parent process to GC temporary storage when we're done. 765 */ 766 pid = fork(); 767 if (pid < 0) { 768 serrno = errno; 769 (void)rmdir(dpath); 770 errno = serrno; 771 err(-1, "fork"); 772 } 773 if (pid > 0) { 774 signal(SIGINT, SIG_IGN); 775 while (waitpid(pid, NULL, 0) != pid); 776 snprintf(cmd, sizeof(cmd), "%s %s", RMDIR, dpath); 777 (void)system(cmd); 778 exit(0); 779 } 780 781 printf("Start: inflight %d open %d\n", getinflight(), 782 getopenfiles()); 783 784 twosome_nothing(); 785 twosome_drop(); 786 787 threesome_nothing(); 788 threesome_drop(); 789 790 fivesome_nothing(); 791 fivesome_drop(); 792 793 complex_cycles(); 794 795 listen_nothing(); 796 listen_drop(); 797 798 listen_connect_nothing(); 799 listen_connect_drop(); 800 801 recursion(); 802 803 printf("Finish: inflight %d open %d\n", getinflight(), 804 getopenfiles()); 805 return (0); 806 } 807