1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Donn Seeley at UUNET Technologies, Inc. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 char copyright[] = 13 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 14 All rights reserved.\n"; 15 #endif /* not lint */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)init.c 6.11.1.1 (Berkeley) 07/19/92"; 19 #endif /* not lint */ 20 21 #include <sys/types.h> 22 #include <sys/wait.h> 23 #include <db.h> 24 #include <errno.h> 25 #include <fcntl.h> 26 #include <signal.h> 27 #include <syslog.h> 28 #include <time.h> 29 #include <ttyent.h> 30 #include <unistd.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 35 #ifdef __STDC__ 36 #include <stdarg.h> 37 #else 38 #include <varargs.h> 39 #endif 40 41 #ifdef SECURE 42 #include <pwd.h> 43 #endif 44 45 #include "pathnames.h" 46 47 /* 48 * Until the mythical util.h arrives... 49 */ 50 extern int login_tty __P((int)); 51 extern int logout __P((const char *)); 52 extern void logwtmp __P((const char *, const char *, const char *)); 53 54 /* 55 * Sleep times; used to prevent thrashing. 56 */ 57 #define GETTY_SPACING 10 /* fork getty on a port every N secs */ 58 #define WINDOW_WAIT 3 /* wait N secs after starting window */ 59 #define STALL_TIMEOUT 30 /* wait N secs after warning */ 60 #define DEATH_WATCH 10 /* wait N secs for procs to die */ 61 62 void handle __P((sig_t, ...)); 63 void delset __P((sigset_t *, ...)); 64 65 void stall __P((char *, ...)); 66 void warning __P((char *, ...)); 67 void emergency __P((char *, ...)); 68 void disaster __P((int)); 69 70 /* 71 * We really need a recursive typedef... 72 * The following at least guarantees that the return type of (*state_t)() 73 * is sufficiently wide to hold a function pointer. 74 */ 75 typedef long (*state_func_t) __P((void)); 76 typedef state_func_t (*state_t) __P((void)); 77 78 state_func_t single_user __P((void)); 79 state_func_t runcom __P((void)); 80 state_func_t read_ttys __P((void)); 81 state_func_t multi_user __P((void)); 82 state_func_t clean_ttys __P((void)); 83 state_func_t catatonia __P((void)); 84 state_func_t death __P((void)); 85 86 enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT; 87 88 void transition __P((state_t)); 89 state_t requested_transition = runcom; 90 91 void setctty __P((char *)); 92 93 typedef struct session { 94 int se_index; /* index of entry in ttys file */ 95 pid_t se_process; /* controlling process */ 96 time_t se_started; /* used to avoid thrashing */ 97 int se_flags; /* status of session */ 98 #define SE_SHUTDOWN 0x1 /* session won't be restarted */ 99 char *se_device; /* filename of port */ 100 char *se_getty; /* what to run on that port */ 101 char **se_getty_argv; /* pre-parsed argument array */ 102 char *se_window; /* window system (started only once) */ 103 char **se_window_argv; /* pre-parsed argument array */ 104 struct session *se_prev; 105 struct session *se_next; 106 } session_t; 107 108 void free_session __P((session_t *)); 109 session_t *new_session __P((session_t *, int, struct ttyent *)); 110 session_t *sessions; 111 112 char **construct_argv __P((char *)); 113 void start_window_system __P((session_t *)); 114 void collect_child __P((int)); 115 pid_t start_getty __P((session_t *)); 116 void transition_handler __P((int)); 117 void alrm_handler __P((int)); 118 int clang; 119 120 int start_logger __P((void)); 121 void clear_session_logs __P((session_t *)); 122 int logger_enable; 123 124 int start_session_db __P((void)); 125 void add_session __P((session_t *)); 126 void del_session __P((session_t *)); 127 session_t *find_session __P((pid_t)); 128 DB *session_db; 129 130 /* 131 * The mother of all processes. 132 */ 133 int 134 main(argc, argv) 135 int argc; 136 char **argv; 137 { 138 int c; 139 struct sigaction sa; 140 sigset_t mask; 141 142 143 /* Dispose of random users. */ 144 if (getuid() != 0) { 145 (void)fprintf(stderr, "init: %s\n", strerror(EPERM)); 146 exit (1); 147 } 148 149 /* System V users like to reexec init. */ 150 if (getpid() != 1) { 151 (void)fprintf(stderr, "init: already running\n"); 152 exit (1); 153 } 154 155 /* 156 * Note that this does NOT open a file... 157 * Does 'init' deserve its own facility number? 158 */ 159 openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); 160 161 /* 162 * Create an initial session. 163 */ 164 if (setsid() < 0) 165 syslog(LOG_ERR, "setsid failed (initial) %m"); 166 167 /* 168 * This code assumes that we always get arguments through flags, 169 * never through bits set in some random machine register. 170 */ 171 while ((c = getopt(argc, argv, "sf")) != -1) 172 switch (c) { 173 case 's': 174 requested_transition = single_user; 175 break; 176 case 'f': 177 runcom_mode = FASTBOOT; 178 break; 179 default: 180 warning("unrecognized flag '-%c'", c); 181 break; 182 } 183 184 if (optind != argc) 185 warning("ignoring excess arguments"); 186 187 /* 188 * We catch or block signals rather than ignore them, 189 * so that they get reset on exec. 190 */ 191 handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV, 192 SIGBUS, SIGSYS, SIGXCPU, SIGXFSZ, 0); 193 handle(transition_handler, SIGHUP, SIGTERM, SIGTSTP, 0); 194 handle(alrm_handler, SIGALRM, 0); 195 sigfillset(&mask); 196 delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS, 197 SIGXCPU, SIGXFSZ, SIGHUP, SIGTERM, SIGTSTP, SIGALRM, 0); 198 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 199 sigemptyset(&sa.sa_mask); 200 sa.sa_flags = 0; 201 sa.sa_handler = SIG_IGN; 202 (void) sigaction(SIGTTIN, &sa, (struct sigaction *)0); 203 (void) sigaction(SIGTTOU, &sa, (struct sigaction *)0); 204 205 /* 206 * Paranoia. 207 */ 208 close(0); 209 close(1); 210 close(2); 211 212 /* 213 * Start the state machine. 214 */ 215 transition(requested_transition); 216 217 /* 218 * Should never reach here. 219 */ 220 return 1; 221 } 222 223 /* 224 * Associate a function with a signal handler. 225 */ 226 void 227 #ifdef __STDC__ 228 handle(sig_t handler, ...) 229 #else 230 handle(va_alist) 231 va_dcl 232 #endif 233 { 234 int sig; 235 struct sigaction sa; 236 int mask_everything; 237 va_list ap; 238 #ifndef __STDC__ 239 sig_t handler; 240 241 va_start(ap); 242 handler = va_arg(ap, sig_t); 243 #else 244 va_start(ap, handler); 245 #endif 246 247 sa.sa_handler = handler; 248 sigfillset(&mask_everything); 249 250 while (sig = va_arg(ap, int)) { 251 sa.sa_mask = mask_everything; 252 /* XXX SA_RESTART? */ 253 sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0; 254 sigaction(sig, &sa, (struct sigaction *) 0); 255 } 256 } 257 258 /* 259 * Delete a set of signals from a mask. 260 */ 261 void 262 #ifdef __STDC__ 263 delset(sigset_t *maskp, ...) 264 #else 265 delset(va_alist) 266 va_dcl 267 #endif 268 { 269 int sig; 270 va_list ap; 271 #ifndef __STDC__ 272 sigset_t *maskp; 273 274 va_start(ap); 275 maskp = va_arg(ap, sigset_t *); 276 #else 277 va_start(ap, maskp); 278 #endif 279 280 while (sig = va_arg(ap, int)) 281 sigdelset(maskp, sig); 282 } 283 284 /* 285 * Log a message and sleep for a while (to give someone an opportunity 286 * to read it and to save log or hardcopy output if the problem is chronic). 287 * NB: should send a message to the session logger to avoid blocking. 288 */ 289 void 290 #ifdef __STDC__ 291 stall(char *message, ...) 292 #else 293 stall(va_alist) 294 va_dcl 295 #endif 296 { 297 pid_t pid; 298 va_list ap; 299 #ifndef __STDC__ 300 char *message; 301 302 va_start(ap); 303 message = va_arg(ap, char *); 304 #else 305 va_start(ap, message); 306 #endif 307 308 vsyslog(LOG_ALERT, message, ap); 309 va_end(ap); 310 sleep(STALL_TIMEOUT); 311 } 312 313 /* 314 * Like stall(), but doesn't sleep. 315 * If cpp had variadic macros, the two functions could be #defines for another. 316 * NB: should send a message to the session logger to avoid blocking. 317 */ 318 void 319 #ifdef __STDC__ 320 warning(char *message, ...) 321 #else 322 warning(va_alist) 323 va_dcl 324 #endif 325 { 326 va_list ap; 327 #ifndef __STDC__ 328 char *message; 329 330 va_start(ap); 331 message = va_arg(ap, char *); 332 #else 333 va_start(ap, message); 334 #endif 335 336 vsyslog(LOG_ALERT, message, ap); 337 va_end(ap); 338 } 339 340 /* 341 * Log an emergency message. 342 * NB: should send a message to the session logger to avoid blocking. 343 */ 344 void 345 #ifdef __STDC__ 346 emergency(char *message, ...) 347 #else 348 emergency(va_alist) 349 va_dcl 350 #endif 351 { 352 va_list ap; 353 #ifndef __STDC__ 354 char *message; 355 356 va_start(ap); 357 message = va_arg(ap, char *); 358 #else 359 va_start(ap, message); 360 #endif 361 362 vsyslog(LOG_EMERG, message, ap); 363 va_end(ap); 364 } 365 366 /* 367 * Catch an unexpected signal. 368 */ 369 void 370 disaster(sig) 371 int sig; 372 { 373 emergency("fatal signal: %s", 374 sig < (unsigned) NSIG ? sys_siglist[sig] : "unknown signal"); 375 376 sleep(STALL_TIMEOUT); 377 _exit(sig); /* reboot */ 378 } 379 380 /* 381 * Change states in the finite state machine. 382 * The initial state is passed as an argument. 383 */ 384 void 385 transition(s) 386 state_t s; 387 { 388 for (;;) 389 s = (state_t) (*s)(); 390 } 391 392 /* 393 * We send requests for session logging to another process for two reasons. 394 * First, we don't want to block if the log files go away (e.g. because 395 * one or more are on hard-mounted NFS systems whose server crashes). 396 * Second, despite all the crud already contained in init, it still isn't 397 * right that init should care about session logging record formats and files. 398 * We could use explicit 'Unix' IPC for this, but let's try to be POSIX... 399 */ 400 int 401 start_logger() 402 { 403 static char *argv[] = { _PATH_SLOGGER, 0 }; 404 int fd, pfd[2]; 405 pid_t pid; 406 sigset_t mask; 407 408 if (pipe(pfd) == -1) { 409 warning("session logging disabled: can't make pipe to %s: %m", 410 argv[0]); 411 return -1; 412 } 413 if ((pid = fork()) == -1) { 414 emergency("session logging disabled: can't fork for %s: %m", 415 argv[0]); 416 return -1; 417 } 418 419 if (pid == 0) { 420 close(pfd[1]); 421 if (pfd[0] != 0) { 422 dup2(pfd[0], 0); 423 close(pfd[0]); 424 } 425 if ((fd = open(_PATH_DEVNULL, O_WRONLY)) != -1) { 426 if (fd != 1) 427 dup2(fd, 1); 428 if (fd != 2) 429 dup2(fd, 2); 430 if (fd != 1 && fd != 2) 431 close(fd); 432 } else { 433 /* paranoid */ 434 close(1); 435 close(2); 436 } 437 sigemptyset(&mask); 438 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 439 execv(argv[0], argv); 440 stall("can't exec %s: %m", argv[0]); 441 _exit(1); 442 } 443 444 close(pfd[0]); 445 fcntl(pfd[1], F_SETFD, FD_CLOEXEC); 446 fcntl(pfd[1], F_SETFL, O_NONBLOCK); 447 448 return pfd[1]; 449 } 450 451 /* 452 * Close out the accounting files for a login session. 453 * NB: should send a message to the session logger to avoid blocking. 454 */ 455 void 456 clear_session_logs(sp) 457 session_t *sp; 458 { 459 char *line = sp->se_device + sizeof(_PATH_DEV) - 1; 460 461 if (logout(line)) 462 logwtmp(line, "", ""); 463 } 464 465 /* 466 * Start a session and allocate a controlling terminal. 467 * Only called by children of init after forking. 468 */ 469 void 470 setctty(name) 471 char *name; 472 { 473 int fd; 474 475 (void) revoke(name); 476 if ((fd = open(name, O_RDWR)) == -1) { 477 stall("can't open %s: %m", name); 478 _exit(1); 479 } 480 if (login_tty(fd) == -1) { 481 stall("can't get %s for controlling terminal: %m", name); 482 _exit(1); 483 } 484 } 485 486 /* 487 * Bring the system up single user. 488 */ 489 state_func_t 490 single_user() 491 { 492 pid_t pid, wpid; 493 int status; 494 sigset_t mask; 495 char *shell = _PATH_BSHELL; 496 char *argv[2]; 497 #ifdef SECURE 498 struct ttyent *typ; 499 struct passwd *pp; 500 static const char banner[] = 501 "Enter root password, or ^D to go multi-user\n"; 502 char *password; 503 #endif 504 505 if ((pid = fork()) == 0) { 506 /* 507 * Start the single user session. 508 */ 509 setctty(_PATH_CONSOLE); 510 511 #ifdef KTRACEHACK 512 { 513 static int tracing = 0; 514 int foo, pid; 515 516 if (tracing) goto skip; 517 foo = open("/traceinit", O_RDONLY, 0); 518 if (foo != -1) { 519 close(foo); 520 if ((pid = fork()) == 0) { 521 execl("/sbin/mount", "mount", "-uw", 522 "/", 0); 523 _exit(-1); 524 } 525 waitpid(pid, 0, 0); 526 if (fork() == 0) { 527 execl("/ktrace", "ktrace", "-aip", 528 "1", 0); 529 _exit(-1); 530 } 531 waitpid(pid, 0, 0); 532 tracing = 1; 533 } 534 skip: ; 535 } 536 #endif /* KTRACEHACK */ 537 538 #ifdef DEBUGSHELL 539 { 540 char altshell[128], *cp = altshell; 541 int num; 542 543 #define SHREQUEST \ 544 "Enter pathname of shell or RETURN for sh: " 545 (void)write(STDERR_FILENO, 546 SHREQUEST, sizeof(SHREQUEST) - 1); 547 while ((num = read(STDIN_FILENO, cp, 1)) != -1 && 548 num != 0 && *cp != '\n' && cp < &altshell[127]) 549 cp++; 550 *cp = '\0'; 551 if (altshell[0] != '\0') 552 shell = altshell; 553 } 554 #endif /* DEBUGSHELL */ 555 556 #ifdef SECURE 557 /* 558 * Check the root password. 559 * We don't care if the console is 'on' by default; 560 * it's the only tty that can be 'off' and 'secure'. 561 */ 562 typ = getttynam("console"); 563 pp = getpwnam("root"); 564 if (typ && (typ->ty_status & TTY_SECURE) == 0 && pp) { 565 write(2, banner, sizeof banner - 1); 566 for (;;) { 567 password = getpass("Password:"); 568 if (password == 0 || *password == '\0') 569 _exit(0); 570 password = crypt(password, pp->pw_passwd); 571 if (strcmp(password, pp->pw_passwd) == 0) 572 break; 573 } 574 } 575 #ifdef notdef 576 /* 577 * Make the single-user shell be root's standard shell? 578 */ 579 if (pp && pp->pw_shell) 580 shell = pp->pw_shell; 581 #endif 582 endttyent(); 583 endpwent(); 584 #endif 585 586 /* 587 * Unblock signals. 588 * We catch all the interesting ones, 589 * and those are reset to SIG_DFL on exec. 590 */ 591 sigemptyset(&mask); 592 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 593 594 /* 595 * Fire off a shell. 596 * If the default one doesn't work, try the Bourne shell. 597 */ 598 argv[0] = "-sh"; 599 argv[1] = 0; 600 execv(shell, argv); 601 emergency("can't exec %s for single user: %m", shell); 602 execv(_PATH_BSHELL, argv); 603 emergency("can't exec %s for single user: %m", _PATH_BSHELL); 604 sleep(STALL_TIMEOUT); 605 _exit(1); 606 } 607 608 if (pid == -1) { 609 /* 610 * We are seriously hosed. Do our best. 611 */ 612 emergency("can't fork single-user shell, trying again"); 613 while (waitpid(-1, (int *) 0, WNOHANG) > 0) 614 continue; 615 return (state_func_t) single_user; 616 } 617 618 requested_transition = 0; 619 do { 620 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 621 collect_child(wpid); 622 if (wpid == -1) { 623 if (errno == EINTR) 624 continue; 625 warning("wait for single-user shell failed: %m; restarting"); 626 return (state_func_t) single_user; 627 } 628 if (wpid == pid && WIFSTOPPED(status)) { 629 warning("init: shell stopped, restarting\n"); 630 kill(pid, SIGCONT); 631 wpid = -1; 632 } 633 } while (wpid != pid && !requested_transition); 634 635 if (requested_transition) 636 return (state_func_t) requested_transition; 637 638 if (!WIFEXITED(status)) { 639 if (WTERMSIG(status) == SIGKILL) { 640 /* 641 * reboot(8) killed shell? 642 */ 643 warning("single user shell terminated."); 644 sleep(STALL_TIMEOUT); 645 _exit(0); 646 } else { 647 warning("single user shell terminated, restarting"); 648 return (state_func_t) single_user; 649 } 650 } 651 652 runcom_mode = FASTBOOT; 653 return (state_func_t) runcom; 654 } 655 656 /* 657 * Run the system startup script. 658 */ 659 state_func_t 660 runcom() 661 { 662 pid_t pid, wpid; 663 int status; 664 char *argv[4]; 665 struct sigaction sa; 666 667 if ((pid = fork()) == 0) { 668 sigemptyset(&sa.sa_mask); 669 sa.sa_flags = 0; 670 sa.sa_handler = SIG_IGN; 671 (void) sigaction(SIGTSTP, &sa, (struct sigaction *)0); 672 (void) sigaction(SIGHUP, &sa, (struct sigaction *)0); 673 674 setctty(_PATH_CONSOLE); 675 676 argv[0] = "sh"; 677 argv[1] = _PATH_RUNCOM; 678 argv[2] = runcom_mode == AUTOBOOT ? "autoboot" : 0; 679 argv[3] = 0; 680 681 sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0); 682 683 execv(_PATH_BSHELL, argv); 684 stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNCOM); 685 _exit(1); /* force single user mode */ 686 } 687 688 if (pid == -1) { 689 emergency("can't fork for %s on %s: %m", 690 _PATH_BSHELL, _PATH_RUNCOM); 691 while (waitpid(-1, (int *) 0, WNOHANG) > 0) 692 continue; 693 sleep(STALL_TIMEOUT); 694 return (state_func_t) single_user; 695 } 696 697 /* 698 * Copied from single_user(). This is a bit paranoid. 699 */ 700 do { 701 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 702 collect_child(wpid); 703 if (wpid == -1) { 704 if (errno == EINTR) 705 continue; 706 warning("wait for %s on %s failed: %m; going to single user mode", 707 _PATH_BSHELL, _PATH_RUNCOM); 708 return (state_func_t) single_user; 709 } 710 if (wpid == pid && WIFSTOPPED(status)) { 711 warning("init: %s on %s stopped, restarting\n", 712 _PATH_BSHELL, _PATH_RUNCOM); 713 kill(pid, SIGCONT); 714 wpid = -1; 715 } 716 } while (wpid != pid); 717 718 if (!WIFEXITED(status)) { 719 warning("%s on %s terminated abnormally, going to single user mode", 720 _PATH_BSHELL, _PATH_RUNCOM); 721 return (state_func_t) single_user; 722 } 723 724 if (WEXITSTATUS(status)) 725 return (state_func_t) single_user; 726 727 runcom_mode = AUTOBOOT; /* the default */ 728 /* NB: should send a message to the session logger to avoid blocking. */ 729 logwtmp("~", "reboot", ""); 730 return (state_func_t) read_ttys; 731 } 732 733 /* 734 * Open the session database. 735 * 736 * NB: We could pass in the size here; is it necessary? 737 */ 738 int 739 start_session_db() 740 { 741 if (session_db && (*session_db->close)(session_db)) 742 emergency("session database close: %s", strerror(errno)); 743 if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) { 744 emergency("session database open: %s", strerror(errno)); 745 return (1); 746 } 747 return (0); 748 749 } 750 751 /* 752 * Add a new login session. 753 */ 754 void 755 add_session(sp) 756 session_t *sp; 757 { 758 DBT key; 759 DBT data; 760 761 key.data = &sp->se_process; 762 key.size = sizeof sp->se_process; 763 data.data = &sp; 764 data.size = sizeof sp; 765 766 if ((*session_db->put)(session_db, &key, &data, 0)) 767 emergency("insert %d: %s", sp->se_process, strerror(errno)); 768 } 769 770 /* 771 * Delete an old login session. 772 */ 773 void 774 del_session(sp) 775 session_t *sp; 776 { 777 DBT key; 778 779 key.data = &sp->se_process; 780 key.size = sizeof sp->se_process; 781 782 if ((*session_db->del)(session_db, &key, 0)) 783 emergency("delete %d: %s", sp->se_process, strerror(errno)); 784 } 785 786 /* 787 * Look up a login session by pid. 788 */ 789 session_t * 790 #ifdef __STDC__ 791 find_session(pid_t pid) 792 #else 793 find_session(pid) 794 pid_t pid; 795 #endif 796 { 797 DBT key; 798 DBT data; 799 session_t *ret; 800 801 key.data = &pid; 802 key.size = sizeof pid; 803 if ((*session_db->get)(session_db, &key, &data, 0) != 0) 804 return 0; 805 bcopy(data.data, (char *)&ret, sizeof(ret)); 806 return ret; 807 } 808 809 /* 810 * Construct an argument vector from a command line. 811 */ 812 char ** 813 construct_argv(command) 814 char *command; 815 { 816 register int argc = 0; 817 register char **argv = (char **) malloc(((strlen(command) + 1) / 2 + 1) 818 * sizeof (char *)); 819 static const char separators[] = " \t"; 820 821 if ((argv[argc++] = strtok(command, separators)) == 0) 822 return 0; 823 while (argv[argc++] = strtok((char *) 0, separators)) 824 continue; 825 return argv; 826 } 827 828 /* 829 * Deallocate a session descriptor. 830 */ 831 void 832 free_session(sp) 833 register session_t *sp; 834 { 835 free(sp->se_device); 836 free(sp->se_getty); 837 free(sp->se_getty_argv); 838 if (sp->se_window) { 839 free(sp->se_window); 840 free(sp->se_window_argv); 841 } 842 free(sp); 843 } 844 845 /* 846 * Allocate a new session descriptor. 847 */ 848 session_t * 849 new_session(sprev, session_index, typ) 850 session_t *sprev; 851 int session_index; 852 register struct ttyent *typ; 853 { 854 register session_t *sp; 855 856 if ((typ->ty_status & TTY_ON) == 0 || 857 typ->ty_name == 0 || 858 typ->ty_getty == 0) 859 return 0; 860 861 sp = (session_t *) malloc(sizeof (session_t)); 862 863 sp->se_index = session_index; 864 sp->se_process = 0; 865 sp->se_started = 0; 866 sp->se_flags = 0; 867 sp->se_window = 0; 868 869 sp->se_device = malloc(sizeof(_PATH_DEV) + strlen(typ->ty_name)); 870 (void) sprintf(sp->se_device, "%s%s", _PATH_DEV, typ->ty_name); 871 872 sp->se_getty = strdup(typ->ty_getty); 873 sp->se_getty_argv = construct_argv(sp->se_getty); 874 if (sp->se_getty_argv == 0) { 875 warning("can't parse getty for port %s", 876 sp->se_device); 877 free_session(sp); 878 return 0; 879 } 880 if (typ->ty_window) { 881 sp->se_window = strdup(typ->ty_window); 882 sp->se_window_argv = construct_argv(sp->se_window); 883 if (sp->se_window_argv == 0) { 884 warning("can't parse window for port %s", 885 sp->se_device); 886 free_session(sp); 887 return 0; 888 } 889 } 890 891 sp->se_next = 0; 892 if (sprev == 0) { 893 sessions = sp; 894 sp->se_prev = 0; 895 } else { 896 sprev->se_next = sp; 897 sp->se_prev = sprev; 898 } 899 900 return sp; 901 } 902 903 /* 904 * Walk the list of ttys and create sessions for each active line. 905 */ 906 state_func_t 907 read_ttys() 908 { 909 int session_index = 0; 910 register session_t *sp, *snext; 911 register struct ttyent *typ; 912 913 /* 914 * Destroy any previous session state. 915 * There shouldn't be any, but just in case... 916 */ 917 for (sp = sessions; sp; sp = snext) { 918 if (sp->se_process) 919 clear_session_logs(sp); 920 snext = sp->se_next; 921 free_session(sp); 922 } 923 sessions = 0; 924 if (start_session_db()) 925 return (state_func_t) single_user; 926 927 /* 928 * Allocate a session entry for each active port. 929 * Note that sp starts at 0. 930 */ 931 while (typ = getttyent()) 932 if (snext = new_session(sp, ++session_index, typ)) 933 sp = snext; 934 935 endttyent(); 936 937 logger_enable = 1; 938 return (state_func_t) multi_user; 939 } 940 941 /* 942 * Start a window system running. 943 */ 944 void 945 start_window_system(sp) 946 session_t *sp; 947 { 948 pid_t pid; 949 sigset_t mask; 950 951 if ((pid = fork()) == -1) { 952 emergency("can't fork for window system on port %s: %m", 953 sp->se_device); 954 /* hope that getty fails and we can try again */ 955 return; 956 } 957 958 if (pid) 959 return; 960 961 sigemptyset(&mask); 962 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 963 964 if (setsid() < 0) 965 emergency("setsid failed (window) %m"); 966 967 execv(sp->se_window_argv[0], sp->se_window_argv); 968 stall("can't exec window system '%s' for port %s: %m", 969 sp->se_window_argv[0], sp->se_device); 970 _exit(1); 971 } 972 973 /* 974 * Start a login session running. 975 */ 976 pid_t 977 start_getty(sp) 978 session_t *sp; 979 { 980 pid_t pid; 981 sigset_t mask; 982 time_t current_time = time((time_t *) 0); 983 984 /* 985 * fork(), not vfork() -- we can't afford to block. 986 */ 987 if ((pid = fork()) == -1) { 988 emergency("can't fork for getty on port %s: %m", sp->se_device); 989 return -1; 990 } 991 992 if (pid) 993 return pid; 994 995 if (current_time > sp->se_started && 996 current_time - sp->se_started < GETTY_SPACING) { 997 warning("getty repeating too quickly on port %s, sleeping", 998 sp->se_device); 999 sleep((unsigned) GETTY_SPACING - 1000 (current_time - sp->se_started)); 1001 } 1002 1003 if (sp->se_window) { 1004 start_window_system(sp); 1005 sleep(WINDOW_WAIT); 1006 } 1007 1008 setctty(sp->se_device); 1009 1010 sigemptyset(&mask); 1011 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 1012 1013 execv(sp->se_getty_argv[0], sp->se_getty_argv); 1014 stall("can't exec getty '%s' for port %s: %m", 1015 sp->se_getty_argv[0], sp->se_device); 1016 _exit(1); 1017 } 1018 1019 /* 1020 * Collect exit status for a child. 1021 * If an exiting login, start a new login running. 1022 */ 1023 void 1024 collect_child(pid) 1025 pid_t pid; 1026 { 1027 register session_t *sp, *sprev, *snext; 1028 1029 if (! sessions) 1030 return; 1031 1032 if (! (sp = find_session(pid))) 1033 return; 1034 1035 clear_session_logs(sp); 1036 del_session(sp); 1037 sp->se_process = 0; 1038 1039 if (sp->se_flags & SE_SHUTDOWN) { 1040 if (sprev = sp->se_prev) 1041 sprev->se_next = sp->se_next; 1042 else 1043 sessions = sp->se_next; 1044 if (snext = sp->se_next) 1045 snext->se_prev = sp->se_prev; 1046 free_session(sp); 1047 return; 1048 } 1049 1050 if ((pid = start_getty(sp)) == -1) { 1051 /* serious trouble */ 1052 requested_transition = clean_ttys; 1053 return; 1054 } 1055 1056 sp->se_process = pid; 1057 sp->se_started = time((time_t *) 0); 1058 add_session(sp); 1059 } 1060 1061 /* 1062 * Catch a signal and request a state transition. 1063 */ 1064 void 1065 transition_handler(sig) 1066 int sig; 1067 { 1068 1069 switch (sig) { 1070 case SIGHUP: 1071 requested_transition = clean_ttys; 1072 break; 1073 case SIGTERM: 1074 requested_transition = death; 1075 break; 1076 case SIGTSTP: 1077 requested_transition = catatonia; 1078 break; 1079 default: 1080 requested_transition = 0; 1081 break; 1082 } 1083 } 1084 1085 /* 1086 * Take the system multiuser. 1087 */ 1088 state_func_t 1089 multi_user() 1090 { 1091 pid_t pid; 1092 register session_t *sp; 1093 1094 requested_transition = 0; 1095 logger_enable = 1; 1096 1097 for (sp = sessions; sp; sp = sp->se_next) { 1098 if (sp->se_process) 1099 continue; 1100 if ((pid = start_getty(sp)) == -1) { 1101 /* serious trouble */ 1102 requested_transition = clean_ttys; 1103 break; 1104 } 1105 sp->se_process = pid; 1106 sp->se_started = time((time_t *) 0); 1107 add_session(sp); 1108 } 1109 1110 while (!requested_transition) 1111 if ((pid = waitpid(-1, (int *) 0, 0)) != -1) 1112 collect_child(pid); 1113 1114 return (state_func_t) requested_transition; 1115 } 1116 1117 /* 1118 * This is an n-squared algorithm. We hope it isn't run often... 1119 */ 1120 state_func_t 1121 clean_ttys() 1122 { 1123 register session_t *sp, *sprev; 1124 register struct ttyent *typ; 1125 register int session_index = 0; 1126 register int devlen; 1127 1128 if (! sessions) 1129 return (state_func_t) multi_user; 1130 1131 devlen = sizeof(_PATH_DEV) - 1; 1132 while (typ = getttyent()) { 1133 ++session_index; 1134 1135 for (sp = sessions; sp; sprev = sp, sp = sp->se_next) 1136 if (strcmp(typ->ty_name, sp->se_device + devlen) == 0) 1137 break; 1138 1139 if (sp) { 1140 if (sp->se_index != session_index) { 1141 warning("port %s changed utmp index from %d to %d", 1142 sp->se_device, sp->se_index, 1143 session_index); 1144 sp->se_index = session_index; 1145 } 1146 if (typ->ty_status & TTY_ON) 1147 sp->se_flags &= ~SE_SHUTDOWN; 1148 else { 1149 sp->se_flags |= SE_SHUTDOWN; 1150 kill(sp->se_process, SIGHUP); 1151 } 1152 continue; 1153 } 1154 1155 new_session(sprev, session_index, typ); 1156 } 1157 1158 endttyent(); 1159 1160 return (state_func_t) multi_user; 1161 } 1162 1163 /* 1164 * Block further logins. 1165 */ 1166 state_func_t 1167 catatonia() 1168 { 1169 register session_t *sp; 1170 1171 for (sp = sessions; sp; sp = sp->se_next) 1172 sp->se_flags |= SE_SHUTDOWN; 1173 1174 return (state_func_t) multi_user; 1175 } 1176 1177 /* 1178 * Note SIGALRM. 1179 */ 1180 void 1181 alrm_handler(sig) 1182 int sig; 1183 { 1184 clang = 1; 1185 } 1186 1187 /* 1188 * Bring the system down to single user. 1189 */ 1190 state_func_t 1191 death() 1192 { 1193 register session_t *sp; 1194 register int i; 1195 pid_t pid; 1196 static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL }; 1197 1198 for (sp = sessions; sp; sp = sp->se_next) 1199 sp->se_flags |= SE_SHUTDOWN; 1200 1201 /* NB: should send a message to the session logger to avoid blocking. */ 1202 logwtmp("~", "shutdown", ""); 1203 logger_enable = 0; 1204 1205 for (i = 0; i < 3; ++i) { 1206 if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH) 1207 return (state_func_t) single_user; 1208 1209 clang = 0; 1210 alarm(DEATH_WATCH); 1211 do 1212 if ((pid = waitpid(-1, (int *)0, 0)) != -1) 1213 collect_child(pid); 1214 while (clang == 0 && errno != ECHILD); 1215 1216 if (errno == ECHILD) 1217 return (state_func_t) single_user; 1218 } 1219 1220 warning("some processes wouldn't die"); 1221 1222 return (state_func_t) single_user; 1223 } 1224