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