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