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