1 /* $OpenBSD: poll_iocond.c,v 1.3 2021/12/27 16:38:06 visa Exp $ */ 2 3 /* 4 * Copyright (c) 2021 Visa Hankala 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * Test poll(2) with various I/O conditions. 21 */ 22 23 #include <sys/types.h> 24 #include <sys/ioctl.h> 25 #include <sys/socket.h> 26 #include <sys/stat.h> 27 #include <sys/wait.h> 28 #include <netinet/in.h> 29 #include <netinet/tcp.h> 30 #include <arpa/inet.h> 31 32 #include <assert.h> 33 #include <err.h> 34 #include <fcntl.h> 35 #include <poll.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 #if defined(__OpenBSD__) 42 /* for pty */ 43 #include <termios.h> 44 #include <util.h> 45 #endif 46 47 #if !defined(__linux__) 48 #define HAVE_SOCKADDR_LEN 1 49 #endif 50 51 #define MIN(a, b) ((a) <= (b) ? (a) : (b)) 52 53 #define TEST_FIFO_NAME "iocond_fifo" 54 55 enum filetype { 56 FTYPE_NONE, 57 FTYPE_FIFO, 58 FTYPE_PIPE, 59 FTYPE_PTY, 60 FTYPE_SOCKET_TCP, 61 FTYPE_SOCKET_UDP, 62 FTYPE_SOCKET_UNIX, 63 }; 64 65 static struct { 66 const char *name; 67 enum filetype type; 68 } filetypes[] = { 69 { "fifo", FTYPE_FIFO }, 70 { "pipe", FTYPE_PIPE }, 71 #if defined(__OpenBSD__) 72 { "pty", FTYPE_PTY }, 73 #endif 74 { "socket-tcp", FTYPE_SOCKET_TCP }, 75 { "socket-udp", FTYPE_SOCKET_UDP }, 76 { "socket-unix", FTYPE_SOCKET_UNIX }, 77 }; 78 79 static enum filetype filetype = FTYPE_NONE; 80 81 static void cleanup(void); 82 static void proc_barrier(int); 83 static void proc_child(int, int); 84 static void proc_parent(int, int); 85 86 int 87 main(int argc, char *argv[]) 88 { 89 const char *ftname; 90 int bfd[2], fds[2]; 91 int child_fd = -1; 92 int parent_fd = -1; 93 int sock = -1; 94 unsigned int i; 95 pid_t pid; 96 97 /* Enforce test timeout. */ 98 alarm(10); 99 100 if (argc != 2) { 101 fprintf(stderr, "usage: %s filetype\n", argv[0]); 102 return 1; 103 } 104 ftname = argv[1]; 105 106 for (i = 0; i < sizeof(filetypes) / sizeof(filetypes[0]); i++) { 107 if (strcmp(ftname, filetypes[i].name) == 0) { 108 filetype = filetypes[i].type; 109 break; 110 } 111 } 112 if (filetype == FTYPE_NONE) 113 errx(1, "unknown filetype"); 114 115 /* Open barrier sockets. */ 116 if (socketpair(AF_UNIX, SOCK_STREAM, 0, bfd) == -1) 117 err(1, "socketpair"); 118 119 atexit(cleanup); 120 121 switch (filetype) { 122 case FTYPE_FIFO: 123 (void)unlink(TEST_FIFO_NAME); 124 if (mkfifo(TEST_FIFO_NAME, 0644) == -1) 125 err(1, "mkfifo"); 126 break; 127 case FTYPE_PIPE: 128 if (pipe(fds) == -1) 129 err(1, "pipe"); 130 parent_fd = fds[0]; 131 child_fd = fds[1]; 132 break; 133 #if defined(__OpenBSD__) 134 case FTYPE_PTY: 135 if (openpty(&parent_fd, &child_fd, NULL, NULL, NULL) == -1) 136 err(1, "openpty"); 137 break; 138 #endif 139 case FTYPE_SOCKET_TCP: { 140 struct sockaddr_in inaddr; 141 142 sock = socket(AF_INET, SOCK_STREAM, 0); 143 144 memset(&inaddr, 0, sizeof(inaddr)); 145 #ifdef HAVE_SOCKADDR_LEN 146 inaddr.sin_len = sizeof(inaddr); 147 #endif 148 inaddr.sin_family = AF_INET; 149 inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 150 if (bind(sock, (struct sockaddr *)&inaddr, 151 sizeof(inaddr)) == -1) 152 err(1, "bind"); 153 if (listen(sock, 1) == -1) 154 err(1, "listen"); 155 break; 156 } 157 case FTYPE_SOCKET_UDP: { 158 struct sockaddr_in inaddr; 159 160 sock = socket(AF_INET, SOCK_DGRAM, 0); 161 162 memset(&inaddr, 0, sizeof(inaddr)); 163 #ifdef HAVE_SOCKADDR_LEN 164 inaddr.sin_len = sizeof(inaddr); 165 #endif 166 inaddr.sin_family = AF_INET; 167 inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 168 if (bind(sock, (struct sockaddr *)&inaddr, 169 sizeof(inaddr)) == -1) 170 err(1, "bind"); 171 break; 172 } 173 case FTYPE_SOCKET_UNIX: 174 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) 175 err(1, "socketpair"); 176 parent_fd = fds[0]; 177 child_fd = fds[1]; 178 break; 179 default: 180 errx(1, "unhandled filetype"); 181 } 182 183 pid = fork(); 184 switch (pid) { 185 case -1: 186 err(1, "fork"); 187 case 0: 188 switch (filetype) { 189 case FTYPE_FIFO: 190 child_fd = open(TEST_FIFO_NAME, O_WRONLY); 191 if (child_fd == -1) 192 err(1, "child: open"); 193 break; 194 case FTYPE_SOCKET_TCP: { 195 struct sockaddr_in inaddr; 196 socklen_t inaddrlen; 197 int on = 1; 198 199 /* Get the bound address. */ 200 inaddrlen = sizeof(inaddr); 201 if (getsockname(sock, (struct sockaddr *)&inaddr, 202 &inaddrlen) == -1) 203 err(1, "child: getsockname"); 204 205 child_fd = socket(AF_INET, SOCK_STREAM, 0); 206 if (child_fd == -1) 207 err(1, "child: socket"); 208 if (connect(child_fd, (struct sockaddr *)&inaddr, 209 sizeof(inaddr)) == -1) 210 err(1, "child: connect"); 211 if (setsockopt(child_fd, IPPROTO_TCP, TCP_NODELAY, 212 &on, sizeof(on)) == -1) 213 err(1, "child: setsockopt(TCP_NODELAY)"); 214 break; 215 } 216 case FTYPE_SOCKET_UDP: { 217 struct sockaddr_in inaddr; 218 socklen_t inaddrlen; 219 220 /* Get the bound address. */ 221 inaddrlen = sizeof(inaddr); 222 if (getsockname(sock, (struct sockaddr *)&inaddr, 223 &inaddrlen) == -1) 224 err(1, "child: getsockname"); 225 226 child_fd = socket(AF_INET, SOCK_DGRAM, 0); 227 if (child_fd == -1) 228 err(1, "child: socket"); 229 if (connect(child_fd, (struct sockaddr *)&inaddr, 230 sizeof(inaddr)) == -1) 231 err(1, "child: connect"); 232 break; 233 } 234 default: 235 break; 236 } 237 if (parent_fd != -1) { 238 close(parent_fd); 239 parent_fd = -1; 240 } 241 if (sock != -1) { 242 close(sock); 243 sock = -1; 244 } 245 proc_child(child_fd, bfd[1]); 246 _exit(0); 247 default: 248 switch (filetype) { 249 case FTYPE_FIFO: 250 parent_fd = open(TEST_FIFO_NAME, O_RDONLY); 251 if (parent_fd == -1) 252 err(1, "parent: open"); 253 break; 254 case FTYPE_SOCKET_TCP: { 255 int on = 1; 256 257 parent_fd = accept(sock, NULL, NULL); 258 if (parent_fd == -1) 259 err(1, "parent: accept"); 260 if (setsockopt(parent_fd, IPPROTO_TCP, TCP_NODELAY, 261 &on, sizeof(on)) == -1) 262 err(1, "parent: setsockopt(TCP_NODELAY)"); 263 break; 264 } 265 case FTYPE_SOCKET_UDP: 266 parent_fd = sock; 267 sock = -1; 268 break; 269 default: 270 break; 271 } 272 if (child_fd != -1) { 273 close(child_fd); 274 child_fd = -1; 275 } 276 if (sock != -1) { 277 close(sock); 278 sock = -1; 279 } 280 proc_parent(parent_fd, bfd[0]); 281 break; 282 } 283 284 if (waitpid(pid, NULL, 0) == -1) 285 err(1, "waitpid"); 286 287 return 0; 288 } 289 290 static void 291 cleanup(void) 292 { 293 if (filetype == FTYPE_FIFO) 294 (void)unlink(TEST_FIFO_NAME); 295 } 296 297 static void 298 proc_barrier(int fd) 299 { 300 int ret; 301 char b = 0; 302 303 ret = write(fd, &b, 1); 304 assert(ret == 1); 305 ret = read(fd, &b, 1); 306 assert(ret == 1); 307 } 308 309 static void 310 proc_child(int fd, int bfd) 311 { 312 struct pollfd pfd[2]; 313 char buf[1024]; 314 size_t nbytes; 315 int ret; 316 char b = 0; 317 318 memset(&pfd, 0, sizeof(pfd)); 319 320 proc_barrier(bfd); 321 322 pfd[0].fd = fd; 323 pfd[0].events = POLLIN | POLLOUT | POLLPRI; 324 325 ret = poll(pfd, 1, 1); 326 assert(ret == 1); 327 assert(pfd[0].revents == POLLOUT); 328 329 proc_barrier(bfd); 330 331 ret = write(fd, &b, 1); 332 assert(ret == 1); 333 334 proc_barrier(bfd); 335 336 ret = poll(pfd, 1, 1); 337 assert(ret == 1); 338 assert(pfd[0].revents == POLLOUT); 339 340 proc_barrier(bfd); 341 342 /* parent: read */ 343 344 proc_barrier(bfd); 345 346 if (filetype != FTYPE_SOCKET_UDP) { 347 /* write until full */ 348 memset(buf, 0, sizeof(buf)); 349 nbytes = 0; 350 for (;;) { 351 pfd[0].fd = fd; 352 pfd[0].events = POLLOUT; 353 ret = poll(pfd, 1, 0); 354 if (ret == 0) 355 break; 356 assert(ret == 1); 357 assert(pfd[0].revents == POLLOUT); 358 ret = write(fd, buf, sizeof(buf)); 359 assert(ret > 0); 360 nbytes += ret; 361 } 362 ret = write(bfd, &nbytes, sizeof(nbytes)); 363 assert(ret == sizeof(nbytes)); 364 365 proc_barrier(bfd); 366 367 /* parent: read until empty */ 368 } 369 370 proc_barrier(bfd); 371 372 /* Test out-of-band data. */ 373 switch (filetype) { 374 #if defined(__OpenBSD__) 375 case FTYPE_PTY: { 376 /* parent: enable user ioctl command mode */ 377 378 proc_barrier(bfd); 379 380 ret = write(fd, &b, 1); 381 assert(ret == 1); 382 383 if (ioctl(fd, UIOCCMD(42), NULL) == -1) 384 err(1, "child: ioctl(UIOCCMD)"); 385 386 ret = write(fd, &b, 1); 387 assert(ret == 1); 388 389 proc_barrier(bfd); 390 391 /* parent: read, and disable user ioctl command mode */ 392 393 proc_barrier(bfd); 394 break; 395 } 396 #endif /* __OpenBSD__ */ 397 398 case FTYPE_SOCKET_TCP: 399 ret = send(fd, &b, 1, 0); 400 assert(ret == 1); 401 402 ret = send(fd, &b, 1, MSG_OOB); 403 assert(ret == 1); 404 405 ret = send(fd, &b, 1, 0); 406 assert(ret == 1); 407 408 proc_barrier(bfd); 409 410 /* parent: read */ 411 412 proc_barrier(bfd); 413 break; 414 415 default: 416 break; 417 } 418 419 /* Test socket shutdown. */ 420 switch (filetype) { 421 case FTYPE_SOCKET_TCP: 422 case FTYPE_SOCKET_UNIX: 423 ret = write(fd, &b, 1); 424 assert(ret == 1); 425 426 ret = shutdown(fd, SHUT_WR); 427 assert(ret == 0); 428 429 proc_barrier(bfd); 430 431 /* parent: read and shutdown */ 432 433 proc_barrier(bfd); 434 435 /* Let inet sockets take their time. */ 436 if (filetype == FTYPE_SOCKET_TCP) 437 usleep(10000); 438 439 pfd[0].fd = fd; 440 pfd[0].events = POLLIN | POLLOUT | POLLPRI; 441 pfd[1].fd = fd; 442 pfd[1].events = 0; 443 444 ret = poll(pfd, 2, 1); 445 #if defined(__linux__) 446 assert(ret == 2); 447 assert(pfd[0].revents == (POLLIN | POLLOUT | POLLHUP)); 448 assert(pfd[1].revents == POLLHUP); 449 #else 450 #if defined(__OpenBSD__) 451 /* XXX */ 452 if (filetype == FTYPE_SOCKET_UNIX) { 453 assert(ret == 1); 454 assert(pfd[0].revents == (POLLIN | POLLOUT)); 455 assert(pfd[1].revents == 0); 456 } else { 457 #endif /* __OpenBSD__ */ 458 assert(ret == 2); 459 assert(pfd[0].revents == (POLLIN | POLLHUP)); 460 assert(pfd[1].revents == POLLHUP); 461 #if defined(__OpenBSD__) 462 } 463 #endif /* __OpenBSD__ */ 464 #endif 465 break; 466 467 case FTYPE_FIFO: 468 case FTYPE_PIPE: 469 case FTYPE_PTY: 470 case FTYPE_SOCKET_UDP: 471 default: 472 break; 473 } 474 475 proc_barrier(bfd); 476 477 close(fd); 478 479 proc_barrier(bfd); 480 481 pfd[0].fd = fd; 482 pfd[0].events = 0; 483 484 ret = poll(pfd, 1, 1); 485 assert(ret == 1); 486 assert(pfd[0].revents == POLLNVAL); 487 } 488 489 static void 490 proc_parent(int fd, int bfd) 491 { 492 struct pollfd pfd[2]; 493 char buf[1024]; 494 size_t nbytes; 495 int ret, retries; 496 char b = 0; 497 498 memset(&pfd, 0, sizeof(pfd)); 499 500 proc_barrier(bfd); 501 502 pfd[0].fd = fd; 503 pfd[0].events = POLLIN | POLLOUT | POLLPRI; 504 if (filetype == FTYPE_FIFO || filetype == FTYPE_PIPE) 505 pfd[0].events &= ~POLLOUT; 506 507 ret = poll(pfd, 1, 1); 508 switch (filetype) { 509 case FTYPE_FIFO: 510 case FTYPE_PIPE: 511 assert(ret == 0); 512 assert(pfd[0].revents == 0); 513 break; 514 default: 515 assert(ret == 1); 516 assert(pfd[0].revents == POLLOUT); 517 break; 518 } 519 520 proc_barrier(bfd); 521 522 /* child: write */ 523 524 proc_barrier(bfd); 525 526 /* Let inet sockets take their time. */ 527 if (filetype == FTYPE_SOCKET_TCP || 528 filetype == FTYPE_SOCKET_UDP) 529 usleep(10000); 530 531 ret = poll(pfd, 1, 1); 532 switch (filetype) { 533 case FTYPE_FIFO: 534 case FTYPE_PIPE: 535 assert(ret == 1); 536 assert(pfd[0].revents == POLLIN); 537 break; 538 case FTYPE_PTY: 539 case FTYPE_SOCKET_TCP: 540 case FTYPE_SOCKET_UDP: 541 case FTYPE_SOCKET_UNIX: 542 assert(ret == 1); 543 assert(pfd[0].revents == (POLLIN | POLLOUT)); 544 break; 545 default: 546 assert(0); 547 } 548 549 proc_barrier(bfd); 550 551 ret = read(fd, &b, 1); 552 assert(ret == 1); 553 554 pfd[0].fd = fd; 555 pfd[0].events = POLLIN; 556 557 ret = poll(pfd, 1, 1); 558 assert(ret == 0); 559 560 proc_barrier(bfd); 561 562 if (filetype != FTYPE_SOCKET_UDP) { 563 /* child: write until full */ 564 nbytes = 0; 565 ret = read(bfd, &nbytes, sizeof(nbytes)); 566 assert(ret == sizeof(nbytes)); 567 568 proc_barrier(bfd); 569 570 /* read until empty */ 571 retries = 5; 572 while (retries > 0) { 573 pfd[0].fd = fd; 574 pfd[0].events = POLLIN; 575 ret = poll(pfd, 1, 0); 576 if (ret == 0) { 577 retries--; 578 /* Let inet sockets take their time. */ 579 if (nbytes > 0 && retries > 0) 580 usleep(10000); 581 continue; 582 } 583 assert(ret == 1); 584 assert(pfd[0].revents == POLLIN); 585 assert(nbytes > 0); 586 ret = read(fd, buf, MIN(sizeof(buf), nbytes)); 587 assert(ret > 0); 588 nbytes -= ret; 589 } 590 assert(nbytes == 0); 591 } 592 593 proc_barrier(bfd); 594 595 /* Test out-of-band data. */ 596 switch (filetype) { 597 #if defined(__OpenBSD__) 598 case FTYPE_PTY: { 599 int off = 0; 600 int on = 1; 601 602 if (ioctl(fd, TIOCUCNTL, &on) == -1) 603 err(1, "parent: ioctl(TIOCUCNTL, 1)"); 604 605 proc_barrier(bfd); 606 607 /* child: write */ 608 609 proc_barrier(bfd); 610 611 pfd[0].fd = fd; 612 pfd[0].events = POLLIN | POLLOUT | POLLPRI; 613 pfd[1].fd = fd; 614 pfd[1].events = 0; 615 616 ret = poll(pfd, 2, 1); 617 assert(ret == 1); 618 assert(pfd[0].revents == (POLLIN | POLLOUT | POLLPRI)); 619 assert(pfd[1].revents == 0); 620 621 /* Read out-of-band data. */ 622 ret = read(fd, buf, sizeof(buf)); 623 assert(ret == 1); 624 625 ret = poll(pfd, 2, 1); 626 assert(ret == 1); 627 assert(pfd[0].revents == (POLLIN | POLLOUT)); 628 assert(pfd[1].revents == 0); 629 630 /* Read normal data. */ 631 ret = read(fd, buf, sizeof(buf)); 632 assert(ret == 3); 633 634 ret = poll(pfd, 2, 1); 635 assert(ret == 1); 636 assert(pfd[0].revents == POLLOUT); 637 assert(pfd[1].revents == 0); 638 639 if (ioctl(fd, TIOCUCNTL, &off) == -1) 640 err(1, "parent: ioctl(TIOCUCNTL, 0)"); 641 642 proc_barrier(bfd); 643 break; 644 } 645 #endif /* __OpenBSD__ */ 646 647 case FTYPE_SOCKET_TCP: { 648 int atmark; 649 int on = 1; 650 651 /* child: write */ 652 653 if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &on, 654 sizeof(on)) == -1) 655 err(1, "parent: setsockopt(SO_OOBINLINE)"); 656 657 proc_barrier(bfd); 658 659 pfd[0].fd = fd; 660 pfd[0].events = POLLIN | POLLOUT | POLLPRI; 661 pfd[1].fd = fd; 662 pfd[1].events = 0; 663 664 ret = poll(pfd, 2, 1); 665 assert(ret == 1); 666 assert(pfd[0].revents == (POLLIN | POLLOUT | POLLPRI)); 667 assert(pfd[1].revents == 0); 668 669 /* Read normal data. */ 670 atmark = 0; 671 if (ioctl(fd, SIOCATMARK, &atmark) == -1) 672 err(1, "parent: ioctl(SIOCATMARK)"); 673 assert(atmark == 0); 674 ret = recv(fd, buf, sizeof(buf), 0); 675 assert(ret == 1); 676 677 ret = poll(pfd, 2, 1); 678 assert(ret == 1); 679 assert(pfd[0].revents == (POLLIN | POLLOUT | POLLPRI)); 680 assert(pfd[1].revents == 0); 681 682 /* Read out-of-band data. */ 683 atmark = 0; 684 if (ioctl(fd, SIOCATMARK, &atmark) == -1) 685 err(1, "parent: ioctl(SIOCATMARK)"); 686 assert(atmark != 0); 687 ret = recv(fd, &b, 1, 0); 688 assert(ret == 1); 689 690 ret = poll(pfd, 2, 1); 691 assert(ret == 1); 692 assert(pfd[0].revents == (POLLIN | POLLOUT)); 693 assert(pfd[1].revents == 0); 694 695 /* Read normal data. */ 696 atmark = 0; 697 if (ioctl(fd, SIOCATMARK, &atmark) == -1) 698 err(1, "parent: ioctl(SIOCATMARK)"); 699 assert(atmark == 0); 700 ret = recv(fd, buf, sizeof(buf), 0); 701 assert(ret == 1); 702 703 ret = poll(pfd, 2, 1); 704 assert(ret == 1); 705 assert(pfd[0].revents == POLLOUT); 706 assert(pfd[1].revents == 0); 707 708 proc_barrier(bfd); 709 break; 710 } 711 712 default: 713 break; 714 } 715 716 /* Test socket shutdown. */ 717 switch (filetype) { 718 case FTYPE_SOCKET_TCP: 719 case FTYPE_SOCKET_UNIX: 720 /* child: write and shutdown */ 721 722 proc_barrier(bfd); 723 724 /* Let inet sockets take their time. */ 725 if (filetype == FTYPE_SOCKET_TCP) 726 usleep(10000); 727 728 pfd[0].fd = fd; 729 pfd[0].events = POLLIN | POLLOUT | POLLPRI; 730 731 ret = poll(pfd, 1, 1); 732 assert(ret == 1); 733 assert(pfd[0].revents == (POLLIN | POLLOUT)); 734 735 ret = read(fd, &b, 1); 736 assert(ret == 1); 737 738 ret = poll(pfd, 1, 1); 739 assert(ret == 1); 740 assert(pfd[0].revents == (POLLIN | POLLOUT)); 741 742 ret = read(fd, &b, 1); 743 assert(ret == 0); 744 745 ret = shutdown(fd, SHUT_WR); 746 assert(ret == 0); 747 748 proc_barrier(bfd); 749 750 pfd[0].fd = fd; 751 pfd[0].events = POLLIN | POLLOUT | POLLPRI; 752 pfd[1].fd = fd; 753 pfd[1].events = 0; 754 755 ret = poll(pfd, 2, 1); 756 #if defined(__linux__) 757 assert(ret == 2); 758 assert(pfd[0].revents == (POLLIN | POLLOUT | POLLHUP)); 759 assert(pfd[1].revents == POLLHUP); 760 #else 761 #if defined(__OpenBSD__) 762 /* XXX */ 763 if (filetype == FTYPE_SOCKET_UNIX) { 764 assert(ret == 1); 765 assert(pfd[0].revents == (POLLIN | POLLOUT)); 766 assert(pfd[1].revents == 0); 767 } else { 768 #endif /* __OpenBSD__ */ 769 assert(ret == 2); 770 assert(pfd[0].revents == (POLLIN | POLLHUP)); 771 assert(pfd[1].revents == POLLHUP); 772 #if defined(__OpenBSD__) 773 } 774 #endif /* __OpenBSD__ */ 775 #endif 776 break; 777 778 case FTYPE_FIFO: 779 case FTYPE_PIPE: 780 case FTYPE_PTY: 781 case FTYPE_SOCKET_UDP: 782 default: 783 break; 784 } 785 786 proc_barrier(bfd); 787 788 /* child: close */ 789 790 proc_barrier(bfd); 791 792 pfd[0].fd = fd; 793 pfd[0].events = POLLIN | POLLOUT | POLLPRI; 794 pfd[1].fd = fd; 795 pfd[1].events = 0; 796 797 ret = poll(pfd, 2, 1); 798 switch (filetype) { 799 case FTYPE_FIFO: 800 case FTYPE_PIPE: 801 case FTYPE_PTY: 802 assert(ret == 2); 803 #if defined(__linux__) 804 assert(pfd[0].revents == POLLHUP); 805 assert(pfd[1].revents == POLLHUP); 806 #else 807 assert(pfd[0].revents == (POLLIN | POLLHUP)); 808 assert(pfd[1].revents == POLLHUP); 809 #endif 810 break; 811 case FTYPE_SOCKET_TCP: 812 case FTYPE_SOCKET_UNIX: 813 assert(ret == 2); 814 #if defined(__linux__) 815 assert(pfd[0].revents == (POLLIN | POLLOUT | POLLHUP)); 816 assert(pfd[1].revents == POLLHUP); 817 #else 818 assert(pfd[0].revents == (POLLIN | POLLHUP)); 819 assert(pfd[1].revents == POLLHUP); 820 #endif 821 break; 822 case FTYPE_SOCKET_UDP: 823 assert(ret == 1); 824 assert(pfd[0].revents == POLLOUT); 825 assert(pfd[1].revents == 0); 826 break; 827 default: 828 assert(0); 829 } 830 831 close(fd); 832 } 833