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 51static int forcegc = 1; 52static char dpath[PATH_MAX]; 53static const char *test; 54 55static int 56getsysctl(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 67static int 68getopenfiles(void) 69{ 70 71 return (getsysctl("kern.openfiles")); 72} 73 74static int 75getinflight(void) 76{ 77 78 return (getsysctl("net.local.inflight")); 79} 80 81static int 82getdeferred(void) 83{ 84 85 return (getsysctl("net.local.deferred")); 86} 87 88static void 89sendfd(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 115static void 116close2(int fd1, int fd2) 117{ 118 119 close(fd1); 120 close(fd2); 121} 122 123static void 124close3(int fd1, int fd2, int fd3) 125{ 126 127 close2(fd1, fd2); 128 close(fd3); 129} 130 131static void 132close4(int fd1, int fd2, int fd3, int fd4) 133{ 134 135 close2(fd1, fd2); 136 close2(fd3, fd4); 137} 138 139static void 140close5(int fd1, int fd2, int fd3, int fd4, int fd5) 141{ 142 143 close3(fd1, fd2, fd3); 144 close2(fd4, fd5); 145} 146 147static int 148my_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 158static void 159my_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 166static void 167my_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 174static void 175my_listen(int sock, int backlog) 176{ 177 178 if (listen(sock, backlog) < 0) 179 err(-1, "%s: listen", test); 180} 181 182static void 183my_socketpair(int *sv) 184{ 185 186 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) 187 err(-1, "%s: socketpair", test); 188} 189 190static void 191my_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 198static void 199setnonblock(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 206static void 207alloc3fds(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 216static void 217alloc5fds(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 228static void 229save_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 */ 240static void 241trigger_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 253static void 254test_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 270static void 271twosome_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 */ 301static void 302twosome_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 319static void 320twosome_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 338static void 339threesome_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 */ 356static void 357threesome_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 */ 434static void 435fivesome_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 448static void 449fivesome_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 485static void 486fivesome_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 */ 499static void 500complex_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 */ 524static void 525listen_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 */ 569static void 570listen_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 */ 651static void 652listen_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 683static void 684listen_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 717static void 718recursion(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 " 752int 753main(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