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.10 (Berkeley) 04/10/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 SECURE 512 /* 513 * Check the root password. 514 * We don't care if the console is 'on' by default; 515 * it's the only tty that can be 'off' and 'secure'. 516 */ 517 typ = getttynam("console"); 518 pp = getpwnam("root"); 519 if (typ && (typ->ty_status & TTY_SECURE) == 0 && pp) { 520 write(2, banner, sizeof banner - 1); 521 for (;;) { 522 password = getpass("Password:"); 523 if (password == 0 || *password == '\0') 524 _exit(0); 525 password = crypt(password, pp->pw_passwd); 526 if (strcmp(password, pp->pw_passwd) == 0) 527 break; 528 } 529 } 530 #if 0 531 /* 532 * Make the single-user shell be root's standard shell? 533 */ 534 if (pp && pp->pw_shell) 535 shell = pp->pw_shell; 536 #endif 537 endttyent(); 538 endpwent(); 539 #endif 540 541 /* 542 * Unblock signals. 543 * We catch all the interesting ones, 544 * and those are reset to SIG_DFL on exec. 545 */ 546 sigemptyset(&mask); 547 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 548 549 /* 550 * Fire off a shell. 551 * If the default one doesn't work, try the Bourne shell. 552 */ 553 argv[0] = "-sh"; 554 argv[1] = 0; 555 execv(shell, argv); 556 emergency("can't exec %s for single user: %m", shell); 557 execv(_PATH_BSHELL, argv); 558 emergency("can't exec %s for single user: %m", _PATH_BSHELL); 559 sleep(STALL_TIMEOUT); 560 _exit(1); 561 } 562 563 if (pid == -1) { 564 /* 565 * We are seriously hosed. Do our best. 566 */ 567 emergency("can't fork single-user shell, trying again"); 568 while (waitpid(-1, (int *) 0, WNOHANG) > 0) 569 continue; 570 return (state_func_t) single_user; 571 } 572 573 requested_transition = 0; 574 do { 575 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 576 collect_child(wpid); 577 if (wpid == -1) { 578 if (errno == EINTR) 579 continue; 580 warning("wait for single-user shell failed: %m; restarting"); 581 return (state_func_t) single_user; 582 } 583 if (wpid == pid && WIFSTOPPED(status)) { 584 warning("init: shell stopped, restarting\n"); 585 kill(pid, SIGCONT); 586 wpid = -1; 587 } 588 } while (wpid != pid && !requested_transition); 589 590 if (requested_transition) 591 return (state_func_t) requested_transition; 592 593 if (!WIFEXITED(status)) { 594 if (WTERMSIG(status) == SIGKILL) { 595 /* 596 * reboot(8) killed shell? 597 */ 598 warning("single user shell terminated."); 599 sleep(STALL_TIMEOUT); 600 _exit(0); 601 } else { 602 warning("single user shell terminated, restarting"); 603 return (state_func_t) single_user; 604 } 605 } 606 607 runcom_mode = FASTBOOT; 608 return (state_func_t) runcom; 609 } 610 611 /* 612 * Run the system startup script. 613 */ 614 state_func_t 615 runcom() 616 { 617 pid_t pid, wpid; 618 int status; 619 char *argv[4]; 620 struct sigaction sa; 621 622 if ((pid = fork()) == 0) { 623 sigemptyset(&sa.sa_mask); 624 sa.sa_flags = 0; 625 sa.sa_handler = SIG_IGN; 626 (void) sigaction(SIGTSTP, &sa, (struct sigaction *)0); 627 (void) sigaction(SIGHUP, &sa, (struct sigaction *)0); 628 629 setctty(_PATH_CONSOLE); 630 631 argv[0] = "sh"; 632 argv[1] = _PATH_RUNCOM; 633 argv[2] = runcom_mode == AUTOBOOT ? "autoboot" : 0; 634 argv[3] = 0; 635 636 sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0); 637 638 execv(_PATH_BSHELL, argv); 639 stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNCOM); 640 _exit(1); /* force single user mode */ 641 } 642 643 if (pid == -1) { 644 emergency("can't fork for %s on %s: %m", 645 _PATH_BSHELL, _PATH_RUNCOM); 646 while (waitpid(-1, (int *) 0, WNOHANG) > 0) 647 continue; 648 sleep(STALL_TIMEOUT); 649 return (state_func_t) single_user; 650 } 651 652 /* 653 * Copied from single_user(). This is a bit paranoid. 654 */ 655 do { 656 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 657 collect_child(wpid); 658 if (wpid == -1) { 659 if (errno == EINTR) 660 continue; 661 warning("wait for %s on %s failed: %m; going to single user mode", 662 _PATH_BSHELL, _PATH_RUNCOM); 663 return (state_func_t) single_user; 664 } 665 if (wpid == pid && WIFSTOPPED(status)) { 666 warning("init: %s on %s stopped, restarting\n", 667 _PATH_BSHELL, _PATH_RUNCOM); 668 kill(pid, SIGCONT); 669 wpid = -1; 670 } 671 } while (wpid != pid); 672 673 if (!WIFEXITED(status)) { 674 warning("%s on %s terminated abnormally, going to single user mode", 675 _PATH_BSHELL, _PATH_RUNCOM); 676 return (state_func_t) single_user; 677 } 678 679 if (WEXITSTATUS(status)) 680 return (state_func_t) single_user; 681 682 runcom_mode = AUTOBOOT; /* the default */ 683 /* NB: should send a message to the session logger to avoid blocking. */ 684 logwtmp("~", "reboot", ""); 685 return (state_func_t) read_ttys; 686 } 687 688 /* 689 * Open the session database. 690 * 691 * NB: We could pass in the size here; is it necessary? 692 */ 693 int 694 start_session_db() 695 { 696 if (session_db && (*session_db->close)(session_db)) 697 emergency("session database close: %s", strerror(errno)); 698 if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) { 699 emergency("session database open: %s", strerror(errno)); 700 return (1); 701 } 702 return (0); 703 704 } 705 706 /* 707 * Add a new login session. 708 */ 709 void 710 add_session(sp) 711 session_t *sp; 712 { 713 DBT key; 714 DBT data; 715 716 key.data = &sp->se_process; 717 key.size = sizeof sp->se_process; 718 data.data = &sp; 719 data.size = sizeof sp; 720 721 if ((*session_db->put)(session_db, &key, &data, 0)) 722 emergency("insert %d: %s", sp->se_process, strerror(errno)); 723 } 724 725 /* 726 * Delete an old login session. 727 */ 728 void 729 del_session(sp) 730 session_t *sp; 731 { 732 DBT key; 733 734 key.data = &sp->se_process; 735 key.size = sizeof sp->se_process; 736 737 if ((*session_db->del)(session_db, &key, 0)) 738 emergency("delete %d: %s", sp->se_process, strerror(errno)); 739 } 740 741 /* 742 * Look up a login session by pid. 743 */ 744 session_t * 745 #ifdef __STDC__ 746 find_session(pid_t pid) 747 #else 748 find_session(pid) 749 pid_t pid; 750 #endif 751 { 752 DBT key; 753 DBT data; 754 session_t *ret; 755 756 key.data = &pid; 757 key.size = sizeof pid; 758 if ((*session_db->get)(session_db, &key, &data, 0) != 0) 759 return 0; 760 bcopy(data.data, (char *)&ret, sizeof(ret)); 761 return ret; 762 } 763 764 /* 765 * Construct an argument vector from a command line. 766 */ 767 char ** 768 construct_argv(command) 769 char *command; 770 { 771 register int argc = 0; 772 register char **argv = (char **) malloc(((strlen(command) + 1) / 2 + 1) 773 * sizeof (char *)); 774 static const char separators[] = " \t"; 775 776 if ((argv[argc++] = strtok(command, separators)) == 0) 777 return 0; 778 while (argv[argc++] = strtok((char *) 0, separators)) 779 continue; 780 return argv; 781 } 782 783 /* 784 * Deallocate a session descriptor. 785 */ 786 void 787 free_session(sp) 788 register session_t *sp; 789 { 790 free(sp->se_device); 791 free(sp->se_getty); 792 free(sp->se_getty_argv); 793 if (sp->se_window) { 794 free(sp->se_window); 795 free(sp->se_window_argv); 796 } 797 free(sp); 798 } 799 800 /* 801 * Allocate a new session descriptor. 802 */ 803 session_t * 804 new_session(sprev, session_index, typ) 805 session_t *sprev; 806 int session_index; 807 register struct ttyent *typ; 808 { 809 register session_t *sp; 810 811 if ((typ->ty_status & TTY_ON) == 0 || 812 typ->ty_name == 0 || 813 typ->ty_getty == 0) 814 return 0; 815 816 sp = (session_t *) malloc(sizeof (session_t)); 817 818 sp->se_index = session_index; 819 sp->se_process = 0; 820 sp->se_started = 0; 821 sp->se_flags = 0; 822 sp->se_window = 0; 823 824 sp->se_device = malloc(sizeof(_PATH_DEV) + strlen(typ->ty_name)); 825 (void) sprintf(sp->se_device, "%s%s", _PATH_DEV, typ->ty_name); 826 827 sp->se_getty = strdup(typ->ty_getty); 828 sp->se_getty_argv = construct_argv(sp->se_getty); 829 if (sp->se_getty_argv == 0) { 830 warning("can't parse getty for port %s", 831 sp->se_device); 832 free_session(sp); 833 return 0; 834 } 835 if (typ->ty_window) { 836 sp->se_window = strdup(typ->ty_window); 837 sp->se_window_argv = construct_argv(sp->se_window); 838 if (sp->se_window_argv == 0) { 839 warning("can't parse window for port %s", 840 sp->se_device); 841 free_session(sp); 842 return 0; 843 } 844 } 845 846 sp->se_next = 0; 847 if (sprev == 0) { 848 sessions = sp; 849 sp->se_prev = 0; 850 } else { 851 sprev->se_next = sp; 852 sp->se_prev = sprev; 853 } 854 855 return sp; 856 } 857 858 /* 859 * Walk the list of ttys and create sessions for each active line. 860 */ 861 state_func_t 862 read_ttys() 863 { 864 int session_index = 0; 865 register session_t *sp, *snext; 866 register struct ttyent *typ; 867 868 /* 869 * Destroy any previous session state. 870 * There shouldn't be any, but just in case... 871 */ 872 for (sp = sessions; sp; sp = snext) { 873 if (sp->se_process) 874 clear_session_logs(sp); 875 snext = sp->se_next; 876 free_session(sp); 877 } 878 sessions = 0; 879 if (start_session_db()) 880 return (state_func_t) single_user; 881 882 /* 883 * Allocate a session entry for each active port. 884 * Note that sp starts at 0. 885 */ 886 while (typ = getttyent()) 887 if (snext = new_session(sp, ++session_index, typ)) 888 sp = snext; 889 890 endttyent(); 891 892 logger_enable = 1; 893 return (state_func_t) multi_user; 894 } 895 896 /* 897 * Start a window system running. 898 */ 899 void 900 start_window_system(sp) 901 session_t *sp; 902 { 903 pid_t pid; 904 sigset_t mask; 905 906 if ((pid = fork()) == -1) { 907 emergency("can't fork for window system on port %s: %m", 908 sp->se_device); 909 /* hope that getty fails and we can try again */ 910 return; 911 } 912 913 if (pid) 914 return; 915 916 sigemptyset(&mask); 917 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 918 919 if (setsid() < 0) 920 emergency("setsid failed (window) %m"); 921 922 execv(sp->se_window_argv[0], sp->se_window_argv); 923 stall("can't exec window system '%s' for port %s: %m", 924 sp->se_window_argv[0], sp->se_device); 925 _exit(1); 926 } 927 928 /* 929 * Start a login session running. 930 */ 931 pid_t 932 start_getty(sp) 933 session_t *sp; 934 { 935 pid_t pid; 936 sigset_t mask; 937 time_t current_time = time((time_t *) 0); 938 939 /* 940 * fork(), not vfork() -- we can't afford to block. 941 */ 942 if ((pid = fork()) == -1) { 943 emergency("can't fork for getty on port %s: %m", sp->se_device); 944 return -1; 945 } 946 947 if (pid) 948 return pid; 949 950 if (current_time > sp->se_started && 951 current_time - sp->se_started < GETTY_SPACING) { 952 warning("getty repeating too quickly on port %s, sleeping", 953 sp->se_device); 954 sleep((unsigned) GETTY_SPACING - 955 (current_time - sp->se_started)); 956 } 957 958 if (sp->se_window) { 959 start_window_system(sp); 960 sleep(WINDOW_WAIT); 961 } 962 963 setctty(sp->se_device); 964 965 sigemptyset(&mask); 966 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 967 968 execv(sp->se_getty_argv[0], sp->se_getty_argv); 969 stall("can't exec getty '%s' for port %s: %m", 970 sp->se_getty_argv[0], sp->se_device); 971 _exit(1); 972 } 973 974 /* 975 * Collect exit status for a child. 976 * If an exiting login, start a new login running. 977 */ 978 void 979 collect_child(pid) 980 pid_t pid; 981 { 982 register session_t *sp, *sprev, *snext; 983 984 if (! sessions) 985 return; 986 987 if (! (sp = find_session(pid))) 988 return; 989 990 clear_session_logs(sp); 991 del_session(sp); 992 sp->se_process = 0; 993 994 if (sp->se_flags & SE_SHUTDOWN) { 995 if (sprev = sp->se_prev) 996 sprev->se_next = sp->se_next; 997 else 998 sessions = sp->se_next; 999 if (snext = sp->se_next) 1000 snext->se_prev = sp->se_prev; 1001 free_session(sp); 1002 return; 1003 } 1004 1005 if ((pid = start_getty(sp)) == -1) { 1006 /* serious trouble */ 1007 requested_transition = clean_ttys; 1008 return; 1009 } 1010 1011 sp->se_process = pid; 1012 sp->se_started = time((time_t *) 0); 1013 add_session(sp); 1014 } 1015 1016 /* 1017 * Catch a signal and request a state transition. 1018 */ 1019 void 1020 transition_handler(sig) 1021 int sig; 1022 { 1023 1024 switch (sig) { 1025 case SIGHUP: 1026 requested_transition = clean_ttys; 1027 break; 1028 case SIGTERM: 1029 requested_transition = death; 1030 break; 1031 case SIGTSTP: 1032 requested_transition = catatonia; 1033 break; 1034 default: 1035 requested_transition = 0; 1036 break; 1037 } 1038 } 1039 1040 /* 1041 * Take the system multiuser. 1042 */ 1043 state_func_t 1044 multi_user() 1045 { 1046 pid_t pid; 1047 register session_t *sp; 1048 1049 requested_transition = 0; 1050 logger_enable = 1; 1051 1052 for (sp = sessions; sp; sp = sp->se_next) { 1053 if (sp->se_process) 1054 continue; 1055 if ((pid = start_getty(sp)) == -1) { 1056 /* serious trouble */ 1057 requested_transition = clean_ttys; 1058 break; 1059 } 1060 sp->se_process = pid; 1061 sp->se_started = time((time_t *) 0); 1062 add_session(sp); 1063 } 1064 1065 while (!requested_transition) 1066 if ((pid = waitpid(-1, (int *) 0, 0)) != -1) 1067 collect_child(pid); 1068 1069 return (state_func_t) requested_transition; 1070 } 1071 1072 /* 1073 * This is an n-squared algorithm. We hope it isn't run often... 1074 */ 1075 state_func_t 1076 clean_ttys() 1077 { 1078 register session_t *sp, *sprev; 1079 register struct ttyent *typ; 1080 register int session_index = 0; 1081 register int devlen; 1082 1083 if (! sessions) 1084 return (state_func_t) multi_user; 1085 1086 devlen = sizeof(_PATH_DEV) - 1; 1087 while (typ = getttyent()) { 1088 ++session_index; 1089 1090 for (sp = sessions; sp; sprev = sp, sp = sp->se_next) 1091 if (strcmp(typ->ty_name, sp->se_device + devlen) == 0) 1092 break; 1093 1094 if (sp) { 1095 if (sp->se_index != session_index) { 1096 warning("port %s changed utmp index from %d to %d", 1097 sp->se_device, sp->se_index, 1098 session_index); 1099 sp->se_index = session_index; 1100 } 1101 if (typ->ty_status & TTY_ON) 1102 sp->se_flags &= ~SE_SHUTDOWN; 1103 else { 1104 sp->se_flags |= SE_SHUTDOWN; 1105 kill(sp->se_process, SIGHUP); 1106 } 1107 continue; 1108 } 1109 1110 new_session(sprev, session_index, typ); 1111 } 1112 1113 endttyent(); 1114 1115 return (state_func_t) multi_user; 1116 } 1117 1118 /* 1119 * Block further logins. 1120 */ 1121 state_func_t 1122 catatonia() 1123 { 1124 register session_t *sp; 1125 1126 for (sp = sessions; sp; sp = sp->se_next) 1127 sp->se_flags |= SE_SHUTDOWN; 1128 1129 return (state_func_t) multi_user; 1130 } 1131 1132 /* 1133 * Note SIGALRM. 1134 */ 1135 void 1136 alrm_handler(sig) 1137 int sig; 1138 { 1139 clang = 1; 1140 } 1141 1142 /* 1143 * Bring the system down to single user. 1144 */ 1145 state_func_t 1146 death() 1147 { 1148 register session_t *sp; 1149 register int i; 1150 pid_t pid; 1151 static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL }; 1152 1153 for (sp = sessions; sp; sp = sp->se_next) 1154 sp->se_flags |= SE_SHUTDOWN; 1155 1156 /* NB: should send a message to the session logger to avoid blocking. */ 1157 logwtmp("~", "shutdown", ""); 1158 logger_enable = 0; 1159 1160 for (i = 0; i < 3; ++i) { 1161 if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH) 1162 return (state_func_t) single_user; 1163 1164 clang = 0; 1165 alarm(DEATH_WATCH); 1166 do 1167 if ((pid = waitpid(-1, (int *)0, 0)) != -1) 1168 collect_child(pid); 1169 while (clang == 0 && errno != ECHILD); 1170 1171 if (errno == ECHILD) 1172 return (state_func_t) single_user; 1173 } 1174 1175 warning("some processes wouldn't die"); 1176 1177 return (state_func_t) single_user; 1178 } 1179