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