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

📄 init.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
			if (errno == EINTR)				continue;			warning("wait for single-user shell failed: %m; restarting");			return (state_func_t) single_user;		}		if (wpid == pid && WIFSTOPPED(status)) {			warning("init: shell stopped, restarting\n");			kill(pid, SIGCONT);			wpid = -1;		}	} while (wpid != pid && !requested_transition);	if (requested_transition)		return (state_func_t) requested_transition;	if (!WIFEXITED(status)) {		if (WTERMSIG(status) == SIGKILL) { 			/* 			 *  reboot(8) killed shell? 			 */			warning("single user shell terminated.");			sleep(STALL_TIMEOUT);			_exit(0);		} else {				warning("single user shell terminated, restarting");			return (state_func_t) single_user;		}	}	runcom_mode = FASTBOOT;	return (state_func_t) runcom;}/* * Run the system startup script. */state_func_truncom(){	pid_t pid, wpid;	int status;	char *argv[4];	struct sigaction sa;	if ((pid = fork()) == 0) {		sigemptyset(&sa.sa_mask);		sa.sa_flags = 0;		sa.sa_handler = SIG_IGN;		(void) sigaction(SIGTSTP, &sa, (struct sigaction *)0);		(void) sigaction(SIGHUP, &sa, (struct sigaction *)0);		setctty(_PATH_CONSOLE);		argv[0] = "sh";		argv[1] = _PATH_RUNCOM;		argv[2] = runcom_mode == AUTOBOOT ? "autoboot" : 0;		argv[3] = 0;		sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0);		execv(_PATH_BSHELL, argv);		stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNCOM);		_exit(1);	/* force single user mode */	}	if (pid == -1) {		emergency("can't fork for %s on %s: %m",			_PATH_BSHELL, _PATH_RUNCOM);		while (waitpid(-1, (int *) 0, WNOHANG) > 0)			continue;		sleep(STALL_TIMEOUT);		return (state_func_t) single_user;	}	/*	 * Copied from single_user().  This is a bit paranoid.	 */	do {		if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)			collect_child(wpid);		if (wpid == -1) {			if (errno == EINTR)				continue;			warning("wait for %s on %s failed: %m; going to single user mode",				_PATH_BSHELL, _PATH_RUNCOM);			return (state_func_t) single_user;		}		if (wpid == pid && WIFSTOPPED(status)) {			warning("init: %s on %s stopped, restarting\n",				_PATH_BSHELL, _PATH_RUNCOM);			kill(pid, SIGCONT);			wpid = -1;		}	} while (wpid != pid);	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM &&	    requested_transition == catatonia) {		/* /etc/rc executed /sbin/reboot; wait for the end quietly */		sigset_t s;		sigfillset(&s);		for (;;)			sigsuspend(&s);	}	if (!WIFEXITED(status)) {		warning("%s on %s terminated abnormally, going to single user mode",			_PATH_BSHELL, _PATH_RUNCOM);		return (state_func_t) single_user;	}	if (WEXITSTATUS(status))		return (state_func_t) single_user;	runcom_mode = AUTOBOOT;		/* the default */	/* NB: should send a message to the session logger to avoid blocking. */	logwtmp("~", "reboot", "");	return (state_func_t) read_ttys;}/* * Open the session database. * * NB: We could pass in the size here; is it necessary? */intstart_session_db(){	if (session_db && (*session_db->close)(session_db))		emergency("session database close: %s", strerror(errno));	if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) {		emergency("session database open: %s", strerror(errno));		return (1);	}	return (0);		}/* * Add a new login session. */voidadd_session(sp)	session_t *sp;{	DBT key;	DBT data;	key.data = &sp->se_process;	key.size = sizeof sp->se_process;	data.data = &sp;	data.size = sizeof sp;	if ((*session_db->put)(session_db, &key, &data, 0))		emergency("insert %d: %s", sp->se_process, strerror(errno));}/* * Delete an old login session. */voiddel_session(sp)	session_t *sp;{	DBT key;	key.data = &sp->se_process;	key.size = sizeof sp->se_process;	if ((*session_db->del)(session_db, &key, 0))		emergency("delete %d: %s", sp->se_process, strerror(errno));}/* * Look up a login session by pid. */session_t *#ifdef __STDC__find_session(pid_t pid)#elsefind_session(pid)	pid_t pid;#endif{	DBT key;	DBT data;	session_t *ret;	key.data = &pid;	key.size = sizeof pid;	if ((*session_db->get)(session_db, &key, &data, 0) != 0)		return 0;	bcopy(data.data, (char *)&ret, sizeof(ret));	return ret;}/* * Construct an argument vector from a command line. */char **construct_argv(command)	char *command;{	register int argc = 0;	register char **argv = (char **) malloc(((strlen(command) + 1) / 2 + 1)						* sizeof (char *));	static const char separators[] = " \t";	if ((argv[argc++] = strtok(command, separators)) == 0)		return 0;	while (argv[argc++] = strtok((char *) 0, separators))		continue;	return argv;}/* * Deallocate a session descriptor. */voidfree_session(sp)	register session_t *sp;{	free(sp->se_device);	if (sp->se_getty) {		free(sp->se_getty);		free(sp->se_getty_argv);	}	if (sp->se_window) {		free(sp->se_window);		free(sp->se_window_argv);	}	free(sp);}/* * Allocate a new session descriptor. */session_t *new_session(sprev, session_index, typ)	session_t *sprev;	int session_index;	register struct ttyent *typ;{	register session_t *sp;	if ((typ->ty_status & TTY_ON) == 0 ||	    typ->ty_name == 0 ||	    typ->ty_getty == 0)		return 0;	sp = (session_t *) malloc(sizeof (session_t));	bzero(sp, sizeof *sp);	sp->se_index = session_index;	sp->se_device = malloc(sizeof(_PATH_DEV) + strlen(typ->ty_name));	(void) sprintf(sp->se_device, "%s%s", _PATH_DEV, typ->ty_name);	if (setupargv(sp, typ) == 0) {		free_session(sp);		return (0);	}	sp->se_next = 0;	if (sprev == 0) {		sessions = sp;		sp->se_prev = 0;	} else {		sprev->se_next = sp;		sp->se_prev = sprev;	}	return sp;}/* * Calculate getty and if useful window argv vectors. */intsetupargv(sp, typ)	session_t *sp;	struct ttyent *typ;{	if (sp->se_getty) {		free(sp->se_getty);		free(sp->se_getty_argv);	}	sp->se_getty = malloc(strlen(typ->ty_getty) + strlen(typ->ty_name) + 2);	(void) sprintf(sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name);	sp->se_getty_argv = construct_argv(sp->se_getty);	if (sp->se_getty_argv == 0) {		warning("can't parse getty for port %s", sp->se_device);		free(sp->se_getty);		sp->se_getty = 0;		return (0);	}	if (typ->ty_window) {		if (sp->se_window)			free(sp->se_window);		sp->se_window = strdup(typ->ty_window);		sp->se_window_argv = construct_argv(sp->se_window);		if (sp->se_window_argv == 0) {			warning("can't parse window for port %s",				sp->se_device);			free(sp->se_window);			sp->se_window = 0;			return (0);		}	}	return (1);}/* * Walk the list of ttys and create sessions for each active line. */state_func_tread_ttys(){	int session_index = 0;	register session_t *sp, *snext;	register struct ttyent *typ;	/*	 * Destroy any previous session state.	 * There shouldn't be any, but just in case...	 */	for (sp = sessions; sp; sp = snext) {		if (sp->se_process)			clear_session_logs(sp);		snext = sp->se_next;		free_session(sp);	}	sessions = 0;	if (start_session_db())		return (state_func_t) single_user;	/*	 * Allocate a session entry for each active port.	 * Note that sp starts at 0.	 */	while (typ = getttyent())		if (snext = new_session(sp, ++session_index, typ))			sp = snext;	endttyent();	return (state_func_t) multi_user;}/* * Start a window system running. */voidstart_window_system(sp)	session_t *sp;{	pid_t pid;	sigset_t mask;	if ((pid = fork()) == -1) {		emergency("can't fork for window system on port %s: %m",			sp->se_device);		/* hope that getty fails and we can try again */		return;	}	if (pid)		return;	sigemptyset(&mask);	sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);	if (setsid() < 0)		emergency("setsid failed (window) %m");	execv(sp->se_window_argv[0], sp->se_window_argv);	stall("can't exec window system '%s' for port %s: %m",		sp->se_window_argv[0], sp->se_device);	_exit(1);}/* * Start a login session running. */pid_tstart_getty(sp)	session_t *sp;{	pid_t pid;	sigset_t mask;	time_t current_time = time((time_t *) 0);	/*	 * fork(), not vfork() -- we can't afford to block.	 */	if ((pid = fork()) == -1) {		emergency("can't fork for getty on port %s: %m", sp->se_device);		return -1;	}	if (pid)		return pid;	if (current_time > sp->se_started &&	    current_time - sp->se_started < GETTY_SPACING) {		warning("getty repeating too quickly on port %s, sleeping",		        sp->se_device);		sleep((unsigned) GETTY_SLEEP);	}	if (sp->se_window) {		start_window_system(sp);		sleep(WINDOW_WAIT);	}	sigemptyset(&mask);	sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);	execv(sp->se_getty_argv[0], sp->se_getty_argv);	stall("can't exec getty '%s' for port %s: %m",		sp->se_getty_argv[0], sp->se_device);	_exit(1);}/* * Collect exit status for a child. * If an exiting login, start a new login running. */void#ifdef __STDC__collect_child(pid_t pid)#elsecollect_child(pid)	pid_t pid;#endif{	register session_t *sp, *sprev, *snext;	if (! sessions)		return;	if (! (sp = find_session(pid)))		return;	clear_session_logs(sp);	del_session(sp);	sp->se_process = 0;	if (sp->se_flags & SE_SHUTDOWN) {		if (sprev = sp->se_prev)			sprev->se_next = sp->se_next;		else			sessions = sp->se_next;		if (snext = sp->se_next)			snext->se_prev = sp->se_prev;		free_session(sp);		return;	}	if ((pid = start_getty(sp)) == -1) {		/* serious trouble */		requested_transition = clean_ttys;		return;	}	sp->se_process = pid;	sp->se_started = time((time_t *) 0);	add_session(sp);}/* * Catch a signal and request a state transition. */voidtransition_handler(sig)	int sig;{	switch (sig) {	case SIGHUP:		requested_transition = clean_ttys;		break;	case SIGTERM:		requested_transition = death;		break;	case SIGTSTP:		requested_transition = catatonia;		break;	default:		requested_transition = 0;		break;	}}/* * Take the system multiuser. */state_func_tmulti_user(){	pid_t pid;	register session_t *sp;	requested_transition = 0;	/*	 * If the administrator has not set the security level to -1	 * to indicate that the kernel should not run multiuser in secure	 * mode, and the run script has not set a higher level of security 	 * than level 1, then put the kernel into secure mode.	 */	if (getsecuritylevel() == 0)		setsecuritylevel(1);	for (sp = sessions; sp; sp = sp->se_next) {		if (sp->se_process)			continue;		if ((pid = start_getty(sp)) == -1) {			/* serious trouble */			requested_transition = clean_ttys;			break;		}		sp->se_process = pid;		sp->se_started = time((time_t *) 0);		add_session(sp);	}	while (!requested_transition)		if ((pid = waitpid(-1, (int *) 0, 0)) != -1)			collect_child(pid);	return (state_func_t) requested_transition;}/* * This is an n-squared algorithm.  We hope it isn't run often... */state_func_tclean_ttys(){	register session_t *sp, *sprev;	register struct ttyent *typ;	register int session_index = 0;	register int devlen;	if (! sessions)		return (state_func_t) multi_user;	devlen = sizeof(_PATH_DEV) - 1;	while (typ = getttyent()) {		++session_index;		for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next)			if (strcmp(typ->ty_name, sp->se_device + devlen) == 0)				break;		if (sp) {			if (sp->se_index != session_index) {				warning("port %s changed utmp index from %d to %d",				       sp->se_device, sp->se_index,				       session_index);				sp->se_index = session_index;			}			if ((typ->ty_status & TTY_ON) == 0 ||			    typ->ty_getty == 0) {				sp->se_flags |= SE_SHUTDOWN;				kill(sp->se_process, SIGHUP);				continue;			}			sp->se_flags &= ~SE_SHUTDOWN;			if (setupargv(sp, typ) == 0) {				warning("can't parse getty for port %s",					sp->se_device);				sp->se_flags |= SE_SHUTDOWN;				kill(sp->se_process, SIGHUP);			}			continue;		}		new_session(sprev, session_index, typ);	}	endttyent();	return (state_func_t) multi_user;}/* * Block further logins. */state_func_tcatatonia(){	register session_t *sp;	for (sp = sessions; sp; sp = sp->se_next)		sp->se_flags |= SE_SHUTDOWN;	return (state_func_t) multi_user;}/* * Note SIGALRM. */voidalrm_handler(sig)	int sig;{	clang = 1;}/* * Bring the system down to single user. */state_func_tdeath(){	register session_t *sp;	register int i;	pid_t pid;	static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL };	for (sp = sessions; sp; sp = sp->se_next)		sp->se_flags |= SE_SHUTDOWN;	/* NB: should send a message to the session logger to avoid blocking. */	logwtmp("~", "shutdown", "");	for (i = 0; i < 3; ++i) {		if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)			return (state_func_t) single_user;		clang = 0;		alarm(DEATH_WATCH);		do			if ((pid = waitpid(-1, (int *)0, 0)) != -1)				collect_child(pid);		while (clang == 0 && errno != ECHILD);		if (errno == ECHILD)			return (state_func_t) single_user;	}	warning("some processes would not die; ps axl advised");	return (state_func_t) single_user;}

⌨️ 快捷键说明

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