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

📄 init.c

📁 sysvinit--linux系统下的init
💻 C
📖 第 1 页 / 共 4 页
字号:
	while(!got_cont) pause();	got_cont = 0;	errno = saved_errno;}/* *	Set terminal settings to reasonable defaults */void console_stty(void){	struct termios tty;	int fd;	if ((fd = console_open(O_RDWR|O_NOCTTY)) < 0) {		initlog(L_VB, "can't open %s", console_dev);		return;	}	(void) tcgetattr(fd, &tty);	tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;	tty.c_cflag |= HUPCL|CLOCAL|CREAD;	tty.c_cc[VINTR]  = 3;	/* ctrl('c') */	tty.c_cc[VQUIT]  = 28;	/* ctrl('\\') */	tty.c_cc[VERASE] = 127;	tty.c_cc[VKILL]  = 24;	/* ctrl('x') */	tty.c_cc[VEOF]   = 4;	/* ctrl('d') */	tty.c_cc[VTIME]  = 0;	tty.c_cc[VMIN]   = 1;	tty.c_cc[VSTART] = 17;	/* ctrl('q') */	tty.c_cc[VSTOP]  = 19;	/* ctrl('s') */	tty.c_cc[VSUSP]  = 26;	/* ctrl('z') */	/*	 *	Set pre and post processing	 */	tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY;	tty.c_oflag = OPOST|ONLCR;	tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOPRT|ECHOKE;	/*	 *	Now set the terminal line.	 *	We don't care about non-transmitted output data	 *	and non-read input data.	 */	(void) tcsetattr(fd, TCSANOW, &tty);	(void) tcflush(fd, TCIOFLUSH);	(void) close(fd);}/* *	Print to the system console */void print(char *s){	int fd;	if ((fd = console_open(O_WRONLY|O_NOCTTY|O_NDELAY)) >= 0) {		write(fd, s, strlen(s));		close(fd);	}}/* *	Log something to a logfile and the console. */#ifdef __GNUC____attribute__ ((format (printf, 2, 3)))#endifvoid initlog(int loglevel, char *s, ...){	va_list va_alist;	char buf[256];	sigset_t nmask, omask;	va_start(va_alist, s);	vsnprintf(buf, sizeof(buf), s, va_alist);	va_end(va_alist);	if (loglevel & L_SY) {		/*		 *	Re-establish connection with syslogd every time.		 *	Block signals while talking to syslog.		 */		sigfillset(&nmask);		sigprocmask(SIG_BLOCK, &nmask, &omask);		openlog("init", 0, LOG_DAEMON);		syslog(LOG_INFO, "%s", buf);		closelog();		sigprocmask(SIG_SETMASK, &omask, NULL);	}	/*	 *	And log to the console.	 */	if (loglevel & L_CO) {		print("\rINIT: ");		print(buf);		print("\r\n");	}}/* *	Build a new environment for execve(). */char **init_buildenv(int child){	char		i_lvl[] = "RUNLEVEL=x";	char		i_prev[] = "PREVLEVEL=x";	char		i_cons[32];	char		**e;	int		n, i;	for (n = 0; environ[n]; n++)		;	n += NR_EXTRA_ENV + 8;	e = calloc(n, sizeof(char *));	for (n = 0; environ[n]; n++)		e[n] = istrdup(environ[n]);	for (i = 0; i < NR_EXTRA_ENV; i++)		if (extra_env[i])			e[n++] = istrdup(extra_env[i]);	if (child) {		snprintf(i_cons, sizeof(i_cons), "CONSOLE=%s", console_dev);		i_lvl[9]   = thislevel;		i_prev[10] = prevlevel;		e[n++] = istrdup(i_lvl);		e[n++] = istrdup(i_prev);		e[n++] = istrdup(i_cons);		e[n++] = istrdup(E_VERSION);	}	e[n++] = NULL;	return e;}void init_freeenv(char **e){	int		n;	for (n = 0; e[n]; n++)		free(e[n]);	free(e);}/* *	Fork and execute. * *	This function is too long and indents too deep. * */int spawn(CHILD *ch, int *res){  char *args[16];		/* Argv array */  char buf[136];		/* Line buffer */  int f, st, rc;		/* Scratch variables */  char *ptr;			/* Ditto */  time_t t;			/* System time */  int oldAlarm;			/* Previous alarm value */  char *proc = ch->process;	/* Command line */  pid_t pid, pgrp;		/* child, console process group. */  sigset_t nmask, omask;	/* For blocking SIGCHLD */  struct sigaction sa;  *res = -1;  buf[sizeof(buf) - 1] = 0;  /* Skip '+' if it's there */  if (proc[0] == '+') proc++;  ch->flags |= XECUTED;  if (ch->action == RESPAWN || ch->action == ONDEMAND) {	/* Is the date stamp from less than 2 minutes ago? */	time(&t);	if (ch->tm + TESTTIME > t) {		ch->count++;	} else {		ch->count = 0;		ch->tm = t;	}	/* Do we try to respawn too fast? */	if (ch->count >= MAXSPAWN) {	  initlog(L_VB,		"Id \"%s\" respawning too fast: disabled for %d minutes",		ch->id, SLEEPTIME / 60);	  ch->flags &= ~RUNNING;	  ch->flags |= FAILING;	  /* Remember the time we stopped */	  ch->tm = t;	  /* Try again in 5 minutes */	  oldAlarm = alarm(0);	  if (oldAlarm > SLEEPTIME || oldAlarm <= 0) oldAlarm = SLEEPTIME;	  alarm(oldAlarm);	  return(-1);	}  }  /* See if there is an "initscript" (except in single user mode). */  if (access(INITSCRIPT, R_OK) == 0 && runlevel != 'S') {	/* Build command line using "initscript" */	args[1] = SHELL;	args[2] = INITSCRIPT;	args[3] = ch->id;	args[4] = ch->rlevel;	args[5] = "unknown";	for(f = 0; actions[f].name; f++) {		if (ch->action == actions[f].act) {			args[5] = actions[f].name;			break;		}	}	args[6] = proc;	args[7] = NULL;  } else if (strpbrk(proc, "~`!$^&*()=|\\{}[];\"'<>?")) {  /* See if we need to fire off a shell for this command */  	/* Give command line to shell */  	args[1] = SHELL;  	args[2] = "-c";  	strcpy(buf, "exec ");  	strncat(buf, proc, sizeof(buf) - strlen(buf) - 1);  	args[3] = buf;  	args[4] = NULL;  } else {	/* Split up command line arguments */	buf[0] = 0;  	strncat(buf, proc, sizeof(buf) - 1);  	ptr = buf;  	for(f = 1; f < 15; f++) {  		/* Skip white space */  		while(*ptr == ' ' || *ptr == '\t') ptr++;  		args[f] = ptr;  				/* May be trailing space.. */		if (*ptr == 0) break;  		/* Skip this `word' */  		while(*ptr && *ptr != ' ' && *ptr != '\t' && *ptr != '#')  			ptr++;  		  		/* If end-of-line, break */	  		if (*ptr == '#' || *ptr == 0) {  			f++;  			*ptr = 0;  			break;  		}  		/* End word with \0 and continue */  		*ptr++ = 0;  	}  	args[f] = NULL;  }  args[0] = args[1];  while(1) {	/*	 *	Block sigchild while forking.	 */	sigemptyset(&nmask);	sigaddset(&nmask, SIGCHLD);	sigprocmask(SIG_BLOCK, &nmask, &omask);	if ((pid = fork()) == 0) {		close(0);		close(1);		close(2);		if (pipe_fd >= 0) close(pipe_fd);  		sigprocmask(SIG_SETMASK, &omask, NULL);		/*		 *	In sysinit, boot, bootwait or single user mode:		 *	for any wait-type subprocess we _force_ the console		 *	to be its controlling tty.		 */  		if (strchr("*#sS", runlevel) && ch->flags & WAITING) {			/*			 *	We fork once extra. This is so that we can			 *	wait and change the process group and session			 *	of the console after exit of the leader.			 */			setsid();			if ((f = console_open(O_RDWR|O_NOCTTY)) >= 0) {				/* Take over controlling tty by force */				(void)ioctl(f, TIOCSCTTY, 1);  				dup(f);  				dup(f);			}			if ((pid = fork()) < 0) {  				initlog(L_VB, "cannot fork");				exit(1);			}			if (pid > 0) {				/*				 *	Ignore keyboard signals etc.				 *	Then wait for child to exit.				 */				SETSIG(sa, SIGINT, SIG_IGN, SA_RESTART);				SETSIG(sa, SIGTSTP, SIG_IGN, SA_RESTART);				SETSIG(sa, SIGQUIT, SIG_IGN, SA_RESTART);				SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART);				while ((rc = waitpid(pid, &st, 0)) != pid)					if (rc < 0 && errno == ECHILD)						break;				/*				 *	Small optimization. See if stealing				 *	controlling tty back is needed.				 */				pgrp = tcgetpgrp(f);				if (pgrp != getpid())					exit(0);				/*				 *	Steal controlling tty away. We do				 *	this with a temporary process.				 */				if ((pid = fork()) < 0) {  					initlog(L_VB, "cannot fork");					exit(1);				}				if (pid == 0) {					setsid();					(void)ioctl(f, TIOCSCTTY, 1);					exit(0);				}				while((rc = waitpid(pid, &st, 0)) != pid)					if (rc < 0 && errno == ECHILD)						break;				exit(0);			}			/* Set ioctl settings to default ones */			console_stty();  		} else {			setsid();			if ((f = console_open(O_RDWR|O_NOCTTY)) < 0) {				initlog(L_VB, "open(%s): %s", console_dev,					strerror(errno));				f = open("/dev/null", O_RDWR);			}			dup(f);			dup(f);		}  		/* Reset all the signals, set up environment */  		for(f = 1; f < NSIG; f++) SETSIG(sa, f, SIG_DFL, SA_RESTART);		environ = init_buildenv(1);		/*		 *	Execute prog. In case of ENOEXEC try again		 *	as a shell script.		 */  		execvp(args[1], args + 1);		if (errno == ENOEXEC) {  			args[1] = SHELL;  			args[2] = "-c";  			strcpy(buf, "exec ");  			strncat(buf, proc, sizeof(buf) - strlen(buf) - 1);  			args[3] = buf;  			args[4] = NULL;			execvp(args[1], args + 1);		}  		initlog(L_VB, "cannot execute \"%s\"", args[1]);  		exit(1);  	}	*res = pid;  	sigprocmask(SIG_SETMASK, &omask, NULL);	INITDBG(L_VB, "Started id %s (pid %d)", ch->id, pid);	if (pid == -1) {		initlog(L_VB, "cannot fork, retry..");		do_sleep(5);		continue;	}	return(pid);  }}/* *	Start a child running! */void startup(CHILD *ch){	/*	 *	See if it's disabled	 */	if (ch->flags & FAILING) return;	switch(ch->action) {		case SYSINIT:		case BOOTWAIT:		case WAIT:		case POWERWAIT:		case POWERFAILNOW:		case POWEROKWAIT:		case CTRLALTDEL:			if (!(ch->flags & XECUTED)) ch->flags |= WAITING;		case KBREQUEST:		case BOOT:		case POWERFAIL:		case ONCE:			if (ch->flags & XECUTED) break;		case ONDEMAND:		case RESPAWN:  			ch->flags |= RUNNING;  			if (spawn(ch, &(ch->pid)) < 0) break;			/*			 *	Do NOT log if process field starts with '+'			 *	FIXME: that's for compatibility with *very*			 *	old getties - probably it can be taken out.			 */  			if (ch->process[0] != '+')				write_utmp_wtmp("", ch->id, ch->pid,					INIT_PROCESS, "");  			break;	}}/* *	Read the inittab file. */void read_inittab(void){  FILE		*fp;			/* The INITTAB file */  CHILD		*ch, *old, *i;		/* Pointers to CHILD structure */  CHILD		*head = NULL;		/* Head of linked list */#ifdef INITLVL  struct stat	st;			/* To stat INITLVL */#endif  sigset_t	nmask, omask;		/* For blocking SIGCHLD. */  char		buf[256];		/* Line buffer */  char		err[64];		/* Error message. */  char		*id, *rlevel,		*action, *process;	/* Fields of a line */  char		*p;  int		lineNo = 0;		/* Line number in INITTAB file */  int		actionNo;		/* Decoded action field */  int		f;			/* Counter */  int		round;			/* round 0 for SIGTERM, 1 for SIGKILL */  int		foundOne = 0;		/* No killing no sleep */  int		talk;			/* Talk to the user */  int		done = 0;		/* Ready yet? */#if DEBUG  if (newFamily != NULL) {	INITDBG(L_VB, "PANIC newFamily != NULL");	exit(1);  }  INITDBG(L_VB, "Reading inittab");#endif  /*   *	Open INITTAB and real line by line.   */  if ((fp = fopen(INITTAB, "r")) == NULL)	initlog(L_VB, "No inittab file found");  while(!done) {	/*	 *	Add single user shell entry at the end.	 */	if (fp == NULL || fgets(buf, sizeof(buf), fp) == NULL) {		done = 1;		/*		 *	See if we have a single user entry.		 */		for(old = newFamily; old; old = old->next)			if (strpbrk(old->rlevel, "S")) break;		if (old == NULL)			snprintf(buf, sizeof(buf), "~~:S:wait:%s\n", SULOGIN);		else			continue;	}	lineNo++;	/*	 *	Skip comments and empty lines	 */	for(p = buf; *p == ' ' || *p == '\t'; p++)		;	if (*p == '#' || *p == '\n') continue;	/*	 *	Decode the fields	 */	id =      strsep(&p, ":");	rlevel =  strsep(&p, ":");	action =  strsep(&p, ":");	process = strsep(&p, "\n");	/*	 *	Check if syntax is OK. Be very verbose here, to	 *	avoid newbie postings on comp.os.linux.setup :)	 */	err[0] = 0;	if (!id || !*id) strcpy(err, "missing id field");	if (!rlevel)     strcpy(err, "missing runlevel field");	if (!process)    strcpy(err, "missing process field");	if (!action || !*action)			strcpy(err, "missing action field");	if (id && strlen(id) > sizeof(utproto.ut_id))		sprintf(err, "id field too long (max %d characters)",			(int)sizeof(utproto.ut_id));	if (rlevel && strlen(rlevel) > 11)		strcpy(err, "rlevel field too long (max 11 characters)");	if (process && strlen(process) > 127)		strcpy(err, "process field too long");	if (action && strlen(action) > 32)		strcpy(err, "action field too long");	if (err[0] != 0) {		initlog(L_VB, "%s[%d]: %s", INITTAB, lineNo, err);		INITDBG(L_VB, "%s:%s:%s:%s", id, rlevel, action, process);		continue;	}  	/*	 *	Decode the "action" field	 */	actionNo = -1;	for(f = 0; actions[f].name; f++)		if (strcasecmp(action, actions[f].name) == 0) {			actionNo = actions[f].act;			break;		}	if (actionNo == -1) {		initlog(L_VB, "%s[%d]: %s: unknown action field",			INITTAB, lineNo, action);		continue;	}	/*	 *	See if the id field is unique	 */	for(old = newFamily; old; old = old->next) {		if(strcmp(old->id, id) == 0 && strcmp(id, "~~")) {			initlog(L_VB, "%s[%d]: duplicate ID field \"%s\"",				INITTAB, lineNo, id);			break;		}	}	if (old) continue;	/*	 *	Allocate a CHILD structure	 */	ch = imalloc(sizeof(CHILD));	/*	 *	And fill it in.	 */	ch->action = actionNo;	strncpy(ch->id, id, sizeof(utproto.ut_id) + 1); /* Hack for different libs. */	strncpy(ch->process, process, sizeof(ch->process) - 1);	if (rlevel[0]) {		for(f = 0; f < sizeof(rlevel) - 1 && rlevel[f]; f++) {			ch->rlevel[f] = rlevel[f];			if (ch->rlevel[f] == 's') ch->rlevel[f] = 'S';		}		strncpy(ch->rlevel, rlevel, sizeof(ch->rlevel) - 1);	} else {		strcpy(ch->rlevel, "0123456789");		if (ISPOWER(ch->action))			strcpy(ch->rlevel, "S0123456789");	}	/*	 *	We have the fake runlevel '#' for SYSINIT  and	 *	'*' for BOOT and BOOTWAIT.	 */	if (ch->action == SYSINIT) strcpy(ch->rlevel, "#");	if (ch->action == BOOT || ch->action == BOOTWAIT)		strcpy(ch->rlevel, "*");	/*	 *	Now add it to the linked list. Special for powerfail.	 */	if (ISPOWER(ch->action)) {		/*		 *	Disable by default		 */		ch->flags |= XECUTED;		/*		 *	Tricky: insert at the front of the list..		 */		old = NULL;		for(i = newFamily; i; i = i->next) {			if (!ISPOWER(i->action)) break;			old = i;		}		/*		 *	Now add after entry "old"		 */		if (old) {			ch->next = i;			old->next = ch;			if (i == NULL) head = ch;		} else {			ch->next = newFamily;			newFamily = ch;			if (ch->next == NULL) head = ch;		}	} else {		/*		 *	Just add at end of the list		 */		if (ch->action == KBREQUEST) ch->flags |= XECUTED;		ch->next = NULL;		if (head)			head->next = ch;		else			newFamily = ch;		head = ch;	}	/*	 *	Walk through the old list comparing id fields	 */	for(old = family; old; old = old->next)		if (strcmp(old->id, ch->id) == 0) {			old->new = ch;			break;		}  }  /*   *	We're done.   */  if (fp) fclose(fp);  /*   *	Loop through the list of children, and see if they need to   *	be killed.    */  INITDBG(L_VB, "Checking for children to kill");  for(round = 0; round < 2; round++) {    talk = 1;    for(ch = family; ch; ch = ch->next) {	ch->flags &= ~KILLME;	/*	 *	Is this line deleted?	 */	if (ch->new == NULL) ch->flags |= KILLME;	/*	 *	If the entry has changed, kill it anyway. Note that	 *	we do not check ch->process, only the "action" field.	 *	This way, you can turn an entry "off" immediately, but	 *	changes in the command line will only become effective	 *	after the running version has exited.	 */	if (ch->new && ch->action != ch->new->action) ch->flags |= KILLME;

⌨️ 快捷键说明

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