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