⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 init.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1991, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * Donn Seeley at Berkeley Software Design, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char copyright[] ="@(#) Copyright (c) 1991, 1993\n\	The Regents of the University of California.  All rights reserved.\n";#endif /* not lint */#ifndef lintstatic char sccsid[] = "@(#)init.c	8.1 (Berkeley) 7/15/93";#endif /* not lint */#include <sys/param.h>#include <sys/sysctl.h>#include <sys/wait.h>#include <db.h>#include <errno.h>#include <fcntl.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <syslog.h>#include <time.h>#include <ttyent.h>#include <unistd.h>#ifdef __STDC__#include <stdarg.h>#else#include <varargs.h>#endif#ifdef SECURE#include <pwd.h>#endif#include "pathnames.h"/* * Until the mythical util.h arrives... */extern int login_tty __P((int));extern int logout __P((const char *));extern void logwtmp __P((const char *, const char *, const char *));/* * Sleep times; used to prevent thrashing. */#define	GETTY_SPACING		 5	/* N secs minimum getty spacing */#define	GETTY_SLEEP		30	/* sleep N secs after spacing problem */#define	WINDOW_WAIT		 3	/* wait N secs after starting window */#define	STALL_TIMEOUT		30	/* wait N secs after warning */#define	DEATH_WATCH		10	/* wait N secs for procs to die */void handle __P((sig_t, ...));void delset __P((sigset_t *, ...));void stall __P((char *, ...));void warning __P((char *, ...));void emergency __P((char *, ...));void disaster __P((int));void badsys __P((int));/* * We really need a recursive typedef... * The following at least guarantees that the return type of (*state_t)() * is sufficiently wide to hold a function pointer. */typedef long (*state_func_t) __P((void));typedef state_func_t (*state_t) __P((void));state_func_t single_user __P((void));state_func_t runcom __P((void));state_func_t read_ttys __P((void));state_func_t multi_user __P((void));state_func_t clean_ttys __P((void));state_func_t catatonia __P((void));state_func_t death __P((void));enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT;void transition __P((state_t));state_t requested_transition = runcom;void setctty __P((char *));typedef struct init_session {	int	se_index;		/* index of entry in ttys file */	pid_t	se_process;		/* controlling process */	time_t	se_started;		/* used to avoid thrashing */	int	se_flags;		/* status of session */#define	SE_SHUTDOWN	0x1		/* session won't be restarted */	char	*se_device;		/* filename of port */	char	*se_getty;		/* what to run on that port */	char	**se_getty_argv;	/* pre-parsed argument array */	char	*se_window;		/* window system (started only once) */	char	**se_window_argv;	/* pre-parsed argument array */	struct	init_session *se_prev;	struct	init_session *se_next;} session_t;void free_session __P((session_t *));session_t *new_session __P((session_t *, int, struct ttyent *));session_t *sessions;char **construct_argv __P((char *));void start_window_system __P((session_t *));void collect_child __P((pid_t));pid_t start_getty __P((session_t *));void transition_handler __P((int));void alrm_handler __P((int));void setsecuritylevel __P((int));int getsecuritylevel __P((void));int setupargv __P((session_t *, struct ttyent *));int clang;void clear_session_logs __P((session_t *));int start_session_db __P((void));void add_session __P((session_t *));void del_session __P((session_t *));session_t *find_session __P((pid_t));DB *session_db;/* * The mother of all processes. */intmain(argc, argv)	int argc;	char **argv;{	int c;	struct sigaction sa;	sigset_t mask;	/* Dispose of random users. */	if (getuid() != 0) {		(void)fprintf(stderr, "init: %s\n", strerror(EPERM));		exit (1);	}	/* System V users like to reexec init. */	if (getpid() != 1) {		(void)fprintf(stderr, "init: already running\n");		exit (1);	}	/*	 * Note that this does NOT open a file...	 * Does 'init' deserve its own facility number?	 */	openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH);	/*	 * Create an initial session.	 */	if (setsid() < 0)		warning("initial setsid() failed: %m");	/*	 * Establish an initial user so that programs running	 * single user do not freak out and die (like passwd).	 */	if (setlogin("root") < 0)		warning("setlogin() failed: %m");	/*	 * This code assumes that we always get arguments through flags,	 * never through bits set in some random machine register.	 */	while ((c = getopt(argc, argv, "sf")) != -1)		switch (c) {		case 's':			requested_transition = single_user;			break;		case 'f':			runcom_mode = FASTBOOT;			break;		default:			warning("unrecognized flag '-%c'", c);			break;		}	if (optind != argc)		warning("ignoring excess arguments");	/*	 * We catch or block signals rather than ignore them,	 * so that they get reset on exec.	 */	handle(badsys, SIGSYS, 0);	handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV,	       SIGBUS, SIGXCPU, SIGXFSZ, 0);	handle(transition_handler, SIGHUP, SIGTERM, SIGTSTP, 0);	handle(alrm_handler, SIGALRM, 0);	sigfillset(&mask);	delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS,		SIGXCPU, SIGXFSZ, SIGHUP, SIGTERM, SIGTSTP, SIGALRM, 0);	sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);	sigemptyset(&sa.sa_mask);	sa.sa_flags = 0;	sa.sa_handler = SIG_IGN;	(void) sigaction(SIGTTIN, &sa, (struct sigaction *)0);	(void) sigaction(SIGTTOU, &sa, (struct sigaction *)0);	/*	 * Paranoia.	 */	close(0);	close(1);	close(2);	/*	 * Start the state machine.	 */	transition(requested_transition);	/*	 * Should never reach here.	 */	return 1;}/* * Associate a function with a signal handler. */void#ifdef __STDC__handle(sig_t handler, ...)#elsehandle(va_alist)	va_dcl#endif{	int sig;	struct sigaction sa;	int mask_everything;	va_list ap;#ifndef __STDC__	sig_t handler;	va_start(ap);	handler = va_arg(ap, sig_t);#else	va_start(ap, handler);#endif	sa.sa_handler = handler;	sigfillset(&mask_everything);	while (sig = va_arg(ap, int)) {		sa.sa_mask = mask_everything;		/* XXX SA_RESTART? */		sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0;		sigaction(sig, &sa, (struct sigaction *) 0);	}	va_end(ap);}/* * Delete a set of signals from a mask. */void#ifdef __STDC__delset(sigset_t *maskp, ...)#elsedelset(va_alist)	va_dcl#endif{	int sig;	va_list ap;#ifndef __STDC__	sigset_t *maskp;	va_start(ap);	maskp = va_arg(ap, sigset_t *);#else	va_start(ap, maskp);#endif	while (sig = va_arg(ap, int))		sigdelset(maskp, sig);	va_end(ap);}/* * Log a message and sleep for a while (to give someone an opportunity * to read it and to save log or hardcopy output if the problem is chronic). * NB: should send a message to the session logger to avoid blocking. */void#ifdef __STDC__stall(char *message, ...)#elsestall(va_alist)	va_dcl#endif{	va_list ap;#ifndef __STDC__	char *message;	va_start(ap);	message = va_arg(ap, char *);#else	va_start(ap, message);#endif	vsyslog(LOG_ALERT, message, ap);	va_end(ap);	sleep(STALL_TIMEOUT);}/* * Like stall(), but doesn't sleep. * If cpp had variadic macros, the two functions could be #defines for another. * NB: should send a message to the session logger to avoid blocking. */void#ifdef __STDC__warning(char *message, ...)#elsewarning(va_alist)	va_dcl#endif{	va_list ap;#ifndef __STDC__	char *message;	va_start(ap);	message = va_arg(ap, char *);#else	va_start(ap, message);#endif	vsyslog(LOG_ALERT, message, ap);	va_end(ap);}/* * Log an emergency message. * NB: should send a message to the session logger to avoid blocking. */void#ifdef __STDC__emergency(char *message, ...)#elseemergency(va_alist)	va_dcl#endif{	va_list ap;#ifndef __STDC__	char *message;	va_start(ap);	message = va_arg(ap, char *);#else	va_start(ap, message);#endif	vsyslog(LOG_EMERG, message, ap);	va_end(ap);}/* * Catch a SIGSYS signal. * * These may arise if a system does not support sysctl. * We tolerate up to 25 of these, then throw in the towel. */voidbadsys(sig)	int sig;{	static int badcount = 0;	if (badcount++ < 25)		return;	disaster(sig);}/* * Catch an unexpected signal. */voiddisaster(sig)	int sig;{	emergency("fatal signal: %s",		sig < (unsigned) NSIG ? sys_siglist[sig] : "unknown signal");	sleep(STALL_TIMEOUT);	_exit(sig);		/* reboot */}/* * Get the security level of the kernel. */intgetsecuritylevel(){#ifdef KERN_SECURELVL	int name[2], curlevel;	size_t len;	extern int errno;	name[0] = CTL_KERN;	name[1] = KERN_SECURELVL;	len = sizeof curlevel;	if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) {		emergency("cannot get kernel security level: %s",		    strerror(errno));		return (-1);	}	return (curlevel);#else	return (-1);#endif}/* * Set the security level of the kernel. */voidsetsecuritylevel(newlevel)	int newlevel;{#ifdef KERN_SECURELVL	int name[2], curlevel;	extern int errno;	curlevel = getsecuritylevel();	if (newlevel == curlevel)		return;	name[0] = CTL_KERN;	name[1] = KERN_SECURELVL;	if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) {		emergency(		    "cannot change kernel security level from %d to %d: %s",		    curlevel, newlevel, strerror(errno));		return;	}#ifdef SECURE	warning("kernel security level changed from %d to %d",	    curlevel, newlevel);#endif#endif}/* * Change states in the finite state machine. * The initial state is passed as an argument. */voidtransition(s)	state_t s;{	for (;;)		s = (state_t) (*s)();}/* * Close out the accounting files for a login session. * NB: should send a message to the session logger to avoid blocking. */voidclear_session_logs(sp)	session_t *sp;{	char *line = sp->se_device + sizeof(_PATH_DEV) - 1;	if (logout(line))		logwtmp(line, "", "");}/* * Start a session and allocate a controlling terminal. * Only called by children of init after forking. */voidsetctty(name)	char *name;{	int fd;	(void) revoke(name);	sleep (2);			/* leave DTR low */	if ((fd = open(name, O_RDWR)) == -1) {		stall("can't open %s: %m", name);		_exit(1);	}	if (login_tty(fd) == -1) {		stall("can't get %s for controlling terminal: %m", name);		_exit(1);	}}/* * Bring the system up single user. */state_func_tsingle_user(){	pid_t pid, wpid;	int status;	sigset_t mask;	char *shell = _PATH_BSHELL;	char *argv[2];#ifdef SECURE	struct ttyent *typ;	struct passwd *pp;	static const char banner[] =		"Enter root password, or ^D to go multi-user\n";	char *clear, *password;#endif	/*	 * If the kernel is in secure mode, downgrade it to insecure mode.	 */	if (getsecuritylevel() > 0)		setsecuritylevel(0);	if ((pid = fork()) == 0) {		/*		 * Start the single user session.		 */		setctty(_PATH_CONSOLE);#ifdef SECURE		/*		 * Check the root password.		 * We don't care if the console is 'on' by default;		 * it's the only tty that can be 'off' and 'secure'.		 */		typ = getttynam("console");		pp = getpwnam("root");		if (typ && (typ->ty_status & TTY_SECURE) == 0 && pp) {			write(2, banner, sizeof banner - 1);			for (;;) {				clear = getpass("Password:");				if (clear == 0 || *clear == '\0')					_exit(0);				password = crypt(clear, pp->pw_passwd);				bzero(clear, _PASSWORD_LEN);				if (strcmp(password, pp->pw_passwd) == 0)					break;				warning("single-user login failed\n");			}		}		endttyent();		endpwent();#endif /* SECURE */#ifdef DEBUGSHELL		{			char altshell[128], *cp = altshell;			int num;#define	SHREQUEST \	"Enter pathname of shell or RETURN for sh: "			(void)write(STDERR_FILENO,			    SHREQUEST, sizeof(SHREQUEST) - 1);			while ((num = read(STDIN_FILENO, cp, 1)) != -1 &&			    num != 0 && *cp != '\n' && cp < &altshell[127])					cp++;			*cp = '\0';			if (altshell[0] != '\0')				shell = altshell;		}#endif /* DEBUGSHELL */		/*		 * Unblock signals.		 * We catch all the interesting ones,		 * and those are reset to SIG_DFL on exec.		 */		sigemptyset(&mask);		sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);		/*		 * Fire off a shell.		 * If the default one doesn't work, try the Bourne shell.		 */		argv[0] = "-sh";		argv[1] = 0;		execv(shell, argv);		emergency("can't exec %s for single user: %m", shell);		execv(_PATH_BSHELL, argv);		emergency("can't exec %s for single user: %m", _PATH_BSHELL);		sleep(STALL_TIMEOUT);		_exit(1);	}	if (pid == -1) {		/*		 * We are seriously hosed.  Do our best.		 */		emergency("can't fork single-user shell, trying again");		while (waitpid(-1, (int *) 0, WNOHANG) > 0)			continue;		return (state_func_t) single_user;	}	requested_transition = 0;	do {		if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)			collect_child(wpid);		if (wpid == -1) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -