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

📄 init.c

📁 sysvinit--linux系统下的init
💻 C
📖 第 1 页 / 共 4 页
字号:
  int			quit = 0;  /*   *	First, try to create /dev/initctl if not present.   */  if (stat(INIT_FIFO, &st2) < 0 && errno == ENOENT)	(void)mkfifo(INIT_FIFO, 0600);  /*   *	If /dev/initctl is open, stat the file to see if it   *	is still the _same_ inode.   */  if (pipe_fd >= 0) {	fstat(pipe_fd, &st);	if (stat(INIT_FIFO, &st2) < 0 ||	    st.st_dev != st2.st_dev ||	    st.st_ino != st2.st_ino) {		close(pipe_fd);		pipe_fd = -1;	}  }  /*   *	Now finally try to open /dev/initctl   */  if (pipe_fd < 0) {	if ((pipe_fd = open(INIT_FIFO, O_RDWR|O_NONBLOCK)) >= 0) {		fstat(pipe_fd, &st);		if (!S_ISFIFO(st.st_mode)) {			initlog(L_VB, "%s is not a fifo", INIT_FIFO);			close(pipe_fd);			pipe_fd = -1;		}	}	if (pipe_fd >= 0) {		/*		 *	Don't use fd's 0, 1 or 2.		 */		(void) dup2(pipe_fd, PIPE_FD);		close(pipe_fd);		pipe_fd = PIPE_FD;		/*		 *	Return to caller - we'll be back later.		 */	}  }  /* Wait for data to appear, _if_ the pipe was opened. */  if (pipe_fd >= 0) while(!quit) {	/* Do select, return on EINTR. */	FD_ZERO(&fds);	FD_SET(pipe_fd, &fds);	tv.tv_sec = 5;	tv.tv_usec = 0;	n = select(pipe_fd + 1, &fds, NULL, NULL, &tv);	if (n <= 0) {		if (n == 0 || errno == EINTR) return;		continue;	}	/* Read the data, return on EINTR. */	n = read(pipe_fd, &request, sizeof(request));	if (n == 0) {		/*		 *	End of file. This can't happen under Linux (because		 *	the pipe is opened O_RDWR - see select() in the		 *	kernel) but you never know...		 */		close(pipe_fd);		pipe_fd = -1;		return;	}	if (n <= 0) {		if (errno == EINTR) return;		initlog(L_VB, "error reading initrequest");		continue;	}	/*	 *	This is a convenient point to also try to	 *	find the console device or check if it changed.	 */	console_init();	/*	 *	Process request.	 */	if (request.magic != INIT_MAGIC || n != sizeof(request)) {		initlog(L_VB, "got bogus initrequest");		continue;	}	switch(request.cmd) {		case INIT_CMD_RUNLVL:			sltime = request.sleeptime;			fifo_new_level(request.runlevel);			quit = 1;			break;		case INIT_CMD_POWERFAIL:			sltime = request.sleeptime;			do_power_fail('F');			quit = 1;			break;		case INIT_CMD_POWERFAILNOW:			sltime = request.sleeptime;			do_power_fail('L');			quit = 1;			break;		case INIT_CMD_POWEROK:			sltime = request.sleeptime;			do_power_fail('O');			quit = 1;			break;		case INIT_CMD_SETENV:			initcmd_setenv(request.i.data, sizeof(request.i.data));			break;		case INIT_CMD_CHANGECONS:			if (user_console) {				free(user_console);				user_console = NULL;			}			if (!request.i.bsd.reserved[0])				user_console = NULL;			else				user_console = strdup(request.i.bsd.reserved);			console_init();			quit = 1;			break;		default:			initlog(L_VB, "got unimplemented initrequest.");			break;	}  }  /*   *	We come here if the pipe couldn't be opened.   */  if (pipe_fd < 0) pause();}/* *	This function is used in the transition *	sysinit (-> single user) boot -> multi-user. */void boot_transitions(){  CHILD		*ch;  static int	newlevel = 0;  static int	warn = 1;  int		loglevel;  int		oldlevel;  /* Check if there is something to wait for! */  for( ch = family; ch; ch = ch->next )	if ((ch->flags & RUNNING) && ch->action != BOOT) break;       if (ch == NULL) {	/* No processes left in this level, proceed to next level. */	loglevel = -1;	oldlevel = 'N';	switch(runlevel) {		case '#': /* SYSINIT -> BOOT */			INITDBG(L_VB, "SYSINIT -> BOOT");			/* Write a boot record. */			wrote_utmp_reboot = 0;			wrote_wtmp_reboot = 0;			write_utmp_wtmp("reboot", "~~", 0, BOOT_TIME, "~");  			/* Get our run level */  			newlevel = dfl_level ? dfl_level : get_init_default();			if (newlevel == 'S') {				runlevel = newlevel;				/* Not really 'S' but show anyway. */				setproctitle("init [S]");			} else				runlevel = '*';			break;		case '*': /* BOOT -> NORMAL */			INITDBG(L_VB, "BOOT -> NORMAL");			if (runlevel != newlevel)				loglevel = newlevel;			runlevel = newlevel;			did_boot = 1;			warn = 1;			break;		case 'S': /* Ended SU mode */		case 's':			INITDBG(L_VB, "END SU MODE");			newlevel = get_init_default();			if (!did_boot && newlevel != 'S')				runlevel = '*';			else {				if (runlevel != newlevel)					loglevel = newlevel;				runlevel = newlevel;				oldlevel = 'S';			}			warn = 1;			for(ch = family; ch; ch = ch->next)			    if (strcmp(ch->rlevel, "S") == 0)				ch->flags &= ~(FAILING|WAITING|XECUTED);			break;		default:			if (warn)			  initlog(L_VB,				"no more processes left in this runlevel");			warn = 0;			loglevel = -1;			if (got_signals == 0)				check_init_fifo();			break;	}	if (loglevel > 0) {		initlog(L_VB, "Entering runlevel: %c", runlevel);		write_utmp_wtmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~");		thislevel = runlevel;		prevlevel = oldlevel;		setproctitle("init [%c]", runlevel);	}  }}/* *	Init got hit by a signal. See which signal it is, *	and act accordingly. */void process_signals(){  CHILD		*ch;  int		pwrstat;  int		oldlevel;  int		fd;  char		c;  if (ISMEMBER(got_signals, SIGPWR)) {	INITDBG(L_VB, "got SIGPWR");	/* See _what_ kind of SIGPWR this is. */	pwrstat = 0;	if ((fd = open(PWRSTAT, O_RDONLY)) >= 0) {		c = 0;		read(fd, &c, 1);		pwrstat = c;		close(fd);		unlink(PWRSTAT);	}	do_power_fail(pwrstat);	DELSET(got_signals, SIGPWR);  }  if (ISMEMBER(got_signals, SIGINT)) {	INITDBG(L_VB, "got SIGINT");	/* Tell ctrlaltdel entry to start up */	for(ch = family; ch; ch = ch->next)		if (ch->action == CTRLALTDEL)			ch->flags &= ~XECUTED;	DELSET(got_signals, SIGINT);  }  if (ISMEMBER(got_signals, SIGWINCH)) {	INITDBG(L_VB, "got SIGWINCH");	/* Tell kbrequest entry to start up */	for(ch = family; ch; ch = ch->next)		if (ch->action == KBREQUEST)			ch->flags &= ~XECUTED;	DELSET(got_signals, SIGWINCH);  }  if (ISMEMBER(got_signals, SIGALRM)) {	INITDBG(L_VB, "got SIGALRM");	/* The timer went off: check it out */	DELSET(got_signals, SIGALRM);  }  if (ISMEMBER(got_signals, SIGCHLD)) {	INITDBG(L_VB, "got SIGCHLD");	/* First set flag to 0 */	DELSET(got_signals, SIGCHLD);	/* See which child this was */	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 (ISMEMBER(got_signals, SIGHUP)) {	INITDBG(L_VB, "got SIGHUP");#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;#ifdef INITLVL		runlevel = read_level(0);#endif		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);			DELSET(got_signals, SIGHUP);		}	}  }  if (ISMEMBER(got_signals, SIGUSR1)) {	/*	 *	SIGUSR1 means close and reopen /dev/initctl	 */	INITDBG(L_VB, "got SIGUSR1");	close(pipe_fd);	pipe_fd = -1;	DELSET(got_signals, SIGUSR1);  }}/* *	The main loop */ int init_main(){  CHILD			*ch;  struct sigaction	sa;  sigset_t		sgt;  pid_t			rc;  int			f, st;  if (!reload) {  #if INITDEBUG	/*	 * Fork so we can debug the init process.	 */	if ((f = fork()) > 0) {		static const char killmsg[] = "PRNT: init killed.\r\n";		pid_t rc;		while((rc = wait(&st)) != f)			if (rc < 0 && errno == ECHILD)				break;		write(1, killmsg, sizeof(killmsg) - 1);		while(1) pause();	}#endif#ifdef __linux__	/*	 *	Tell the kernel to send us SIGINT when CTRL-ALT-DEL	 *	is pressed, and that we want to handle keyboard signals.	 */	init_reboot(BMAGIC_SOFT);	if ((f = open(VT_MASTER, O_RDWR | O_NOCTTY)) >= 0) {		(void) ioctl(f, KDSIGACCEPT, SIGWINCH);		close(f);	} else		(void) ioctl(0, KDSIGACCEPT, SIGWINCH);#endif	/*	 *	Ignore all signals.	 */	for(f = 1; f <= NSIG; f++)		SETSIG(sa, f, SIG_IGN, SA_RESTART);  }  SETSIG(sa, SIGALRM,  signal_handler, 0);  SETSIG(sa, SIGHUP,   signal_handler, 0);  SETSIG(sa, SIGINT,   signal_handler, 0);  SETSIG(sa, SIGCHLD,  chld_handler, SA_RESTART);  SETSIG(sa, SIGPWR,   signal_handler, 0);  SETSIG(sa, SIGWINCH, signal_handler, 0);  SETSIG(sa, SIGUSR1,  signal_handler, 0);  SETSIG(sa, SIGSTOP,  stop_handler, SA_RESTART);  SETSIG(sa, SIGTSTP,  stop_handler, SA_RESTART);  SETSIG(sa, SIGCONT,  cont_handler, SA_RESTART);  SETSIG(sa, SIGSEGV,  (void (*)(int))segv_handler, SA_RESTART);  console_init();  if (!reload) {  	/* Close whatever files are open, and reset the console. */	close(0);	close(1);	close(2);  	console_stty();  	setsid();  	/*	 *	Set default PATH variable.	 */  	putenv(PATH_DFL);  	/*	 *	Initialize /var/run/utmp (only works if /var is on	 *	root and mounted rw)	 */  	(void) close(open(UTMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0644));  	/*	 *	Say hello to the world	 */  	initlog(L_CO, bootmsg, "booting");  	/*	 *	See if we have to start an emergency shell.	 */	if (emerg_shell) {		SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART);		if (spawn(&ch_emerg, &f) > 0) {			while((rc = wait(&st)) != f)				if (rc < 0 && errno == ECHILD)					break;		}  		SETSIG(sa, SIGCHLD,  chld_handler, SA_RESTART);  	}  	/*	 *	Start normal boot procedure.	 */  	runlevel = '#';  	read_inittab();    } else {	/*	 *	Restart: unblock signals and let the show go on	 */	initlog(L_CO, bootmsg, "reloading");	sigfillset(&sgt);	sigprocmask(SIG_UNBLOCK, &sgt, NULL);  }  start_if_needed();  while(1) {     /* See if we need to make the boot transitions. */     boot_transitions();     INITDBG(L_VB, "init_main: waiting..");     /* Check if there are processes to be waited on. */     for(ch = family; ch; ch = ch->next)	if ((ch->flags & RUNNING) && ch->action != BOOT) break;#if CHANGE_WAIT     /* Wait until we get hit by some signal. */     while (ch != NULL && got_signals == 0) {	if (ISMEMBER(got_signals, SIGHUP)) {		/* See if there are processes to be waited on. */		for(ch = family; ch; ch = ch->next)			if (ch->flags & WAITING) break;	}	if (ch != NULL) check_init_fifo();     }#else /* CHANGE_WAIT */     if (ch != NULL && got_signals == 0) check_init_fifo();#endif /* CHANGE_WAIT */     /* Check the 'failing' flags */     fail_check();     /* Process any signals. */     process_signals();     /* See what we need to start up (again) */     start_if_needed();  }  /*NOTREACHED*/}/* * Tell the user about the syntax we expect. */void usage(char *s){	fprintf(stderr, "Usage: %s 0123456SsQqAaBbCcUu\n", s);	exit(1);}int telinit(char *progname, int argc, char **argv){#ifdef TELINIT_USES_INITLVL	FILE			*fp;#endif	struct init_request	request;	struct sigaction	sa;	int			f, fd, l;	char			*env = NULL;	memset(&request, 0, sizeof(request));	request.magic     = INIT_MAGIC;	while ((f = getopt(argc, argv, "t:e:")) != EOF) switch(f) {		case 't':			sltime = atoi(optarg);			break;		case 'e':			if (env == NULL)				env = request.i.data;			l = strlen(optarg);			if (env + l + 2 > request.i.data + sizeof(request.i.data)) {				fprintf(stderr, "%s: -e option data "					"too large\n", progname);				exit(1);			}			memcpy(env, optarg, l);			env += l;			*env++ = 0;			break;		default:			usage(progname);			break;	}	if (env) *env++ = 0;	if (env) {		if (argc != optind)			usage(progname);		request.cmd = INIT_CMD_SETENV;	} else {		if (argc - optind != 1 || strlen(argv[optind]) != 1)			usage(progname);		if (!strchr("0123456789SsQqAaBbCcUu", argv[optind][0]))			usage(progname);		request.cmd = INIT_CMD_RUNLVL;		request.runlevel  = env ? 0 : argv[optind][0];		request.sleeptime = sltime;	}	/* Open the fifo and write a command. */	/* Make sure we don't hang on opening /dev/initctl */	SETSIG(sa, SIGALRM, signal_handler, 0);	alarm(3);	if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0 &&	    write(fd, &request, sizeof(request)) == sizeof(request)) {		close(fd);		alarm(0);		return 0;	}#ifdef TELINIT_USES_INITLVL	if (request.cmd == INIT_CMD_RUNLVL) {		/* Fallthrough to the old method. */		/* Now write the new runlevel. */		if ((fp = fopen(INITLVL, "w")) == NULL) {			fprintf(stderr, "%s: cannot create %s\n",				progname, INITLVL);			exit(1);		}		fprintf(fp, "%s %d", argv[optind], sltime);		fclose(fp);		/* And tell init about the pending runlevel change. */		if (kill(INITPID, SIGHUP) < 0) perror(progname);		return 0;	}#endif	fprintf(stderr, "%s: ", progname);	if (ISMEMBER(got_signals, SIGALRM)) {		fprintf(stderr, "timeout opening/writing control channel %s\n",			INIT_FIFO);	} else {		perror(INIT_FIFO);	}	return 1;}/* * Main entry for init and telinit. */int main(int argc, char **argv){	char			*p;	int			f;	int			isinit;	/* Get my own name */	if ((p = strrchr(argv[0], '/')) != NULL)  		p++;	else  		p = argv[0];	umask(022);	/* Quick check */	if (geteuid() != 0) {		fprintf(stderr, "%s: must be superuser.\n", p);		exit(1);	}	/*	 *	Is this telinit or init ?	 */	isinit = (getpid() == 1);	for (f = 1; f < argc; f++) {		if (!strcmp(argv[f], "-i") || !strcmp(argv[f], "--init"))			isinit = 1;			break;	}	if (!isinit) exit(telinit(p, argc, argv));	/*	 *	Check for re-exec	 */ 		if (check_pipe(STATE_PIPE)) {		receive_state(STATE_PIPE);		myname = istrdup(argv[0]);		argv0 = argv[0];		maxproclen = 0;		for (f = 0; f < argc; f++)			maxproclen += strlen(argv[f]) + 1;		reload = 1;		setproctitle("init [%c]",runlevel);		init_main();	}  	/* Check command line arguments */	maxproclen = strlen(argv[0]) + 1;  	for(f = 1; f < argc; f++) {		if (!strcmp(argv[f], "single") || !strcmp(argv[f], "-s"))			dfl_level = 'S';		else if (!strcmp(argv[f], "-a") || !strcmp(argv[f], "auto"))			putenv("AUTOBOOT=YES");		else if (!strcmp(argv[f], "-b") || !strcmp(argv[f],"emergency"))			emerg_shell = 1;		else if (!strcmp(argv[f], "-z")) {			/* Ignore -z xxx */			if (argv[f + 1]) f++;		} else if (strchr("0123456789sS", argv[f][0])			&& strlen(argv[f]) == 1)			dfl_level = argv[f][0];		/* "init u" in the very beginning makes no sense */		if (dfl_level == 's') dfl_level = 'S';		maxproclen += strlen(argv[f]) + 1;	}	/* Start booting. */	argv0 = argv[0];	argv[1] = NULL;	setproctitle("init boot");	init_main(dfl_level);	/*NOTREACHED*/	return 0;}

⌨️ 快捷键说明

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