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