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

📄 init.c

📁 sysvinit--linux系统下的init
💻 C
📖 第 1 页 / 共 4 页
字号:
	/*	 *	Only BOOT processes may live in all levels	 */	if (ch->action != BOOT &&	    strchr(ch->rlevel, runlevel) == NULL) {		/*		 *	Ondemand procedures live always,		 *	except in single user		 */		if (runlevel == 'S' || !(ch->flags & DEMAND))			ch->flags |= KILLME;	}	/*	 *	Now, if this process may live note so in the new list	 */	if ((ch->flags & KILLME) == 0) {		ch->new->flags  = ch->flags;		ch->new->pid    = ch->pid;		ch->new->exstat = ch->exstat;		continue;	}	/*	 *	Is this process still around?	 */	if ((ch->flags & RUNNING) == 0) {		ch->flags &= ~KILLME;		continue;	}	INITDBG(L_VB, "Killing \"%s\"", ch->process);	switch(round) {		case 0: /* Send TERM signal */			if (talk)				initlog(L_CO,					"Sending processes the TERM signal");			kill(-(ch->pid), SIGTERM);			foundOne = 1;			break;		case 1: /* Send KILL signal and collect status */			if (talk)				initlog(L_CO,					"Sending processes the KILL signal");			kill(-(ch->pid), SIGKILL);			break;	}	talk = 0;	    }    /*     *	See if we have to wait 5 seconds     */    if (foundOne && round == 0) {	/*	 *	Yup, but check every second if we still have children.	 */	for(f = 0; f < sltime; f++) {		for(ch = family; ch; ch = ch->next) {			if (!(ch->flags & KILLME)) continue;			if ((ch->flags & RUNNING) && !(ch->flags & ZOMBIE))				break;		}		if (ch == NULL) {			/*			 *	No running children, skip SIGKILL			 */			round = 1;			foundOne = 0; /* Skip the sleep below. */			break;		}		do_sleep(1);	}    }  }  /*   *	Now give all processes the chance to die and collect exit statuses.   */  if (foundOne) do_sleep(1);  for(ch = family; ch; ch = ch->next)	if (ch->flags & KILLME) {		if (!(ch->flags & ZOMBIE))		    initlog(L_CO, "Pid %d [id %s] seems to hang", ch->pid,				ch->id);		else {		    INITDBG(L_VB, "Updating utmp for pid %d [id %s]",				ch->pid, ch->id);		    ch->flags &= ~RUNNING;		    if (ch->process[0] != '+')		    	write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);		}	}  /*   *	Both rounds done; clean up the list.   */  sigemptyset(&nmask);  sigaddset(&nmask, SIGCHLD);  sigprocmask(SIG_BLOCK, &nmask, &omask);  for(ch = family; ch; ch = old) {	old = ch->next;	free(ch);  }  family = newFamily;  for(ch = family; ch; ch = ch->next) ch->new = NULL;  newFamily = NULL;  sigprocmask(SIG_SETMASK, &omask, NULL);#ifdef INITLVL  /*   *	Dispose of INITLVL file.   */  if (lstat(INITLVL, &st) >= 0 && S_ISLNK(st.st_mode)) {	/*	 *	INITLVL is a symbolic link, so just truncate the file.	 */	close(open(INITLVL, O_WRONLY|O_TRUNC));  } else {	/*	 *	Delete INITLVL file.	 */  	unlink(INITLVL);  }#endif#ifdef INITLVL2  /*   *	Dispose of INITLVL2 file.   */  if (lstat(INITLVL2, &st) >= 0 && S_ISLNK(st.st_mode)) {	/*	 *	INITLVL2 is a symbolic link, so just truncate the file.	 */	close(open(INITLVL2, O_WRONLY|O_TRUNC));  } else {	/*	 *	Delete INITLVL2 file.	 */  	unlink(INITLVL2);  }#endif}/* *	Walk through the family list and start up children. *	The entries that do not belong here at all are removed *	from the list. */void start_if_needed(void){	CHILD *ch;		/* Pointer to child */	int delete;		/* Delete this entry from list? */	INITDBG(L_VB, "Checking for children to start");	for(ch = family; ch; ch = ch->next) {#if DEBUG		if (ch->rlevel[0] == 'C') {			INITDBG(L_VB, "%s: flags %d", ch->process, ch->flags);		}#endif		/* Are we waiting for this process? Then quit here. */		if (ch->flags & WAITING) break;		/* Already running? OK, don't touch it */		if (ch->flags & RUNNING) continue;		/* See if we have to start it up */		delete = 1;		if (strchr(ch->rlevel, runlevel) ||		    ((ch->flags & DEMAND) && !strchr("#*Ss", runlevel))) {			startup(ch);			delete = 0;		}		if (delete) {			/* FIXME: is this OK? */			ch->flags &= ~(RUNNING|WAITING);			if (!ISPOWER(ch->action) && ch->action != KBREQUEST)				ch->flags &= ~XECUTED;			ch->pid = 0;		} else			/* Do we have to wait for this process? */			if (ch->flags & WAITING) break;	}	/* Done. */}/* *	Ask the user on the console for a runlevel */int ask_runlevel(void){	const char	prompt[] = "\nEnter runlevel: ";	char		buf[8];	int		lvl = -1;	int		fd;	console_stty();	fd = console_open(O_RDWR|O_NOCTTY);	if (fd < 0) return('S');	while(!strchr("0123456789S", lvl)) {  		write(fd, prompt, sizeof(prompt) - 1);		buf[0] = 0;  		read(fd, buf, sizeof(buf));  		if (buf[0] != 0 && (buf[1] == '\r' || buf[1] == '\n'))			lvl = buf[0];		if (islower(lvl)) lvl = toupper(lvl);	}	close(fd);	return lvl;}/* *	Search the INITTAB file for the 'initdefault' field, with the default *	runlevel. If this fails, ask the user to supply a runlevel. */int get_init_default(void){	CHILD *ch;	int lvl = -1;	char *p;	/*	 *	Look for initdefault.	 */	for(ch = family; ch; ch = ch->next)		if (ch->action == INITDEFAULT) {			p = ch->rlevel;			while(*p) {				if (*p > lvl) lvl = *p;				p++;			}			break;		}	/*	 *	See if level is valid	 */	if (lvl > 0) {		if (islower(lvl)) lvl = toupper(lvl);		if (strchr("0123456789S", lvl) == NULL) {			initlog(L_VB,				"Initdefault level '%c' is invalid", lvl);			lvl = 0;		}	}	/*	 *	Ask for runlevel on console if needed.	 */	if (lvl <= 0) lvl = ask_runlevel();	/*	 *	Log the fact that we have a runlevel now.	 */	return lvl;}/* *	We got signaled. * *	Do actions for the new level. If we are compatible with *	the "old" INITLVL and arg == 0, try to read the new *	runlevel from that file first. */int read_level(int arg){	CHILD		*ch;			/* Walk through list */	unsigned char	foo = 'X';		/* Contents of INITLVL */	int		ok = 1;#ifdef INITLVL	FILE		*fp;	struct stat	stt;	int		st;#endif	if (arg) foo = arg;#ifdef INITLVL	ok = 0;	if (arg == 0) {		fp = NULL;		if (stat(INITLVL, &stt) != 0 || stt.st_size != 0L)			fp = fopen(INITLVL, "r");#ifdef INITLVL2		if (fp == NULL &&		    (stat(INITLVL2, &stt) != 0 || stt.st_size != 0L))			fp = fopen(INITLVL2, "r");#endif		if (fp == NULL) {			/* INITLVL file empty or not there - act as 'init q' */			initlog(L_SY, "Re-reading inittab");  			return(runlevel);		}		ok = fscanf(fp, "%c %d", &foo, &st);		fclose(fp);	} else {		/* We go to the new runlevel passed as an argument. */		foo = arg;		ok = 1;	}	if (ok == 2) sltime = st;#endif /* INITLVL */	if (islower(foo)) foo = toupper(foo);	if (ok < 1 || ok > 2 || strchr("QS0123456789ABCU", foo) == NULL) { 		initlog(L_VB, "bad runlevel: %c", foo);  		return runlevel;	}	/* Log this action */	switch(foo) {		case 'S':  			initlog(L_VB, "Going single user");			break;		case 'Q':			initlog(L_SY, "Re-reading inittab");			break;		case 'A':		case 'B':		case 'C':			initlog(L_SY,				"Activating demand-procedures for '%c'", foo);			break;		case 'U':			initlog(L_SY, "Trying to re-exec init");			return 'U';		default:		  	initlog(L_VB, "Switching to runlevel: %c", foo);	}	if (foo == 'Q') return runlevel;	/* Check if this is a runlevel a, b or c */	if (strchr("ABC", foo)) {		if (runlevel == 'S') return(runlevel);		/* Read inittab again first! */		read_inittab();  		/* Mark those special tasks */		for(ch = family; ch; ch = ch->next)			if (strchr(ch->rlevel, foo) != NULL ||			    strchr(ch->rlevel, tolower(foo)) != NULL) {				ch->flags |= DEMAND;				ch->flags &= ~XECUTED;				INITDBG(L_VB,					"Marking (%s) as ondemand, flags %d",					ch->id, ch->flags);			}  		return runlevel;	}	/* Store both the old and the new runlevel. */	write_utmp_wtmp("runlevel", "~~", foo + 256*runlevel, RUN_LVL, "~");	thislevel = foo;	prevlevel = runlevel;	return foo;}/* *	This procedure is called after every signal (SIGHUP, SIGALRM..) * *	Only clear the 'failing' flag if the process is sleeping *	longer than 5 minutes, or inittab was read again due *	to user interaction. */void fail_check(void){	CHILD	*ch;			/* Pointer to child structure */	time_t	t;			/* System time */	time_t	next_alarm = 0;		/* When to set next alarm */	time(&t);	for(ch = family; ch; ch = ch->next) {		if (ch->flags & FAILING) {			/* Can we free this sucker? */			if (ch->tm + SLEEPTIME < t) {				ch->flags &= ~FAILING;				ch->count = 0;				ch->tm = 0;			} else {				/* No, we'll look again later */				if (next_alarm == 0 ||				    ch->tm + SLEEPTIME > next_alarm)					next_alarm = ch->tm + SLEEPTIME;			}		}	}	if (next_alarm) {		next_alarm -= t;		if (next_alarm < 1) next_alarm = 1;		alarm(next_alarm);	}}/* Set all 'Fail' timers to 0 */void fail_cancel(void){	CHILD *ch;	for(ch = family; ch; ch = ch->next) {		ch->count = 0;		ch->tm = 0;		ch->flags &= ~FAILING;	}}/* *	Start up powerfail entries. */void do_power_fail(int pwrstat){	CHILD *ch;	/*	 *	Tell powerwait & powerfail entries to start up	 */	for (ch = family; ch; ch = ch->next) {		if (pwrstat == 'O') {			/*		 	 *	The power is OK again.		 	 */			if (ch->action == POWEROKWAIT)				ch->flags &= ~XECUTED;		} else if (pwrstat == 'L') {			/*			 *	Low battery, shut down now.			 */			if (ch->action == POWERFAILNOW)				ch->flags &= ~XECUTED;		} else {			/*			 *	Power is failing, shutdown imminent			 */			if (ch->action == POWERFAIL || ch->action == POWERWAIT)				ch->flags &= ~XECUTED;		}	}}/* *	Check for state-pipe presence */int check_pipe(int fd){	struct timeval	t;	fd_set		s;	char		signature[8];	FD_ZERO(&s);	FD_SET(fd, &s);	t.tv_sec = t.tv_usec = 0;	if (select(fd+1, &s, NULL, NULL, &t) != 1)		return 0;	if (read(fd, signature, 8) != 8)		 return 0;	return strncmp(Signature, signature, 8) == 0;}/* *	 Make a state-pipe. */int make_pipe(int fd){	int fds[2];	pipe(fds);	dup2(fds[0], fd);	close(fds[0]);	fcntl(fds[1], F_SETFD, 1);	fcntl(fd, F_SETFD, 0);	write(fds[1], Signature, 8);	return fds[1];}/* *	Attempt to re-exec. */void re_exec(void){	CHILD		*ch;	sigset_t	mask, oldset;	pid_t		pid;	char		**env;	int		fd;	if (strchr("S12345",runlevel) == NULL)		return;	/*	 *	Reset the alarm, and block all signals.	 */	alarm(0);	sigfillset(&mask);	sigprocmask(SIG_BLOCK, &mask, &oldset);	/*	 *	construct a pipe fd --> STATE_PIPE and write a signature	 */	fd = make_pipe(STATE_PIPE);	/* 	 * It's a backup day today, so I'm pissed off.  Being a BOFH, however, 	 * does have it's advantages...	 */	fail_cancel();	close(pipe_fd);	pipe_fd = -1;	DELSET(got_signals, SIGCHLD);	DELSET(got_signals, SIGHUP);	DELSET(got_signals, SIGUSR1);	/*	 *	That should be cleaned.	 */	for(ch = family; ch; ch = ch->next)	    if (ch->flags & ZOMBIE) {		INITDBG(L_VB, "Child died, PID= %d", ch->pid);		ch->flags &= ~(RUNNING|ZOMBIE|WAITING);		if (ch->process[0] != '+')			write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);	    }	if ((pid = fork()) == 0) {		/*		 *	Child sends state information to the parent.		 */		send_state(fd);		exit(0);	}	/*	 *	The existing init process execs a new init binary.	 */	env = init_buildenv(0);	execl(myname, myname, "--init", NULL, env);	/*	 *	We shouldn't be here, something failed. 	 *	Bitch, close the state pipe, unblock signals and return.	 */	close(fd);	close(STATE_PIPE);	sigprocmask(SIG_SETMASK, &oldset, NULL);	init_freeenv(env);	initlog(L_CO, "Attempt to re-exec failed");}/* *	We got a change runlevel request through the *	init.fifo. Process it. */void fifo_new_level(int level){#if CHANGE_WAIT	CHILD	*ch;#endif	int	oldlevel;	if (level == runlevel) return;#if CHANGE_WAIT	/* Are we waiting for a child? */	for(ch = family; ch; ch = ch->next)		if (ch->flags & WAITING) break;	if (ch == NULL)#endif	{		/* We need to go into a new runlevel */		oldlevel = runlevel;		runlevel = read_level(level);		if (runlevel == 'U') {			runlevel = oldlevel;			re_exec();		} else {			if (oldlevel != 'S' && runlevel == 'S') console_stty();			if (runlevel == '6' || runlevel == '0' ||			    runlevel == '1') console_stty();			read_inittab();			fail_cancel();			setproctitle("init [%c]", runlevel);		}	}}/* *	Set/unset environment variables. The variables are *	encoded as KEY=VAL\0KEY=VAL\0\0. With "=VAL" it means *	setenv, without it means unsetenv. */void initcmd_setenv(char *data, int size){	char		*env, *p, *e, *eq;	int		i, sz;	e = data + size;	while (*data && data < e) {		eq = NULL;		for (p = data; *p && p < e; p++)			if (*p == '=') eq = p;		if (*p) break;		env = data;		data = ++p;		sz = eq ? (eq - env) : (p - env);		/*initlog(L_SY, "init_setenv: %s, %s, %d", env, eq, sz);*/		/*		 *	We only allow INIT_* to be set.		 */		if (strncmp(env, "INIT_", 5) != 0)			continue;		/* Free existing vars. */		for (i = 0; i < NR_EXTRA_ENV; i++) {			if (extra_env[i] == NULL) continue;			if (!strncmp(extra_env[i], env, sz) &&			    extra_env[i][sz] == '=') {				free(extra_env[i]);				extra_env[i] = NULL;			}		}		/* Set new vars if needed. */		if (eq == NULL) continue;		for (i = 0; i < NR_EXTRA_ENV; i++) {			if (extra_env[i] == NULL) {				extra_env[i] = istrdup(env);				break;			}		}	}}/* *	Read from the init FIFO. Processes like telnetd and rlogind can *	ask us to create login processes on their behalf. * *	FIXME:	this needs to be finished. NOT that it is buggy, but we need *		to add the telnetd/rlogind stuff so people can start using it. *		Maybe move to using an AF_UNIX socket so we can use *		the 2.2 kernel credential stuff to see who we're talking to. *	 */void check_init_fifo(void){  struct init_request	request;  struct timeval	tv;  struct stat		st, st2;  fd_set		fds;  int			n;

⌨️ 快捷键说明

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