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