1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 /* 29 * Copyright (c) 2018, Joyent, Inc. 30 */ 31 32 33 #include <stdlib.h> 34 #include <stdio.h> 35 #include <fcntl.h> 36 #include <errno.h> 37 #include <poll.h> 38 #include <string.h> 39 #include <termio.h> 40 #include <signal.h> 41 #include <sys/types.h> 42 #include <sys/stropts.h> 43 #include <unistd.h> 44 #include <sys/wait.h> 45 #include "ttymon.h" 46 #include "tmstruct.h" 47 #include "tmextern.h" 48 #include "sac.h" 49 50 static struct pmtab *find_pid(pid_t); 51 static void kill_subprocesses(void); 52 53 static struct pmtab *find_fd(int); 54 static void pcsync_close(int *, int *, int, int); 55 56 /* 57 * fork_tmchild - fork child on the device 58 */ 59 static void 60 fork_tmchild(struct pmtab *pmptr) 61 { 62 pid_t pid; 63 sigset_t cset; 64 sigset_t tset; 65 int pcpipe0[2], pcpipe1[2]; 66 int p0; 67 68 #ifdef DEBUG 69 debug("in fork_tmchild"); 70 #endif 71 pmptr->p_inservice = FALSE; 72 73 /* 74 * initialize pipe. 75 * Child has pcpipe[0] pipe fd for reading and writing 76 * and closes pcpipe[1]. Parent has pcpipe[1] pipe fd for 77 * reading and writing and closes pcpipe[0]. 78 * 79 * This way if the child process exits the parent's block 80 * read on pipe will return immediately as the other end of 81 * the pipe has closed. Similarly if the parent process exits 82 * child's blocking read on the pipe will return immediately. 83 */ 84 85 if (((p0 = pipe(pcpipe0)) == -1) || (pipe(pcpipe1) == -1)) { 86 if (p0 == 0) { 87 (void) close(pcpipe0[0]); 88 (void) close(pcpipe0[1]); 89 } 90 log("pipe() failed: %s", strerror(errno)); 91 pmptr->p_status = VALID; 92 pmptr->p_childpid = 0; 93 Retry = TRUE; 94 } 95 96 /* protect following region from SIGCLD */ 97 (void) sigprocmask(SIG_SETMASK, NULL, &cset); 98 tset = cset; 99 (void) sigaddset(&tset, SIGCLD); 100 (void) sigprocmask(SIG_SETMASK, &tset, NULL); 101 if ((pid = fork()) == 0) { 102 /* 103 * Close all file descriptors except pmptr->p_fd 104 * Wait for the parent process to close its fd 105 */ 106 pcsync_close(pcpipe0, pcpipe1, pid, pmptr->p_fd); 107 /* The CHILD */ 108 tmchild(pmptr); 109 /* tmchild should never return */ 110 fatal("tmchild for <%s> returns unexpected", pmptr->p_device); 111 } else if (pid < 0) { 112 log("fork failed: %s", strerror(errno)); 113 pmptr->p_status = VALID; 114 pmptr->p_childpid = 0; 115 Retry = TRUE; 116 } else { 117 /* 118 * The PARENT - store pid of child and close the device 119 */ 120 pmptr->p_childpid = pid; 121 } 122 if (pmptr->p_fd > 0) { 123 (void) close(pmptr->p_fd); 124 pmptr->p_fd = 0; 125 } 126 (void) sigprocmask(SIG_SETMASK, &cset, NULL); 127 /* 128 * Wait for child to close file descriptors 129 */ 130 pcsync_close(pcpipe0, pcpipe1, pid, pmptr->p_fd); 131 } 132 133 /* 134 * got_carrier - carrier is detected on the stream 135 * - depends on the flags, different action is taken 136 * - R_FLAG - wait for data 137 * - C_FLAG - if port is not disabled, fork tmchild 138 * - A_FLAG - wait for data 139 * - otherwise - write out prompt, then wait for data 140 */ 141 void 142 got_carrier(struct pmtab *pmptr) 143 { 144 flush_input(pmptr->p_fd); 145 146 if (pmptr->p_ttyflags & R_FLAG) { 147 #ifdef DEBUG 148 debug("R_FLAG"); 149 #endif 150 return; 151 } else if ((pmptr->p_ttyflags & (C_FLAG|B_FLAG)) && 152 (State != PM_DISABLED) && 153 (!(pmptr->p_flags & X_FLAG))) { 154 fork_tmchild(pmptr); 155 } else if (pmptr->p_ttyflags & A_FLAG) { 156 #ifdef DEBUG 157 debug("A_FLAG"); 158 #endif 159 return; 160 } else if (pmptr->p_timeout) { 161 fork_tmchild(pmptr); 162 } else if (!(pmptr->p_ttyflags & X_FLAG)) { 163 write_prompt(pmptr->p_fd, pmptr, TRUE, TRUE); 164 } 165 } 166 167 /* 168 * got_data - data is detected on the stream, fork tmchild 169 */ 170 static void 171 got_data(struct pmtab *pmptr) 172 { 173 struct sigaction sigact; 174 175 if (tm_checklock(pmptr->p_fd) != 0) { 176 pmptr->p_status = LOCKED; 177 (void) close(pmptr->p_fd); 178 pmptr->p_fd = 0; 179 Nlocked++; 180 if (Nlocked == 1) { 181 sigact.sa_flags = 0; 182 sigact.sa_handler = sigalarm; 183 (void) sigemptyset(&sigact.sa_mask); 184 (void) sigaction(SIGALRM, &sigact, NULL); 185 (void) alarm(ALARMTIME); 186 } 187 } else { 188 fork_tmchild(pmptr); 189 } 190 } 191 /* 192 * got_hup - stream hangup is detected, close the device 193 */ 194 static void 195 got_hup(struct pmtab *pmptr) 196 { 197 #ifdef DEBUG 198 debug("in got hup"); 199 #endif 200 (void) close(pmptr->p_fd); 201 pmptr->p_fd = 0; 202 pmptr->p_inservice = 0; 203 Retry = TRUE; 204 } 205 206 207 /* 208 * do_poll - poll device 209 * - if POLLHUP received, close the device 210 * - if POLLIN received, fork tmchild. 211 */ 212 void 213 do_poll(struct pollfd *fdp, int nfds) 214 { 215 int i, n; 216 struct pmtab *pmptr; 217 218 n = poll(fdp, (unsigned long)nfds, -1); /* blocked poll */ 219 #ifdef DEBUG 220 debug("poll return"); 221 #endif 222 if (n < 0) { 223 if (errno == EINTR) /* interrupt by signal */ 224 return; 225 fatal("do_poll: poll failed: %s", strerror(errno)); 226 } 227 for (i = 0; (i < nfds) && (n != 0); i++, fdp++) { 228 if (fdp->revents != 0) { 229 n--; 230 if ((pmptr = find_fd(fdp->fd)) == NULL) { 231 log("do_poll: cannot find fd %d in pmtab", 232 fdp->fd); 233 continue; 234 } else if (fdp->revents & POLLHUP) { 235 got_hup(pmptr); 236 } else if (fdp->revents & POLLIN) { 237 #ifdef DEBUG 238 debug("got POLLIN"); 239 #endif 240 got_data(pmptr); 241 } else if (fdp->revents & POLLERR) { 242 fatal("ttymon[%d]: do_poll: POLLERR on fd %d", 243 getpid(), fdp->fd); 244 } 245 } 246 } 247 } 248 249 /* 250 * sigchild - handler for SIGCLD 251 * - find the pid of dead child 252 * - clean utmp if U_FLAG is set 253 */ 254 void 255 sigchild(int n __unused) 256 { 257 struct pmtab *pmptr; 258 siginfo_t info; 259 int status; 260 pid_t pid; 261 int rcode; 262 263 #ifdef DEBUG 264 debug("in sigchild"); 265 #endif 266 267 /* find all processes that died */ 268 for (;;) { 269 rcode = waitid(P_ALL, 0, &info, WNOHANG|WEXITED); 270 if (rcode == -1 && errno == EINTR) 271 continue; 272 273 /* If no more children have exited, just return */ 274 if (rcode == -1 || (pid = info.si_pid) == 0) 275 break; 276 277 /* construct status as returned from waitid() */ 278 status = info.si_status & 0377; 279 switch (info.si_code) { 280 case CLD_EXITED: 281 status <<= 8; 282 break; 283 case CLD_DUMPED: 284 status |= WCOREFLG; 285 break; 286 case CLD_KILLED: 287 break; 288 } 289 290 if ((pmptr = find_pid(pid)) == NULL) { 291 #ifdef DEBUG 292 log("cannot find dead child (%ld) in pmtab", pid); 293 #endif 294 /* 295 * This may happen if the entry is deleted from pmtab 296 * before the service exits. 297 * We try to cleanup utmp entry 298 */ 299 cleanut(pid, status); 300 } else { 301 if (pmptr->p_flags & U_FLAG) 302 cleanut(pid, status); 303 pmptr->p_status = VALID; 304 pmptr->p_fd = 0; 305 pmptr->p_childpid = 0; 306 pmptr->p_inservice = 0; 307 Retry = TRUE; 308 } 309 } 310 } 311 312 /* 313 * sigterm - handler for SIGTERM 314 */ 315 void 316 sigterm(int _s __unused) 317 { 318 fatal("caught SIGTERM"); 319 } 320 321 /* 322 * state_change - this is called when ttymon changes 323 * its internal state between enabled and disabled 324 */ 325 void 326 state_change(void) 327 { 328 struct pmtab *pmptr; 329 330 #ifdef DEBUG 331 debug("in state_change"); 332 #endif 333 334 /* 335 * closing PCpipe will cause attached non-service children 336 * to get SIGPOLL and exit 337 */ 338 (void) close(PCpipe[0]); 339 (void) close(PCpipe[1]); 340 341 /* reopen PCpipe */ 342 setup_PCpipe(); 343 344 /* 345 * also close all open ports so ttymon can start over 346 * with new internal state 347 */ 348 for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) { 349 if ((pmptr->p_fd > 0) && (pmptr->p_childpid == 0)) { 350 (void) close(pmptr->p_fd); 351 pmptr->p_fd = 0; 352 } 353 } 354 Retry = TRUE; 355 356 } 357 358 /* 359 * re_read - reread pmtab 360 * - kill tmchild if entry changed 361 */ 362 void 363 re_read(void) 364 { 365 sigset_t cset; 366 sigset_t tset; 367 368 (void) sigprocmask(SIG_SETMASK, NULL, &cset); 369 tset = cset; 370 (void) sigaddset(&tset, SIGCLD); 371 (void) sigprocmask(SIG_SETMASK, &tset, NULL); 372 if (Nlocked > 0) { 373 (void) alarm(0); 374 Nlocked = 0; 375 } 376 read_pmtab(); 377 kill_subprocesses(); 378 (void) sigprocmask(SIG_SETMASK, &cset, NULL); 379 purge(); 380 381 if (Nentries > Npollfd) { 382 #ifdef DEBUG 383 debug("Nentries > Npollfd, reallocating pollfds"); 384 #endif 385 /* need to malloc more pollfd structure */ 386 free(Pollp); 387 Npollfd = Nentries + 10; 388 if (Npollfd > Maxfds) 389 Npollfd = Maxfds; 390 Pollp = malloc((unsigned)(Npollfd * sizeof (struct pollfd))); 391 if (Pollp == NULL) 392 fatal("malloc for Pollp failed"); 393 } 394 Retry = TRUE; 395 } 396 397 /* 398 * find_pid(pid) - find the corresponding pmtab entry for the pid 399 */ 400 static struct pmtab * 401 find_pid(pid_t pid) 402 { 403 struct pmtab *pmptr; 404 405 for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) { 406 if (pmptr->p_childpid == pid) { 407 return (pmptr); 408 } 409 } 410 return (NULL); 411 } 412 413 /* 414 * find_fd(fd) - find the corresponding pmtab entry for the fd 415 */ 416 static struct pmtab * 417 find_fd(int fd) 418 { 419 struct pmtab *pmptr; 420 421 for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) { 422 if (pmptr->p_fd == fd) { 423 return (pmptr); 424 } 425 } 426 return (NULL); 427 } 428 429 /* 430 * kill_subprocesses() - if the pmtab entry has been changed, 431 * kill tmchild if it is not in service. 432 * - close the device if there is no tmchild 433 */ 434 static void 435 kill_subprocesses(void) 436 { 437 struct pmtab *pmptr; 438 439 for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) { 440 if (pmptr->p_status == VALID) 441 continue; 442 if ((pmptr->p_fd > 0) && (pmptr->p_childpid == 0)) { 443 (void) close(pmptr->p_fd); 444 pmptr->p_fd = 0; 445 } else if ((pmptr->p_fd == 0) && (pmptr->p_childpid > 0) && 446 (pmptr->p_inservice == FALSE)) { 447 (void) kill(pmptr->p_childpid, SIGTERM); 448 } 449 } 450 } 451 452 static void 453 mark_service(pid_t pid) 454 { 455 struct pmtab *pmptr; 456 #ifdef DEBUG 457 debug("in mark_service"); 458 #endif 459 if ((pmptr = find_pid(pid)) == NULL) { 460 log("mark_service: cannot find child (%ld) in pmtab", pid); 461 return; 462 } 463 pmptr->p_inservice = TRUE; 464 } 465 466 /* 467 * read_pid(fd) - read pid info from PCpipe 468 */ 469 static void 470 read_pid(int fd) 471 { 472 int ret; 473 pid_t pid; 474 475 for (;;) { 476 if ((ret = read(fd, &pid, sizeof (pid))) < 0) { 477 if (errno == EINTR) 478 continue; 479 if (errno == EAGAIN) 480 return; 481 fatal("read PCpipe failed: %s", strerror(errno)); 482 } 483 if (ret == 0) 484 return; 485 if (ret != sizeof (pid)) 486 fatal("read return size incorrect, ret = %d", ret); 487 488 mark_service(pid); 489 } 490 } 491 492 /* 493 * sipoll_catch() - signal handle of SIGPOLL for ttymon 494 * - it will check both PCpipe and pmpipe 495 */ 496 void 497 sigpoll_catch(int s __unused) 498 { 499 int ret; 500 struct pollfd pfd[2]; 501 502 #ifdef DEBUG 503 debug("in sigpoll_catch"); 504 #endif 505 506 pfd[0].fd = PCpipe[0]; 507 pfd[1].fd = Pfd; 508 pfd[0].events = POLLIN; 509 pfd[1].events = POLLIN; 510 if ((ret = poll(pfd, 2, 0)) < 0) 511 fatal("sigpoll_catch: poll failed: %s", strerror(errno)); 512 513 if (ret > 0) { 514 if (pfd[0].revents & POLLIN) 515 read_pid(pfd[0].fd); 516 if (pfd[1].revents & POLLIN) 517 sacpoll(); 518 } 519 } 520 521 void 522 sigalarm(int signo __unused) 523 { 524 struct pmtab *pmptr; 525 struct sigaction sigact; 526 int fd; 527 528 #ifdef DEBUG 529 debug("in sigalarm, Nlocked = %d", Nlocked); 530 #endif 531 for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) { 532 if ((pmptr->p_status == LOCKED) && (pmptr->p_fd == 0)) { 533 fd = open(pmptr->p_device, O_RDWR | O_NONBLOCK); 534 if (fd == -1) { 535 log("open (%s) failed: %s", pmptr->p_device, 536 strerror(errno)); 537 pmptr->p_status = VALID; 538 Nlocked--; 539 Retry = TRUE; 540 } else { 541 if (tm_checklock(fd) == 0) { 542 Nlocked--; 543 pmptr->p_fd = fd; 544 Retry = TRUE; 545 } else { 546 (void) close(fd); 547 } 548 } 549 } else if ((pmptr->p_status == SESSION) && (pmptr->p_fd == 0)) { 550 fd = open(pmptr->p_device, O_RDWR | O_NONBLOCK); 551 if (fd == -1) { 552 log("open (%s) failed: %s", pmptr->p_device, 553 strerror(errno)); 554 pmptr->p_status = VALID; 555 Nlocked--; 556 Retry = TRUE; 557 } else { 558 if (check_session(fd) == 0) { 559 Nlocked--; 560 pmptr->p_fd = fd; 561 Retry = TRUE; 562 } else { 563 (void) close(fd); 564 } 565 } 566 } else if ((pmptr->p_status == UNACCESS) && 567 (pmptr->p_fd == 0)) { 568 fd = open(pmptr->p_device, O_RDWR | O_NONBLOCK); 569 if (fd == -1) { 570 log("open (%s) failed: %s", pmptr->p_device, 571 strerror(errno)); 572 pmptr->p_status = VALID; 573 Nlocked--; 574 Retry = TRUE; 575 } else { 576 Nlocked--; 577 pmptr->p_fd = fd; 578 Retry = TRUE; 579 } 580 } 581 } 582 if (Nlocked > 0) { 583 sigact.sa_flags = 0; 584 sigact.sa_handler = sigalarm; 585 (void) sigemptyset(&sigact.sa_mask); 586 (void) sigaction(SIGALRM, &sigact, NULL); 587 (void) alarm(ALARMTIME); 588 } else { 589 sigact.sa_flags = 0; 590 sigact.sa_handler = SIG_IGN; 591 (void) sigemptyset(&sigact.sa_mask); 592 (void) sigaction(SIGALRM, &sigact, NULL); 593 } 594 } 595 596 /* 597 * pcsync_close - For the child process close all open fd's except 598 * the one that is passed to the routine. Coordinate the reads and 599 * writes to the pipes by the parent and child process to ensure 600 * the parent and child processes have closed all the file descriptors 601 * that are not needed any more. 602 */ 603 static void 604 pcsync_close(int *p0, int *p1, int pid, int fd) 605 { 606 char ch; 607 608 if (pid == 0) { /* Child */ 609 struct pmtab *tp; 610 for (tp = PMtab; tp; tp = tp->p_next) 611 if ((tp->p_fd > 0) && (tp->p_fd != fd)) 612 (void) close(tp->p_fd); 613 (void) close(p0[1]); 614 (void) close(p1[0]); 615 if (read(p0[0], &ch, 1) == 1) 616 (void) write(p1[1], "a", 1); 617 (void) close(p0[0]); 618 (void) close(p1[1]); 619 } else { /* Parent */ 620 (void) close(p0[0]); 621 (void) close(p1[1]); 622 if (write(p0[1], "a", 1) == 1) 623 (void) read(p1[0], &ch, 1); 624 (void) close(p0[1]); 625 (void) close(p1[0]); 626 } 627 } 628