init.c revision 30272
1/*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Donn Seeley at Berkeley Software Design, Inc. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * $Id: init.c,v 1.27 1997/08/18 01:40:12 davidn Exp $ 37 */ 38 39#ifndef lint 40static char copyright[] = 41"@(#) Copyright (c) 1991, 1993\n\ 42 The Regents of the University of California. All rights reserved.\n"; 43#endif /* not lint */ 44 45#ifndef lint 46static char sccsid[] = "@(#)init.c 8.1 (Berkeley) 7/15/93"; 47#endif /* not lint */ 48 49#include <sys/param.h> 50#include <sys/ioctl.h> 51#include <sys/mount.h> 52#include <sys/sysctl.h> 53#include <sys/wait.h> 54#include <sys/types.h> 55#include <sys/stat.h> 56 57#include <db.h> 58#include <errno.h> 59#include <fcntl.h> 60#include <libutil.h> 61#include <signal.h> 62#include <stdio.h> 63#include <stdlib.h> 64#include <string.h> 65#include <syslog.h> 66#include <time.h> 67#include <ttyent.h> 68#include <unistd.h> 69#include <sys/reboot.h> 70#include <err.h> 71 72#ifdef __STDC__ 73#include <stdarg.h> 74#else 75#include <varargs.h> 76#endif 77 78#ifdef SECURE 79#include <pwd.h> 80#endif 81 82#ifdef LOGIN_CAP 83#include <login_cap.h> 84#endif 85 86#include "pathnames.h" 87 88/* 89 * Sleep times; used to prevent thrashing. 90 */ 91#define GETTY_SPACING 5 /* N secs minimum getty spacing */ 92#define GETTY_SLEEP 30 /* sleep N secs after spacing problem */ 93#define GETTY_NSPACE 3 /* max. spacing count to bring reaction */ 94#define WINDOW_WAIT 3 /* wait N secs after starting window */ 95#define STALL_TIMEOUT 30 /* wait N secs after warning */ 96#define DEATH_WATCH 10 /* wait N secs for procs to die */ 97#define DEATH_SCRIPT 120 /* wait for 2mn for /etc/rc.shutdown */ 98#define RESOURCE_RC "daemon" 99#define RESOURCE_WINDOW "default" 100#define RESOURCE_GETTY "default" 101 102void handle __P((sig_t, ...)); 103void delset __P((sigset_t *, ...)); 104 105void stall __P((char *, ...)); 106void warning __P((char *, ...)); 107void emergency __P((char *, ...)); 108void disaster __P((int)); 109void badsys __P((int)); 110int runshutdown __P((void)); 111 112/* 113 * We really need a recursive typedef... 114 * The following at least guarantees that the return type of (*state_t)() 115 * is sufficiently wide to hold a function pointer. 116 */ 117typedef long (*state_func_t) __P((void)); 118typedef state_func_t (*state_t) __P((void)); 119 120state_func_t single_user __P((void)); 121state_func_t runcom __P((void)); 122state_func_t read_ttys __P((void)); 123state_func_t multi_user __P((void)); 124state_func_t clean_ttys __P((void)); 125state_func_t catatonia __P((void)); 126state_func_t death __P((void)); 127 128enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT; 129#define FALSE 0 130#define TRUE 1 131 132int Reboot = FALSE; 133 134int devfs; 135 136void transition __P((state_t)); 137state_t requested_transition = runcom; 138 139void setctty __P((char *)); 140 141typedef struct init_session { 142 int se_index; /* index of entry in ttys file */ 143 pid_t se_process; /* controlling process */ 144 time_t se_started; /* used to avoid thrashing */ 145 int se_flags; /* status of session */ 146#define SE_SHUTDOWN 0x1 /* session won't be restarted */ 147 int se_nspace; /* spacing count */ 148 char *se_device; /* filename of port */ 149 char *se_getty; /* what to run on that port */ 150 char *se_getty_argv_space; /* pre-parsed argument array space */ 151 char **se_getty_argv; /* pre-parsed argument array */ 152 char *se_window; /* window system (started only once) */ 153 char *se_window_argv_space; /* pre-parsed argument array space */ 154 char **se_window_argv; /* pre-parsed argument array */ 155 char *se_type; /* default terminal type */ 156 struct init_session *se_prev; 157 struct init_session *se_next; 158} session_t; 159 160void free_session __P((session_t *)); 161session_t *new_session __P((session_t *, int, struct ttyent *)); 162session_t *sessions; 163 164char **construct_argv __P((char *)); 165void start_window_system __P((session_t *)); 166void collect_child __P((pid_t)); 167pid_t start_getty __P((session_t *)); 168void transition_handler __P((int)); 169void alrm_handler __P((int)); 170void setsecuritylevel __P((int)); 171int getsecuritylevel __P((void)); 172int setupargv __P((session_t *, struct ttyent *)); 173#ifdef LOGIN_CAP 174void setprocresources __P((const char *)); 175#endif 176int clang; 177 178void clear_session_logs __P((session_t *)); 179 180int start_session_db __P((void)); 181void add_session __P((session_t *)); 182void del_session __P((session_t *)); 183session_t *find_session __P((pid_t)); 184DB *session_db; 185 186/* 187 * The mother of all processes. 188 */ 189int 190main(argc, argv) 191 int argc; 192 char **argv; 193{ 194 int c; 195 struct sigaction sa; 196 sigset_t mask; 197 198 199 /* Dispose of random users. */ 200 if (getuid() != 0) 201 errx(1, "%s", strerror(EPERM)); 202 203 /* System V users like to reexec init. */ 204 if (getpid() != 1) 205 errx(1, "already running"); 206 207 /* 208 * Note that this does NOT open a file... 209 * Does 'init' deserve its own facility number? 210 */ 211 openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH); 212 213 /* 214 * Create an initial session. 215 */ 216 if (setsid() < 0) 217 warning("initial setsid() failed: %m"); 218 219 /* 220 * Establish an initial user so that programs running 221 * single user do not freak out and die (like passwd). 222 */ 223 if (setlogin("root") < 0) 224 warning("setlogin() failed: %m"); 225 226 /* 227 * This code assumes that we always get arguments through flags, 228 * never through bits set in some random machine register. 229 */ 230 while ((c = getopt(argc, argv, "dsf")) != -1) 231 switch (c) { 232 case 'd': 233 devfs = 1; 234 break; 235 case 's': 236 requested_transition = single_user; 237 break; 238 case 'f': 239 runcom_mode = FASTBOOT; 240 break; 241 default: 242 warning("unrecognized flag '-%c'", c); 243 break; 244 } 245 246 if (optind != argc) 247 warning("ignoring excess arguments"); 248 249 if (devfs) { 250 mount("devfs", "/dev", MNT_NOEXEC|MNT_RDONLY, 0); 251 } 252 253 /* 254 * We catch or block signals rather than ignore them, 255 * so that they get reset on exec. 256 */ 257 handle(badsys, SIGSYS, 0); 258 handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV, 259 SIGBUS, SIGXCPU, SIGXFSZ, 0); 260 handle(transition_handler, SIGHUP, SIGINT, SIGTERM, SIGTSTP, 0); 261 handle(alrm_handler, SIGALRM, 0); 262 sigfillset(&mask); 263 delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS, 264 SIGXCPU, SIGXFSZ, SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGALRM, 0); 265 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 266 sigemptyset(&sa.sa_mask); 267 sa.sa_flags = 0; 268 sa.sa_handler = SIG_IGN; 269 (void) sigaction(SIGTTIN, &sa, (struct sigaction *)0); 270 (void) sigaction(SIGTTOU, &sa, (struct sigaction *)0); 271 272 /* 273 * Paranoia. 274 */ 275 close(0); 276 close(1); 277 close(2); 278 279 /* 280 * Start the state machine. 281 */ 282 transition(requested_transition); 283 284 /* 285 * Should never reach here. 286 */ 287 return 1; 288} 289 290/* 291 * Associate a function with a signal handler. 292 */ 293void 294#ifdef __STDC__ 295handle(sig_t handler, ...) 296#else 297handle(va_alist) 298 va_dcl 299#endif 300{ 301 int sig; 302 struct sigaction sa; 303 int mask_everything; 304 va_list ap; 305#ifndef __STDC__ 306 sig_t handler; 307 308 va_start(ap); 309 handler = va_arg(ap, sig_t); 310#else 311 va_start(ap, handler); 312#endif 313 314 sa.sa_handler = handler; 315 sigfillset(&mask_everything); 316 317 while ((sig = va_arg(ap, int)) != NULL) { 318 sa.sa_mask = mask_everything; 319 /* XXX SA_RESTART? */ 320 sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0; 321 sigaction(sig, &sa, (struct sigaction *) 0); 322 } 323 va_end(ap); 324} 325 326/* 327 * Delete a set of signals from a mask. 328 */ 329void 330#ifdef __STDC__ 331delset(sigset_t *maskp, ...) 332#else 333delset(va_alist) 334 va_dcl 335#endif 336{ 337 int sig; 338 va_list ap; 339#ifndef __STDC__ 340 sigset_t *maskp; 341 342 va_start(ap); 343 maskp = va_arg(ap, sigset_t *); 344#else 345 va_start(ap, maskp); 346#endif 347 348 while ((sig = va_arg(ap, int)) != NULL) 349 sigdelset(maskp, sig); 350 va_end(ap); 351} 352 353/* 354 * Log a message and sleep for a while (to give someone an opportunity 355 * to read it and to save log or hardcopy output if the problem is chronic). 356 * NB: should send a message to the session logger to avoid blocking. 357 */ 358void 359#ifdef __STDC__ 360stall(char *message, ...) 361#else 362stall(va_alist) 363 va_dcl 364#endif 365{ 366 va_list ap; 367#ifndef __STDC__ 368 char *message; 369 370 va_start(ap); 371 message = va_arg(ap, char *); 372#else 373 va_start(ap, message); 374#endif 375 376 vsyslog(LOG_ALERT, message, ap); 377 va_end(ap); 378 sleep(STALL_TIMEOUT); 379} 380 381/* 382 * Like stall(), but doesn't sleep. 383 * If cpp had variadic macros, the two functions could be #defines for another. 384 * NB: should send a message to the session logger to avoid blocking. 385 */ 386void 387#ifdef __STDC__ 388warning(char *message, ...) 389#else 390warning(va_alist) 391 va_dcl 392#endif 393{ 394 va_list ap; 395#ifndef __STDC__ 396 char *message; 397 398 va_start(ap); 399 message = va_arg(ap, char *); 400#else 401 va_start(ap, message); 402#endif 403 404 vsyslog(LOG_ALERT, message, ap); 405 va_end(ap); 406} 407 408/* 409 * Log an emergency message. 410 * NB: should send a message to the session logger to avoid blocking. 411 */ 412void 413#ifdef __STDC__ 414emergency(char *message, ...) 415#else 416emergency(va_alist) 417 va_dcl 418#endif 419{ 420 va_list ap; 421#ifndef __STDC__ 422 char *message; 423 424 va_start(ap); 425 message = va_arg(ap, char *); 426#else 427 va_start(ap, message); 428#endif 429 430 vsyslog(LOG_EMERG, message, ap); 431 va_end(ap); 432} 433 434/* 435 * Catch a SIGSYS signal. 436 * 437 * These may arise if a system does not support sysctl. 438 * We tolerate up to 25 of these, then throw in the towel. 439 */ 440void 441badsys(sig) 442 int sig; 443{ 444 static int badcount = 0; 445 446 if (badcount++ < 25) 447 return; 448 disaster(sig); 449} 450 451/* 452 * Catch an unexpected signal. 453 */ 454void 455disaster(sig) 456 int sig; 457{ 458 emergency("fatal signal: %s", 459 (unsigned)sig < NSIG ? sys_siglist[sig] : "unknown signal"); 460 461 sleep(STALL_TIMEOUT); 462 _exit(sig); /* reboot */ 463} 464 465/* 466 * Get the security level of the kernel. 467 */ 468int 469getsecuritylevel() 470{ 471#ifdef KERN_SECURELVL 472 int name[2], curlevel; 473 size_t len; 474 extern int errno; 475 476 name[0] = CTL_KERN; 477 name[1] = KERN_SECURELVL; 478 len = sizeof curlevel; 479 if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) { 480 emergency("cannot get kernel security level: %s", 481 strerror(errno)); 482 return (-1); 483 } 484 return (curlevel); 485#else 486 return (-1); 487#endif 488} 489 490/* 491 * Set the security level of the kernel. 492 */ 493void 494setsecuritylevel(newlevel) 495 int newlevel; 496{ 497#ifdef KERN_SECURELVL 498 int name[2], curlevel; 499 extern int errno; 500 501 curlevel = getsecuritylevel(); 502 if (newlevel == curlevel) 503 return; 504 name[0] = CTL_KERN; 505 name[1] = KERN_SECURELVL; 506 if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) { 507 emergency( 508 "cannot change kernel security level from %d to %d: %s", 509 curlevel, newlevel, strerror(errno)); 510 return; 511 } 512#ifdef SECURE 513 warning("kernel security level changed from %d to %d", 514 curlevel, newlevel); 515#endif 516#endif 517} 518 519/* 520 * Change states in the finite state machine. 521 * The initial state is passed as an argument. 522 */ 523void 524transition(s) 525 state_t s; 526{ 527 for (;;) 528 s = (state_t) (*s)(); 529} 530 531/* 532 * Close out the accounting files for a login session. 533 * NB: should send a message to the session logger to avoid blocking. 534 */ 535void 536clear_session_logs(sp) 537 session_t *sp; 538{ 539 char *line = sp->se_device + sizeof(_PATH_DEV) - 1; 540 541 if (logout(line)) 542 logwtmp(line, "", ""); 543} 544 545/* 546 * Start a session and allocate a controlling terminal. 547 * Only called by children of init after forking. 548 */ 549void 550setctty(name) 551 char *name; 552{ 553 int fd; 554 555 (void) revoke(name); 556 if ((fd = open(name, O_RDWR)) == -1) { 557 stall("can't open %s: %m", name); 558 _exit(1); 559 } 560 if (login_tty(fd) == -1) { 561 stall("can't get %s for controlling terminal: %m", name); 562 _exit(1); 563 } 564} 565 566/* 567 * Bring the system up single user. 568 */ 569state_func_t 570single_user() 571{ 572 pid_t pid, wpid; 573 int status; 574 sigset_t mask; 575 char *shell = _PATH_BSHELL; 576 char *argv[2]; 577#ifdef SECURE 578 struct ttyent *typ; 579 struct passwd *pp; 580 static const char banner[] = 581 "Enter root password, or ^D to go multi-user\n"; 582 char *clear, *password; 583#endif 584 585 /* 586 * If the kernel is in secure mode, downgrade it to insecure mode. 587 */ 588 if (getsecuritylevel() > 0) 589 setsecuritylevel(0); 590 591 if (Reboot) { 592 /* Instead of going single user, let's halt the machine */ 593 sync(); 594 alarm(2); 595 pause(); 596 reboot(RB_AUTOBOOT); 597 _exit(0); 598 } 599 600 if ((pid = fork()) == 0) { 601 /* 602 * Start the single user session. 603 */ 604 setctty(_PATH_CONSOLE); 605 606#ifdef SECURE 607 /* 608 * Check the root password. 609 * We don't care if the console is 'on' by default; 610 * it's the only tty that can be 'off' and 'secure'. 611 */ 612 typ = getttynam("console"); 613 pp = getpwnam("root"); 614 if (typ && (typ->ty_status & TTY_SECURE) == 0 && pp && *pp->pw_passwd) { 615 write(2, banner, sizeof banner - 1); 616 for (;;) { 617 clear = getpass("Password:"); 618 if (clear == 0 || *clear == '\0') 619 _exit(0); 620 password = crypt(clear, pp->pw_passwd); 621 bzero(clear, _PASSWORD_LEN); 622 if (strcmp(password, pp->pw_passwd) == 0) 623 break; 624 warning("single-user login failed\n"); 625 } 626 } 627 endttyent(); 628 endpwent(); 629#endif /* SECURE */ 630 631#ifdef DEBUGSHELL 632 { 633 char altshell[128], *cp = altshell; 634 int num; 635 636#define SHREQUEST \ 637 "Enter full pathname of shell or RETURN for " _PATH_BSHELL ": " 638 (void)write(STDERR_FILENO, 639 SHREQUEST, sizeof(SHREQUEST) - 1); 640 while ((num = read(STDIN_FILENO, cp, 1)) != -1 && 641 num != 0 && *cp != '\n' && cp < &altshell[127]) 642 cp++; 643 *cp = '\0'; 644 if (altshell[0] != '\0') 645 shell = altshell; 646 } 647#endif /* DEBUGSHELL */ 648 649 /* 650 * Unblock signals. 651 * We catch all the interesting ones, 652 * and those are reset to SIG_DFL on exec. 653 */ 654 sigemptyset(&mask); 655 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 656 657 /* 658 * Fire off a shell. 659 * If the default one doesn't work, try the Bourne shell. 660 */ 661 argv[0] = "-sh"; 662 argv[1] = 0; 663 execv(shell, argv); 664 emergency("can't exec %s for single user: %m", shell); 665 execv(_PATH_BSHELL, argv); 666 emergency("can't exec %s for single user: %m", _PATH_BSHELL); 667 sleep(STALL_TIMEOUT); 668 _exit(1); 669 } 670 671 if (pid == -1) { 672 /* 673 * We are seriously hosed. Do our best. 674 */ 675 emergency("can't fork single-user shell, trying again"); 676 while (waitpid(-1, (int *) 0, WNOHANG) > 0) 677 continue; 678 return (state_func_t) single_user; 679 } 680 681 requested_transition = 0; 682 do { 683 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 684 collect_child(wpid); 685 if (wpid == -1) { 686 if (errno == EINTR) 687 continue; 688 warning("wait for single-user shell failed: %m; restarting"); 689 return (state_func_t) single_user; 690 } 691 if (wpid == pid && WIFSTOPPED(status)) { 692 warning("init: shell stopped, restarting\n"); 693 kill(pid, SIGCONT); 694 wpid = -1; 695 } 696 } while (wpid != pid && !requested_transition); 697 698 if (requested_transition) 699 return (state_func_t) requested_transition; 700 701 if (!WIFEXITED(status)) { 702 if (WTERMSIG(status) == SIGKILL) { 703 /* 704 * reboot(8) killed shell? 705 */ 706 warning("single user shell terminated."); 707 sleep(STALL_TIMEOUT); 708 _exit(0); 709 } else { 710 warning("single user shell terminated, restarting"); 711 return (state_func_t) single_user; 712 } 713 } 714 715 runcom_mode = FASTBOOT; 716 return (state_func_t) runcom; 717} 718 719/* 720 * Run the system startup script. 721 */ 722state_func_t 723runcom() 724{ 725 pid_t pid, wpid; 726 int status; 727 char *argv[4]; 728 struct sigaction sa; 729 730 if ((pid = fork()) == 0) { 731 sigemptyset(&sa.sa_mask); 732 sa.sa_flags = 0; 733 sa.sa_handler = SIG_IGN; 734 (void) sigaction(SIGTSTP, &sa, (struct sigaction *)0); 735 (void) sigaction(SIGHUP, &sa, (struct sigaction *)0); 736 737 setctty(_PATH_CONSOLE); 738 739 argv[0] = "sh"; 740 argv[1] = _PATH_RUNCOM; 741 argv[2] = runcom_mode == AUTOBOOT ? "autoboot" : 0; 742 argv[3] = 0; 743 744 sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0); 745 746#ifdef LOGIN_CAP 747 setprocresources(RESOURCE_RC); 748#endif 749 execv(_PATH_BSHELL, argv); 750 stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNCOM); 751 _exit(1); /* force single user mode */ 752 } 753 754 if (pid == -1) { 755 emergency("can't fork for %s on %s: %m", 756 _PATH_BSHELL, _PATH_RUNCOM); 757 while (waitpid(-1, (int *) 0, WNOHANG) > 0) 758 continue; 759 sleep(STALL_TIMEOUT); 760 return (state_func_t) single_user; 761 } 762 763 /* 764 * Copied from single_user(). This is a bit paranoid. 765 */ 766 do { 767 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 768 collect_child(wpid); 769 if (wpid == -1) { 770 if (errno == EINTR) 771 continue; 772 warning("wait for %s on %s failed: %m; going to single user mode", 773 _PATH_BSHELL, _PATH_RUNCOM); 774 return (state_func_t) single_user; 775 } 776 if (wpid == pid && WIFSTOPPED(status)) { 777 warning("init: %s on %s stopped, restarting\n", 778 _PATH_BSHELL, _PATH_RUNCOM); 779 kill(pid, SIGCONT); 780 wpid = -1; 781 } 782 } while (wpid != pid); 783 784 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM && 785 requested_transition == catatonia) { 786 /* /etc/rc executed /sbin/reboot; wait for the end quietly */ 787 sigset_t s; 788 789 sigfillset(&s); 790 for (;;) 791 sigsuspend(&s); 792 } 793 794 if (!WIFEXITED(status)) { 795 warning("%s on %s terminated abnormally, going to single user mode", 796 _PATH_BSHELL, _PATH_RUNCOM); 797 return (state_func_t) single_user; 798 } 799 800 if (WEXITSTATUS(status)) 801 return (state_func_t) single_user; 802 803 runcom_mode = AUTOBOOT; /* the default */ 804 /* NB: should send a message to the session logger to avoid blocking. */ 805 logwtmp("~", "reboot", ""); 806 return (state_func_t) read_ttys; 807} 808 809/* 810 * Open the session database. 811 * 812 * NB: We could pass in the size here; is it necessary? 813 */ 814int 815start_session_db() 816{ 817 if (session_db && (*session_db->close)(session_db)) 818 emergency("session database close: %s", strerror(errno)); 819 if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) { 820 emergency("session database open: %s", strerror(errno)); 821 return (1); 822 } 823 return (0); 824 825} 826 827/* 828 * Add a new login session. 829 */ 830void 831add_session(sp) 832 session_t *sp; 833{ 834 DBT key; 835 DBT data; 836 837 key.data = &sp->se_process; 838 key.size = sizeof sp->se_process; 839 data.data = &sp; 840 data.size = sizeof sp; 841 842 if ((*session_db->put)(session_db, &key, &data, 0)) 843 emergency("insert %d: %s", sp->se_process, strerror(errno)); 844} 845 846/* 847 * Delete an old login session. 848 */ 849void 850del_session(sp) 851 session_t *sp; 852{ 853 DBT key; 854 855 key.data = &sp->se_process; 856 key.size = sizeof sp->se_process; 857 858 if ((*session_db->del)(session_db, &key, 0)) 859 emergency("delete %d: %s", sp->se_process, strerror(errno)); 860} 861 862/* 863 * Look up a login session by pid. 864 */ 865session_t * 866#ifdef __STDC__ 867find_session(pid_t pid) 868#else 869find_session(pid) 870 pid_t pid; 871#endif 872{ 873 DBT key; 874 DBT data; 875 session_t *ret; 876 877 key.data = &pid; 878 key.size = sizeof pid; 879 if ((*session_db->get)(session_db, &key, &data, 0) != 0) 880 return 0; 881 bcopy(data.data, (char *)&ret, sizeof(ret)); 882 return ret; 883} 884 885/* 886 * Construct an argument vector from a command line. 887 */ 888char ** 889construct_argv(command) 890 char *command; 891{ 892 char *strk (char *); 893 register int argc = 0; 894 register char **argv = (char **) malloc(((strlen(command) + 1) / 2 + 1) 895 * sizeof (char *)); 896 897 if ((argv[argc++] = strk(command)) == 0) 898 return 0; 899 while ((argv[argc++] = strk((char *) 0)) != NULL) 900 continue; 901 return argv; 902} 903 904/* 905 * Deallocate a session descriptor. 906 */ 907void 908free_session(sp) 909 register session_t *sp; 910{ 911 free(sp->se_device); 912 if (sp->se_getty) { 913 free(sp->se_getty); 914 free(sp->se_getty_argv_space); 915 free(sp->se_getty_argv); 916 } 917 if (sp->se_window) { 918 free(sp->se_window); 919 free(sp->se_window_argv_space); 920 free(sp->se_window_argv); 921 } 922 if (sp->se_type) 923 free(sp->se_type); 924 free(sp); 925} 926 927/* 928 * Allocate a new session descriptor. 929 */ 930session_t * 931new_session(sprev, session_index, typ) 932 session_t *sprev; 933 int session_index; 934 register struct ttyent *typ; 935{ 936 register session_t *sp; 937 int fd; 938 939 if ((typ->ty_status & TTY_ON) == 0 || 940 typ->ty_name == 0 || 941 typ->ty_getty == 0) 942 return 0; 943 944 sp = (session_t *) calloc(1, sizeof (session_t)); 945 946 sp->se_index = session_index; 947 948 sp->se_device = malloc(sizeof(_PATH_DEV) + strlen(typ->ty_name)); 949 (void) sprintf(sp->se_device, "%s%s", _PATH_DEV, typ->ty_name); 950 951 /* 952 * Attempt to open the device, if we get "device not configured" 953 * then don't add the device to the session list. 954 */ 955 if ((fd = open(sp->se_device, O_RDONLY | O_NONBLOCK, 0)) < 0) { 956 if (errno == ENXIO) { 957 free_session(sp); 958 return (0); 959 } 960 } else 961 close(fd); 962 963 if (setupargv(sp, typ) == 0) { 964 free_session(sp); 965 return (0); 966 } 967 968 sp->se_next = 0; 969 if (sprev == 0) { 970 sessions = sp; 971 sp->se_prev = 0; 972 } else { 973 sprev->se_next = sp; 974 sp->se_prev = sprev; 975 } 976 977 return sp; 978} 979 980/* 981 * Calculate getty and if useful window argv vectors. 982 */ 983int 984setupargv(sp, typ) 985 session_t *sp; 986 struct ttyent *typ; 987{ 988 989 if (sp->se_getty) { 990 free(sp->se_getty); 991 free(sp->se_getty_argv_space); 992 free(sp->se_getty_argv); 993 } 994 sp->se_getty = malloc(strlen(typ->ty_getty) + strlen(typ->ty_name) + 2); 995 (void) sprintf(sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name); 996 sp->se_getty_argv_space = strdup(sp->se_getty); 997 sp->se_getty_argv = construct_argv(sp->se_getty_argv_space); 998 if (sp->se_getty_argv == 0) { 999 warning("can't parse getty for port %s", sp->se_device); 1000 free(sp->se_getty); 1001 free(sp->se_getty_argv_space); 1002 sp->se_getty = sp->se_getty_argv_space = 0; 1003 return (0); 1004 } 1005 if (sp->se_window) { 1006 free(sp->se_window); 1007 free(sp->se_window_argv_space); 1008 free(sp->se_window_argv); 1009 } 1010 sp->se_window = sp->se_window_argv_space = 0; 1011 sp->se_window_argv = 0; 1012 if (typ->ty_window) { 1013 sp->se_window = strdup(typ->ty_window); 1014 sp->se_window_argv_space = strdup(sp->se_window); 1015 sp->se_window_argv = construct_argv(sp->se_window_argv_space); 1016 if (sp->se_window_argv == 0) { 1017 warning("can't parse window for port %s", 1018 sp->se_device); 1019 free(sp->se_window_argv_space); 1020 free(sp->se_window); 1021 sp->se_window = sp->se_window_argv_space = 0; 1022 return (0); 1023 } 1024 } 1025 if (sp->se_type) 1026 free(sp->se_type); 1027 sp->se_type = typ->ty_type ? strdup(typ->ty_type) : 0; 1028 return (1); 1029} 1030 1031/* 1032 * Walk the list of ttys and create sessions for each active line. 1033 */ 1034state_func_t 1035read_ttys() 1036{ 1037 int session_index = 0; 1038 register session_t *sp, *snext; 1039 register struct ttyent *typ; 1040 1041 /* 1042 * Destroy any previous session state. 1043 * There shouldn't be any, but just in case... 1044 */ 1045 for (sp = sessions; sp; sp = snext) { 1046 if (sp->se_process) 1047 clear_session_logs(sp); 1048 snext = sp->se_next; 1049 free_session(sp); 1050 } 1051 sessions = 0; 1052 if (start_session_db()) 1053 return (state_func_t) single_user; 1054 1055 /* 1056 * Allocate a session entry for each active port. 1057 * Note that sp starts at 0. 1058 */ 1059 while ((typ = getttyent()) != NULL) 1060 if ((snext = new_session(sp, ++session_index, typ)) != NULL) 1061 sp = snext; 1062 1063 endttyent(); 1064 1065 return (state_func_t) multi_user; 1066} 1067 1068/* 1069 * Start a window system running. 1070 */ 1071void 1072start_window_system(sp) 1073 session_t *sp; 1074{ 1075 pid_t pid; 1076 sigset_t mask; 1077 char term[64], *env[2]; 1078 1079 if ((pid = fork()) == -1) { 1080 emergency("can't fork for window system on port %s: %m", 1081 sp->se_device); 1082 /* hope that getty fails and we can try again */ 1083 return; 1084 } 1085 1086 if (pid) 1087 return; 1088 1089 sigemptyset(&mask); 1090 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 1091 1092 if (setsid() < 0) 1093 emergency("setsid failed (window) %m"); 1094 1095#ifdef LOGIN_CAP 1096 setprocresources(RESOURCE_WINDOW); 1097#endif 1098 if (sp->se_type) { 1099 /* Don't use malloc after fork */ 1100 strcpy(term, "TERM="); 1101 strncat(term, sp->se_type, sizeof(term) - 6); 1102 env[0] = term; 1103 env[1] = 0; 1104 } 1105 else 1106 env[0] = 0; 1107 execve(sp->se_window_argv[0], sp->se_window_argv, env); 1108 stall("can't exec window system '%s' for port %s: %m", 1109 sp->se_window_argv[0], sp->se_device); 1110 _exit(1); 1111} 1112 1113/* 1114 * Start a login session running. 1115 */ 1116pid_t 1117start_getty(sp) 1118 session_t *sp; 1119{ 1120 pid_t pid; 1121 sigset_t mask; 1122 time_t current_time = time((time_t *) 0); 1123 int too_quick = 0; 1124 char term[64], *env[2]; 1125 1126 if (current_time >= sp->se_started && 1127 current_time - sp->se_started < GETTY_SPACING) { 1128 if (++sp->se_nspace > GETTY_NSPACE) { 1129 sp->se_nspace = 0; 1130 too_quick = 1; 1131 } 1132 } else 1133 sp->se_nspace = 0; 1134 1135 /* 1136 * fork(), not vfork() -- we can't afford to block. 1137 */ 1138 if ((pid = fork()) == -1) { 1139 emergency("can't fork for getty on port %s: %m", sp->se_device); 1140 return -1; 1141 } 1142 1143 if (pid) 1144 return pid; 1145 1146 if (too_quick) { 1147 warning("getty repeating too quickly on port %s, sleeping %d secs", 1148 sp->se_device, GETTY_SLEEP); 1149 sleep((unsigned) GETTY_SLEEP); 1150 } 1151 1152 if (sp->se_window) { 1153 start_window_system(sp); 1154 sleep(WINDOW_WAIT); 1155 } 1156 1157 sigemptyset(&mask); 1158 sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); 1159 1160#ifdef LOGIN_CAP 1161 setprocresources(RESOURCE_GETTY); 1162#endif 1163 if (sp->se_type) { 1164 /* Don't use malloc after fork */ 1165 strcpy(term, "TERM="); 1166 strncat(term, sp->se_type, sizeof(term) - 6); 1167 env[0] = term; 1168 env[1] = 0; 1169 } 1170 else 1171 env[0] = 0; 1172 execve(sp->se_getty_argv[0], sp->se_getty_argv, env); 1173 stall("can't exec getty '%s' for port %s: %m", 1174 sp->se_getty_argv[0], sp->se_device); 1175 _exit(1); 1176} 1177 1178/* 1179 * Collect exit status for a child. 1180 * If an exiting login, start a new login running. 1181 */ 1182void 1183#ifdef __STDC__ 1184collect_child(pid_t pid) 1185#else 1186collect_child(pid) 1187 pid_t pid; 1188#endif 1189{ 1190 register session_t *sp, *sprev, *snext; 1191 1192 if (! sessions) 1193 return; 1194 1195 if (! (sp = find_session(pid))) 1196 return; 1197 1198 clear_session_logs(sp); 1199 del_session(sp); 1200 sp->se_process = 0; 1201 1202 if (sp->se_flags & SE_SHUTDOWN) { 1203 if ((sprev = sp->se_prev) != NULL) 1204 sprev->se_next = sp->se_next; 1205 else 1206 sessions = sp->se_next; 1207 if ((snext = sp->se_next) != NULL) 1208 snext->se_prev = sp->se_prev; 1209 free_session(sp); 1210 return; 1211 } 1212 1213 if ((pid = start_getty(sp)) == -1) { 1214 /* serious trouble */ 1215 requested_transition = clean_ttys; 1216 return; 1217 } 1218 1219 sp->se_process = pid; 1220 sp->se_started = time((time_t *) 0); 1221 add_session(sp); 1222} 1223 1224/* 1225 * Catch a signal and request a state transition. 1226 */ 1227void 1228transition_handler(sig) 1229 int sig; 1230{ 1231 1232 switch (sig) { 1233 case SIGHUP: 1234 requested_transition = clean_ttys; 1235 break; 1236 case SIGINT: 1237 Reboot = TRUE; 1238 case SIGTERM: 1239 requested_transition = death; 1240 break; 1241 case SIGTSTP: 1242 requested_transition = catatonia; 1243 break; 1244 default: 1245 requested_transition = 0; 1246 break; 1247 } 1248} 1249 1250/* 1251 * Take the system multiuser. 1252 */ 1253state_func_t 1254multi_user() 1255{ 1256 pid_t pid; 1257 register session_t *sp; 1258 1259 requested_transition = 0; 1260 1261 /* 1262 * If the administrator has not set the security level to -1 1263 * to indicate that the kernel should not run multiuser in secure 1264 * mode, and the run script has not set a higher level of security 1265 * than level 1, then put the kernel into secure mode. 1266 */ 1267 if (getsecuritylevel() == 0) 1268 setsecuritylevel(1); 1269 1270 for (sp = sessions; sp; sp = sp->se_next) { 1271 if (sp->se_process) 1272 continue; 1273 if ((pid = start_getty(sp)) == -1) { 1274 /* serious trouble */ 1275 requested_transition = clean_ttys; 1276 break; 1277 } 1278 sp->se_process = pid; 1279 sp->se_started = time((time_t *) 0); 1280 add_session(sp); 1281 } 1282 1283 while (!requested_transition) 1284 if ((pid = waitpid(-1, (int *) 0, 0)) != -1) 1285 collect_child(pid); 1286 1287 return (state_func_t) requested_transition; 1288} 1289 1290/* 1291 * This is an n-squared algorithm. We hope it isn't run often... 1292 */ 1293state_func_t 1294clean_ttys() 1295{ 1296 register session_t *sp, *sprev; 1297 register struct ttyent *typ; 1298 register int session_index = 0; 1299 register int devlen; 1300 char *old_getty, *old_window, *old_type; 1301 1302 if (! sessions) 1303 return (state_func_t) multi_user; 1304 1305 devlen = sizeof(_PATH_DEV) - 1; 1306 while ((typ = getttyent()) != NULL) { 1307 ++session_index; 1308 1309 for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next) 1310 if (strcmp(typ->ty_name, sp->se_device + devlen) == 0) 1311 break; 1312 1313 if (sp) { 1314 if (sp->se_index != session_index) { 1315 warning("port %s changed utmp index from %d to %d", 1316 sp->se_device, sp->se_index, 1317 session_index); 1318 sp->se_index = session_index; 1319 } 1320 if ((typ->ty_status & TTY_ON) == 0 || 1321 typ->ty_getty == 0) { 1322 sp->se_flags |= SE_SHUTDOWN; 1323 kill(sp->se_process, SIGHUP); 1324 continue; 1325 } 1326 sp->se_flags &= ~SE_SHUTDOWN; 1327 old_getty = sp->se_getty ? strdup(sp->se_getty) : 0; 1328 old_window = sp->se_window ? strdup(sp->se_window) : 0; 1329 old_type = sp->se_type ? strdup(sp->se_type) : 0; 1330 if (setupargv(sp, typ) == 0) { 1331 warning("can't parse getty for port %s", 1332 sp->se_device); 1333 sp->se_flags |= SE_SHUTDOWN; 1334 kill(sp->se_process, SIGHUP); 1335 } 1336 else if ( !old_getty 1337 || (!old_type && sp->se_type) 1338 || (old_type && !sp->se_type) 1339 || (!old_window && sp->se_window) 1340 || (old_window && !sp->se_window) 1341 || (strcmp(old_getty, sp->se_getty) != 0) 1342 || (old_window && strcmp(old_window, sp->se_window) != 0) 1343 || (old_type && strcmp(old_type, sp->se_type) != 0) 1344 ) { 1345 /* Don't set SE_SHUTDOWN here */ 1346 sp->se_nspace = 0; 1347 sp->se_started = 0; 1348 kill(sp->se_process, SIGHUP); 1349 } 1350 if (old_getty) 1351 free(old_getty); 1352 if (old_getty) 1353 free(old_window); 1354 if (old_type) 1355 free(old_type); 1356 continue; 1357 } 1358 1359 new_session(sprev, session_index, typ); 1360 } 1361 1362 endttyent(); 1363 1364 return (state_func_t) multi_user; 1365} 1366 1367/* 1368 * Block further logins. 1369 */ 1370state_func_t 1371catatonia() 1372{ 1373 register session_t *sp; 1374 1375 for (sp = sessions; sp; sp = sp->se_next) 1376 sp->se_flags |= SE_SHUTDOWN; 1377 1378 return (state_func_t) multi_user; 1379} 1380 1381/* 1382 * Note SIGALRM. 1383 */ 1384void 1385alrm_handler(sig) 1386 int sig; 1387{ 1388 (void)sig; 1389 clang = 1; 1390} 1391 1392/* 1393 * Bring the system down to single user. 1394 */ 1395state_func_t 1396death() 1397{ 1398 register session_t *sp; 1399 register int i; 1400 pid_t pid; 1401 static const int death_sigs[2] = { SIGTERM, SIGKILL }; 1402 1403 /* NB: should send a message to the session logger to avoid blocking. */ 1404 logwtmp("~", "shutdown", ""); 1405 1406 for (sp = sessions; sp; sp = sp->se_next) { 1407 sp->se_flags |= SE_SHUTDOWN; 1408 kill(sp->se_process, SIGHUP); 1409 } 1410 1411 /* Try to run the rc.shutdown script within a period of time */ 1412 (void) runshutdown(); 1413 1414 for (i = 0; i < 2; ++i) { 1415 if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH) 1416 return (state_func_t) single_user; 1417 1418 clang = 0; 1419 alarm(DEATH_WATCH); 1420 do 1421 if ((pid = waitpid(-1, (int *)0, 0)) != -1) 1422 collect_child(pid); 1423 while (clang == 0 && errno != ECHILD); 1424 1425 if (errno == ECHILD) 1426 return (state_func_t) single_user; 1427 } 1428 1429 warning("some processes would not die; ps axl advised"); 1430 1431 return (state_func_t) single_user; 1432} 1433 1434/* 1435 * Run the system shutdown script. 1436 * 1437 * Exit codes: XXX I should document more 1438 * -2 shutdown script terminated abnormally 1439 * -1 fatal error - can't run script 1440 * 0 good. 1441 * >0 some error (exit code) 1442 */ 1443int 1444runshutdown() 1445{ 1446 pid_t pid, wpid; 1447 int status; 1448 int shutdowntimeout; 1449 size_t len; 1450 char *argv[3]; 1451 struct sigaction sa; 1452 struct stat sb; 1453 1454 /* 1455 * rc.shutdown is optional, so to prevent any unnecessary 1456 * complaints from the shell we simply don't run it if the 1457 * file does not exist. If the stat() here fails for other 1458 * reasons, we'll let the shell complain. 1459 */ 1460 if (stat(_PATH_RUNDOWN, &sb) == -1 && errno == ENOENT) 1461 return 0; 1462 1463 if ((pid = fork()) == 0) { 1464 int fd; 1465 1466 /* Assume that init already grab console as ctty before */ 1467 1468 sigemptyset(&sa.sa_mask); 1469 sa.sa_flags = 0; 1470 sa.sa_handler = SIG_IGN; 1471 (void) sigaction(SIGTSTP, &sa, (struct sigaction *)0); 1472 (void) sigaction(SIGHUP, &sa, (struct sigaction *)0); 1473 1474 if ((fd = open(_PATH_CONSOLE, O_RDWR)) == -1) 1475 warning("can't open %s: %m", _PATH_CONSOLE); 1476 else { 1477 (void) dup2(fd, 0); 1478 (void) dup2(fd, 1); 1479 (void) dup2(fd, 2); 1480 if (fd > 2) 1481 close(fd); 1482 } 1483 1484 /* 1485 * Run the shutdown script. 1486 */ 1487 argv[0] = "sh"; 1488 argv[1] = _PATH_RUNDOWN; 1489 argv[2] = 0; 1490 1491 sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0); 1492 1493#ifdef LOGIN_CAP 1494 setprocresources(RESOURCE_RC); 1495#endif 1496 execv(_PATH_BSHELL, argv); 1497 warning("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNDOWN); 1498 _exit(1); /* force single user mode */ 1499 } 1500 1501 if (pid == -1) { 1502 emergency("can't fork for %s on %s: %m", 1503 _PATH_BSHELL, _PATH_RUNDOWN); 1504 while (waitpid(-1, (int *) 0, WNOHANG) > 0) 1505 continue; 1506 sleep(STALL_TIMEOUT); 1507 return -1; 1508 } 1509 1510 len = sizeof(shutdowntimeout); 1511 if (sysctlbyname("kern.shutdown_timeout", 1512 &shutdowntimeout, 1513 &len, NULL, 0) == -1 || shutdowntimeout < 2) 1514 shutdowntimeout = DEATH_SCRIPT; 1515 alarm(shutdowntimeout); 1516 clang = 0; 1517 /* 1518 * Copied from single_user(). This is a bit paranoid. 1519 * Use the same ALRM handler. 1520 */ 1521 do { 1522 if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) 1523 collect_child(wpid); 1524 if (clang == 1) { 1525 /* we were waiting for the sub-shell */ 1526 kill(wpid, SIGTERM); 1527 warning("timeout expired for %s on %s: %m; going to single used mode", 1528 _PATH_BSHELL, _PATH_RUNDOWN); 1529 return -1; 1530 } 1531 if (wpid == -1) { 1532 if (errno == EINTR) 1533 continue; 1534 warning("wait for %s on %s failed: %m; going to single user mode", 1535 _PATH_BSHELL, _PATH_RUNDOWN); 1536 return -1; 1537 } 1538 if (wpid == pid && WIFSTOPPED(status)) { 1539 warning("init: %s on %s stopped, restarting\n", 1540 _PATH_BSHELL, _PATH_RUNDOWN); 1541 kill(pid, SIGCONT); 1542 wpid = -1; 1543 } 1544 } while (wpid != pid && !clang); 1545 1546 /* Turn off the alarm */ 1547 alarm(0); 1548 1549 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM && 1550 requested_transition == catatonia) { 1551 /* 1552 * /etc/rc.shutdown executed /sbin/reboot; 1553 * wait for the end quietly 1554 */ 1555 sigset_t s; 1556 1557 sigfillset(&s); 1558 for (;;) 1559 sigsuspend(&s); 1560 } 1561 1562 if (!WIFEXITED(status)) { 1563 warning("%s on %s terminated abnormally, going to single user mode", 1564 _PATH_BSHELL, _PATH_RUNDOWN); 1565 return -2; 1566 } 1567 1568 if ((status = WEXITSTATUS(status)) != 0) 1569 warning("%s returned status %d", _PATH_RUNDOWN, status); 1570 1571 return status; 1572} 1573 1574char * 1575strk (char *p) 1576{ 1577 static char *t; 1578 char *q; 1579 int c; 1580 1581 if (p) 1582 t = p; 1583 if (!t) 1584 return 0; 1585 1586 c = *t; 1587 while (c == ' ' || c == '\t' ) 1588 c = *++t; 1589 if (!c) { 1590 t = 0; 1591 return 0; 1592 } 1593 q = t; 1594 if (c == '\'') { 1595 c = *++t; 1596 q = t; 1597 while (c && c != '\'') 1598 c = *++t; 1599 if (!c) /* unterminated string */ 1600 q = t = 0; 1601 else 1602 *t++ = 0; 1603 } else { 1604 while (c && c != ' ' && c != '\t' ) 1605 c = *++t; 1606 *t++ = 0; 1607 if (!c) 1608 t = 0; 1609 } 1610 return q; 1611} 1612 1613#ifdef LOGIN_CAP 1614void 1615setprocresources(cname) 1616 const char *cname; 1617{ 1618 login_cap_t *lc; 1619 if ((lc = login_getclassbyname(cname, NULL)) != NULL) { 1620 setusercontext(lc, (struct passwd*)NULL, 0, LOGIN_SETPRIORITY|LOGIN_SETRESOURCES); 1621 login_close(lc); 1622 } 1623} 1624#endif 1625