1 /* Tests for opening/closing pseudo terminals - by D.C. van Moolenbroek */ 2 /* This test needs to be run as root; otherwise, openpty() won't work. */ 3 #include <stdlib.h> 4 #include <stdio.h> 5 #include <string.h> 6 #include <signal.h> 7 #include <termios.h> 8 #include <sys/wait.h> 9 #include <sys/syslimits.h> 10 #include <paths.h> 11 #include <fcntl.h> 12 #include <util.h> 13 14 #define ITERATIONS 10 15 16 #include "common.h" 17 18 static int sighups; /* number of SIGHUP signals received */ 19 20 /* 21 * Signal handler for SIGHUP and SIGUSR1. 22 */ 23 static void 24 signal_handler(int sig) 25 { 26 if (sig == SIGHUP) 27 sighups++; 28 } 29 30 /* 31 * Set the slave side of the pseudo terminal to raw mode. This simplifies 32 * testing communication. 33 */ 34 static void 35 make_raw(int slavefd) 36 { 37 struct termios tios; 38 39 if (tcgetattr(slavefd, &tios) < 0) e(100); 40 41 cfmakeraw(&tios); 42 43 if (tcsetattr(slavefd, TCSANOW, &tios) < 0) e(101); 44 } 45 46 /* 47 * See if the given pseudo terminal can successfully perform basic 48 * communication between master and slave. 49 */ 50 static void 51 test_comm(int masterfd, int slavefd) 52 { 53 char c; 54 55 make_raw(slavefd); 56 57 c = 'A'; 58 if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(200); 59 if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(201); 60 if (c != 'A') e(202); 61 62 c = 'B'; 63 if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(203); 64 if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(204); 65 if (c != 'B') e(205); 66 67 c = 'C'; 68 if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(206); 69 if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(207); 70 if (c != 'C') e(208); 71 72 c = 'D'; 73 if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(209); 74 if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(210); 75 if (c != 'D') e(211); 76 } 77 78 /* 79 * Get device node names for the master and slave end of a free pseudo 80 * terminal. We don't want to replicate the entire openpty(3) logic here, so 81 * start by letting openpty(3) do the work for us. We make the assumption that 82 * nobody snatches the pair while we are running. 83 */ 84 static void 85 get_names(char pname[PATH_MAX], char tname[PATH_MAX]) 86 { 87 int len, masterfd, slavefd; 88 89 if (openpty(&masterfd, &slavefd, tname, NULL, NULL) < 0) e(300); 90 91 /* 92 * openpty(3) gives us only the slave name, but we also need the master 93 * name. 94 */ 95 strlcpy(pname, tname, PATH_MAX); 96 len = strlen(_PATH_DEV); 97 98 if (strncmp(pname, _PATH_DEV, len)) e(301); 99 100 /* If this fails, this test needs to be updated. */ 101 if (pname[len] != 't') e(302); 102 103 pname[len] = 'p'; 104 105 test_comm(masterfd, slavefd); 106 107 if (close(masterfd) < 0) e(303); 108 if (close(slavefd) < 0) e(304); 109 } 110 111 /* 112 * Test various orders of opening and closing the master and slave sides of a 113 * pseudo terminal, as well as opening/closing one side without ever opening 114 * the other. 115 */ 116 static void 117 test77a(void) 118 { 119 struct sigaction act, oact; 120 char pname[PATH_MAX], tname[PATH_MAX]; 121 int masterfd, slavefd; 122 123 subtest = 1; 124 125 /* We do not want to get SIGHUP signals in this test. */ 126 memset(&act, 0, sizeof(act)); 127 act.sa_handler = SIG_IGN; 128 if (sigaction(SIGHUP, &act, &oact) < 0) e(1); 129 130 /* Get master and slave device names for a free pseudo terminal. */ 131 get_names(pname, tname); 132 133 /* Try opening and then closing the master. */ 134 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(2); 135 136 if (close(masterfd) < 0) e(3); 137 138 /* Now see if we can reopen the master as well as the slave. */ 139 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(4); 140 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(5); 141 142 test_comm(masterfd, slavefd); 143 144 /* In the meantime, test different closing orders. This is order A. */ 145 if (close(slavefd) < 0) e(6); 146 if (close(masterfd) < 0) e(7); 147 148 /* Now try opening the pair again. */ 149 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(8); 150 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(9); 151 152 test_comm(masterfd, slavefd); 153 154 if (close(slavefd) < 0) e(10); 155 156 /* 157 * Try reopening the slave after closing it. It is not very important 158 * that this works, but the TTY driver should currently support it. 159 */ 160 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(11); 161 162 test_comm(masterfd, slavefd); 163 164 /* This is closing order B. This may or may not cause a SIGHUP. */ 165 if (close(masterfd) < 0) e(12); 166 if (close(slavefd) < 0) e(13); 167 168 /* Try the normal open procedure. */ 169 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(14); 170 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(15); 171 172 test_comm(masterfd, slavefd); 173 174 if (close(slavefd) < 0) e(16); 175 if (close(masterfd) < 0) e(17); 176 177 /* Try reopening and closing the slave, without opening the master. */ 178 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(18); 179 180 if (close(slavefd) < 0) e(19); 181 182 /* Again, try the normal open procedure. */ 183 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(20); 184 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(21); 185 186 test_comm(masterfd, slavefd); 187 188 if (close(slavefd) < 0) e(22); 189 if (close(masterfd) < 0) e(23); 190 191 /* Finally, try opening the slave first. */ 192 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(24); 193 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(25); 194 195 test_comm(masterfd, slavefd); 196 197 if (close(slavefd) < 0) e(26); 198 if (close(masterfd) < 0) e(27); 199 200 if (sigaction(SIGHUP, &oact, NULL) < 0) e(28); 201 } 202 203 /* 204 * Test opening a single side multiple times. 205 */ 206 static void 207 test77b(void) 208 { 209 char pname[PATH_MAX], tname[PATH_MAX]; 210 int masterfd, slavefd, extrafd; 211 212 subtest = 2; 213 214 /* Get master and slave device names for a free pseudo terminal. */ 215 get_names(pname, tname); 216 217 /* It must not be possible to open the master multiple times. */ 218 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(1); 219 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(2); 220 221 test_comm(masterfd, slavefd); 222 223 if ((extrafd = open(pname, O_RDWR | O_NOCTTY)) >= 0) e(3); 224 if (errno != EIO) e(4); 225 226 test_comm(masterfd, slavefd); 227 228 if (close(slavefd) < 0) e(5); 229 if (close(masterfd) < 0) e(6); 230 231 /* The slave can be opened multiple times, though. */ 232 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(7); 233 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(8); 234 235 test_comm(masterfd, slavefd); 236 237 if ((extrafd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(9); 238 239 test_comm(masterfd, extrafd); 240 test_comm(masterfd, slavefd); 241 242 if (close(slavefd) < 0) e(10); 243 if (close(extrafd) < 0) e(11); 244 if (close(masterfd) < 0) e(12); 245 } 246 247 /* 248 * Test communication on half-open pseudo terminals. 249 */ 250 static void 251 test77c(void) 252 { 253 struct sigaction act, oact; 254 char pname[PATH_MAX], tname[PATH_MAX]; 255 int masterfd, slavefd; 256 char c; 257 258 subtest = 3; 259 260 /* We do not want to get SIGHUP signals in this test. */ 261 memset(&act, 0, sizeof(act)); 262 act.sa_handler = SIG_IGN; 263 if (sigaction(SIGHUP, &act, &oact) < 0) e(1); 264 265 /* Get master and slave device names for a free pseudo terminal. */ 266 get_names(pname, tname); 267 268 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(2); 269 270 /* Writes to the master should be buffered until there is a slave. */ 271 c = 'E'; 272 if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(3); 273 274 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(4); 275 276 make_raw(slavefd); 277 278 if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(5); 279 if (c != 'E') e(6); 280 281 /* Discard the echo on the master. */ 282 if (tcflush(slavefd, TCOFLUSH) != 0) e(7); 283 284 test_comm(masterfd, slavefd); 285 286 if (close(slavefd) < 0) e(8); 287 288 /* Writes to the master after the slave has been closed should fail. */ 289 if (write(masterfd, &c, sizeof(c)) >= 0) e(9); 290 if (errno != EIO) e(10); 291 292 if (close(masterfd) < 0) e(11); 293 294 /* Writes to the slave should be buffered until there is a master. */ 295 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(12); 296 297 make_raw(slavefd); 298 299 c = 'F'; 300 if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(13); 301 302 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(14); 303 304 if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(15); 305 if (c != 'F') e(16); 306 307 test_comm(masterfd, slavefd); 308 309 if (close(masterfd) < 0) e(17); 310 311 if (write(slavefd, &c, sizeof(c)) >= 0) e(18); 312 if (errno != EIO) e(19); 313 314 /* Reads from the slave should return EOF if the master is gone. */ 315 if (read(slavefd, &c, sizeof(c)) != 0) e(20); 316 317 if (close(slavefd) < 0) e(21); 318 319 if (sigaction(SIGHUP, &oact, NULL) < 0) e(22); 320 } 321 322 /* 323 * Wait for a child process to terminate. Return 0 if the child exited without 324 * errors, -1 otherwise. 325 */ 326 static int 327 waitchild(void) 328 { 329 int status; 330 331 if (wait(&status) <= 0) return -1; 332 if (!WIFEXITED(status)) return -1; 333 if (WEXITSTATUS(status) != 0) return -1; 334 335 return 0; 336 } 337 338 /* 339 * Test opening the slave side with and without the O_NOCTTY flag. 340 */ 341 static void 342 test77d(void) 343 { 344 char pname[PATH_MAX], tname[PATH_MAX]; 345 int masterfd, slavefd; 346 347 subtest = 4; 348 349 /* Get master and slave device names for a free pseudo terminal. */ 350 get_names(pname, tname); 351 352 /* Make ourselves process group leader if we aren't already. */ 353 (void) setsid(); 354 355 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(1); 356 357 /* 358 * Opening the slave with O_NOCTTY should not change its controlling 359 * terminal. 360 */ 361 switch (fork()) { 362 case 0: 363 if (setsid() < 0) e(2); 364 365 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(3); 366 367 if (open("/dev/tty", O_RDWR) >= 0) e(4); 368 if (errno != ENXIO) e(5); 369 370 exit(errct); 371 case -1: 372 e(6); 373 default: 374 break; 375 } 376 377 if (waitchild() < 0) e(7); 378 379 if (close(masterfd) < 0) e(8); 380 381 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(9); 382 383 /* 384 * Opening the slave without O_NOCTTY should change its controlling 385 * terminal, though. 386 */ 387 switch (fork()) { 388 case 0: 389 if (setsid() < 0) e(10); 390 391 if ((slavefd = open(tname, O_RDWR)) < 0) e(11); 392 393 if (open("/dev/tty", O_RDWR) < 0) e(12); 394 395 exit(errct); 396 case -1: 397 e(13); 398 default: 399 break; 400 } 401 402 if (waitchild() < 0) e(14); 403 404 if (close(masterfd) < 0) e(15); 405 } 406 407 /* 408 * Test receiving of SIGHUP on master hang-up. All of the tests so far have 409 * ignored SIGHUP, and probably would not have received one anyway, since the 410 * process was not its own session leader. Time to test this aspect. 411 */ 412 static void 413 test77e(void) 414 { 415 struct sigaction act, hup_oact, usr_oact; 416 sigset_t set, oset; 417 char pname[PATH_MAX], tname[PATH_MAX]; 418 int masterfd, slavefd; 419 420 subtest = 5; 421 422 /* Get master and slave device names for a free pseudo terminal. */ 423 get_names(pname, tname); 424 425 memset(&act, 0, sizeof(act)); 426 act.sa_handler = signal_handler; 427 if (sigaction(SIGHUP, &act, &hup_oact) < 0) e(1); 428 429 memset(&act, 0, sizeof(act)); 430 act.sa_handler = signal_handler; 431 if (sigaction(SIGUSR1, &act, &usr_oact) < 0) e(2); 432 433 sigemptyset(&set); 434 sigaddset(&set, SIGHUP); 435 sigaddset(&set, SIGUSR1); 436 if (sigprocmask(SIG_BLOCK, &set, &oset) < 0) e(3); 437 438 sighups = 0; 439 440 /* Make ourselves process group leader if we aren't already. */ 441 (void) setsid(); 442 443 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(4); 444 445 switch (fork()) { 446 case 0: 447 if (close(masterfd) < 0) e(5); 448 449 /* Become session leader. */ 450 if (setsid() < 0) e(6); 451 452 if ((slavefd = open(tname, O_RDWR)) < 0) e(7); 453 454 /* Tell the parent we are ready. */ 455 kill(getppid(), SIGUSR1); 456 457 /* We should now get a SIGHUP. */ 458 set = oset; 459 if (sigsuspend(&set) >= 0) e(8); 460 461 if (sighups != 1) e(9); 462 463 exit(errct); 464 case -1: 465 e(10); 466 default: 467 break; 468 } 469 470 /* Wait for SIGUSR1 from the child. */ 471 set = oset; 472 if (sigsuspend(&set) >= 0) e(11); 473 474 /* Closing the master should now raise a SIGHUP signal in the child. */ 475 if (close(masterfd) < 0) e(12); 476 477 if (waitchild() < 0) e(13); 478 479 if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0) e(14); 480 481 if (sigaction(SIGHUP, &hup_oact, NULL) < 0) e(15); 482 if (sigaction(SIGUSR1, &usr_oact, NULL) < 0) e(16); 483 } 484 485 /* 486 * Test basic select functionality on /dev/tty. While this test should not be 487 * part of this test set, we already have all the infrastructure we need here. 488 */ 489 static void 490 test77f(void) 491 { 492 struct sigaction act, oact; 493 char c, pname[PATH_MAX], tname[PATH_MAX]; 494 struct timeval tv; 495 fd_set fd_set; 496 int fd, maxfd, masterfd, slavefd; 497 498 subtest = 6; 499 500 /* We do not want to get SIGHUP signals in this test. */ 501 memset(&act, 0, sizeof(act)); 502 act.sa_handler = SIG_IGN; 503 if (sigaction(SIGHUP, &act, &oact) < 0) e(1); 504 505 /* Get master and slave device names for a free pseudo terminal. */ 506 get_names(pname, tname); 507 508 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(2); 509 510 switch (fork()) { 511 case 0: 512 if (setsid() < 0) e(3); 513 514 close(masterfd); 515 516 if ((slavefd = open(tname, O_RDWR)) < 0) e(4); 517 518 if ((fd = open("/dev/tty", O_RDWR)) < 0) e(5); 519 520 make_raw(fd); 521 522 /* Without slave input, /dev/tty is not ready for reading. */ 523 FD_ZERO(&fd_set); 524 FD_SET(fd, &fd_set); 525 tv.tv_sec = 0; 526 tv.tv_usec = 0; 527 528 if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 0) e(6); 529 if (FD_ISSET(fd, &fd_set)) e(7); 530 531 FD_SET(fd, &fd_set); 532 tv.tv_sec = 0; 533 tv.tv_usec = 10000; 534 535 if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 0) e(8); 536 if (FD_ISSET(fd, &fd_set)) e(9); 537 538 /* It will be ready for writing, though. */ 539 FD_SET(fd, &fd_set); 540 541 if (select(fd + 1, NULL, &fd_set, NULL, NULL) != 1) e(10); 542 if (!FD_ISSET(fd, &fd_set)) e(11); 543 544 /* Test mixing file descriptors to the same terminal. */ 545 FD_ZERO(&fd_set); 546 FD_SET(fd, &fd_set); 547 FD_SET(slavefd, &fd_set); 548 tv.tv_sec = 0; 549 tv.tv_usec = 10000; 550 551 maxfd = fd > slavefd ? fd : slavefd; 552 if (select(maxfd + 1, &fd_set, NULL, NULL, &tv) != 0) e(12); 553 if (FD_ISSET(fd, &fd_set)) e(13); 554 if (FD_ISSET(slavefd, &fd_set)) e(14); 555 556 /* The delayed echo on the master must wake up our select. */ 557 c = 'A'; 558 if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(15); 559 560 FD_ZERO(&fd_set); 561 FD_SET(fd, &fd_set); 562 563 if (select(fd + 1, &fd_set, NULL, NULL, NULL) != 1) e(16); 564 if (!FD_ISSET(fd, &fd_set)) e(17); 565 566 /* Select must now still flag readiness for reading. */ 567 tv.tv_sec = 0; 568 tv.tv_usec = 0; 569 570 if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 1) e(18); 571 if (!FD_ISSET(fd, &fd_set)) e(19); 572 573 /* That is, until we read the byte. */ 574 if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(20); 575 if (c != 'B') e(21); 576 577 if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 0) e(22); 578 if (FD_ISSET(fd, &fd_set)) e(23); 579 580 /* Ask the parent to close the master. */ 581 c = 'C'; 582 if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(24); 583 584 FD_SET(fd, &fd_set); 585 586 /* The closure must cause an EOF condition on the slave. */ 587 if (select(fd + 1, &fd_set, NULL, NULL, NULL) != 1) e(25); 588 if (!FD_ISSET(fd, &fd_set)) e(26); 589 590 if (select(fd + 1, &fd_set, NULL, NULL, NULL) != 1) e(27); 591 if (!FD_ISSET(fd, &fd_set)) e(28); 592 593 if (read(slavefd, &c, sizeof(c)) != 0) e(29); 594 595 exit(errct); 596 case -1: 597 e(30); 598 default: 599 /* Wait for the child to write something to the slave. */ 600 FD_ZERO(&fd_set); 601 FD_SET(masterfd, &fd_set); 602 603 if (select(masterfd + 1, &fd_set, NULL, NULL, NULL) != 1) 604 e(31); 605 if (!FD_ISSET(masterfd, &fd_set)) e(32); 606 607 if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(33); 608 if (c != 'A') e(34); 609 610 /* Write a reply once the child is blocked in its select. */ 611 tv.tv_sec = 1; 612 tv.tv_usec = 0; 613 if (select(masterfd + 1, &fd_set, NULL, NULL, &tv) != 0) 614 e(35); 615 616 c = 'B'; 617 if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(36); 618 619 /* Wait for the child to request closing the master. */ 620 if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(37); 621 if (c != 'C') e(38); 622 623 /* Close the master once the child is blocked in its select. */ 624 sleep(1); 625 626 close(masterfd); 627 628 break; 629 } 630 631 if (waitchild() < 0) e(39); 632 633 if (sigaction(SIGHUP, &oact, NULL) < 0) e(28); 634 } 635 636 int 637 main(int argc, char **argv) 638 { 639 int i, m; 640 641 start(77); 642 643 if (argc == 2) 644 m = atoi(argv[1]); 645 else 646 m = 0xFF; 647 648 for (i = 0; i < ITERATIONS; i++) { 649 if (m & 0x01) test77a(); 650 if (m & 0x02) test77b(); 651 if (m & 0x04) test77c(); 652 if (m & 0x08) test77d(); 653 if (m & 0x10) test77e(); 654 if (m & 0x20) test77f(); 655 } 656 657 quit(); 658 } 659