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

📄 init.c

📁 sysvinit--linux系统下的init
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Init		A System-V Init Clone. * * Usage:	/sbin/init *		     init [0123456SsQqAaBbCc] *		  telinit [0123456SsQqAaBbCc] * * Version:	@(#)init.c  2.86  30-Jul-2004  miquels@cistron.nl */#define VERSION "2.86"#define DATE    "31-Jul-2004"/* *		This file is part of the sysvinit suite, *		Copyright 1991-2004 Miquel van Smoorenburg. * *		This program is free software; you can redistribute it and/or *		modify it under the terms of the GNU General Public License *		as published by the Free Software Foundation; either version *		2 of the License, or (at your option) any later version. * */#include <sys/types.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <sys/wait.h>#ifdef __linux__#include <sys/kd.h>#endif#include <sys/resource.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <stdio.h>#include <time.h>#include <fcntl.h>#include <string.h>#include <signal.h>#include <termios.h>#include <utmp.h>#include <ctype.h>#include <stdarg.h>#include <sys/syslog.h>#include <sys/time.h>#ifdef __i386__#  if (__GLIBC__ >= 2)     /* GNU libc 2.x */#    define STACK_DEBUG 1#    if (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)       /* Only glibc 2.0 needs this */#      include <sigcontext.h>#    endif#  endif#endif#include "init.h"#include "initreq.h"#include "paths.h"#include "reboot.h"#include "set.h"#ifndef SIGPWR#  define SIGPWR SIGUSR2#endif#ifndef CBAUD#  define CBAUD		0#endif#ifndef CBAUDEX#  define CBAUDEX	0#endif/* Set a signal handler. */#define SETSIG(sa, sig, fun, flags) \		do { \			sa.sa_handler = fun; \			sa.sa_flags = flags; \			sigemptyset(&sa.sa_mask); \			sigaction(sig, &sa, NULL); \		} while(0)/* Version information */char *Version = "@(#) init " VERSION "  " DATE "  miquels@cistron.nl";char *bootmsg = "version " VERSION " %s";#define E_VERSION "INIT_VERSION=sysvinit-" VERSIONCHILD *family = NULL;		/* The linked list of all entries */CHILD *newFamily = NULL;	/* The list after inittab re-read */CHILD ch_emerg = {		/* Emergency shell */	0, 0, 0, 0, 0,	"~~",	"S",	3,	"/sbin/sulogin",	NULL,	NULL};char runlevel = 'S';		/* The current run level */char thislevel = 'S';		/* The current runlevel */char prevlevel = 'N';		/* Previous runlevel */int dfl_level = 0;		/* Default runlevel */sig_atomic_t got_cont = 0;	/* Set if we received the SIGCONT signal */sig_atomic_t got_signals;	/* Set if we received a signal. */int emerg_shell = 0;		/* Start emergency shell? */int wrote_wtmp_reboot = 1;	/* Set when we wrote the reboot record */int wrote_utmp_reboot = 1;	/* Set when we wrote the reboot record */int sltime = 5;			/* Sleep time between TERM and KILL */char *argv0;			/* First arguments; show up in ps listing */int maxproclen;			/* Maximal length of argv[0] with \0 */struct utmp utproto;		/* Only used for sizeof(utproto.ut_id) */char *user_console = NULL;	/* User console device */char *console_dev;		/* Console device. */int pipe_fd = -1;		/* /dev/initctl */int did_boot = 0;		/* Did we already do BOOT* stuff? */int main(int, char **);/*	Used by re-exec part */int reload = 0;			/* Should we do initialization stuff? */char *myname="/sbin/init";	/* What should we exec */int oops_error;			/* Used by some of the re-exec code. */const char *Signature = "12567362";	/* Signature for re-exec fd *//* Macro to see if this is a special action */#define ISPOWER(i) ((i) == POWERWAIT || (i) == POWERFAIL || \		    (i) == POWEROKWAIT || (i) == POWERFAILNOW || \		    (i) == CTRLALTDEL)/* ascii values for the `action' field. */struct actions {  char *name;  int act;} actions[] = {  { "respawn", 	   RESPAWN	},  { "wait",	   WAIT		},  { "once",	   ONCE		},  { "boot",	   BOOT		},  { "bootwait",	   BOOTWAIT	},  { "powerfail",   POWERFAIL	},  { "powerfailnow",POWERFAILNOW },  { "powerwait",   POWERWAIT	},  { "powerokwait", POWEROKWAIT	},  { "ctrlaltdel",  CTRLALTDEL	},  { "off",	   OFF		},  { "ondemand",	   ONDEMAND	},  { "initdefault", INITDEFAULT	},  { "sysinit",	   SYSINIT	},  { "kbrequest",   KBREQUEST    },  { NULL,	   0		},};/* *	State parser token table (see receive_state) */struct {  char name[4];	  int cmd;} cmds[] = {  { "VER", 	   C_VER	},  { "END",	   C_END	},  { "REC",	   C_REC	},  { "EOR",	   C_EOR	},  { "LEV",	   C_LEV	},  { "FL ",	   C_FLAG	},  { "AC ",	   C_ACTION	},  { "CMD",	   C_PROCESS	},  { "PID",	   C_PID	},  { "EXS",	   C_EXS	},  { "-RL",	   D_RUNLEVEL	},  { "-TL",	   D_THISLEVEL	},  { "-PL",	   D_PREVLEVEL	},  { "-SI",	   D_GOTSIGN	},  { "-WR",	   D_WROTE_WTMP_REBOOT},  { "-WU",	   D_WROTE_UTMP_REBOOT},  { "-ST",	   D_SLTIME	},  { "-DB",	   D_DIDBOOT	},  { "",	   	   0		}};struct {	char *name;	int mask;} flags[]={	{"RU",RUNNING},	{"DE",DEMAND},	{"XD",XECUTED},	{NULL,0}};#define NR_EXTRA_ENV	16char *extra_env[NR_EXTRA_ENV];/* *	Sleep a number of seconds. * *	This only works correctly because the linux select updates *	the elapsed time in the struct timeval passed to select! */void do_sleep(int sec){	struct timeval tv;	tv.tv_sec = sec;	tv.tv_usec = 0;	while(select(0, NULL, NULL, NULL, &tv) < 0 && errno == EINTR)		;}/* *	Non-failing allocation routines (init cannot fail). */void *imalloc(size_t size){	void	*m;	while ((m = malloc(size)) == NULL) {		initlog(L_VB, "out of memory");		do_sleep(5);	}	memset(m, 0, size);	return m;}char *istrdup(char *s){	char	*m;	int	l;	l = strlen(s) + 1;	m = imalloc(l);	memcpy(m, s, l);	return m;}/* *	Send the state info of the previous running init to *	the new one, in a version-independant way. */void send_state(int fd){	FILE	*fp;	CHILD	*p;	int	i,val;	fp = fdopen(fd,"w");	fprintf(fp, "VER%s\n", Version);	fprintf(fp, "-RL%c\n", runlevel);	fprintf(fp, "-TL%c\n", thislevel);	fprintf(fp, "-PL%c\n", prevlevel);	fprintf(fp, "-SI%u\n", got_signals);	fprintf(fp, "-WR%d\n", wrote_wtmp_reboot);	fprintf(fp, "-WU%d\n", wrote_utmp_reboot);	fprintf(fp, "-ST%d\n", sltime);	fprintf(fp, "-DB%d\n", did_boot);	for (p = family; p; p = p->next) {		fprintf(fp, "REC%s\n", p->id);		fprintf(fp, "LEV%s\n", p->rlevel);		for (i = 0, val = p->flags; flags[i].mask; i++)			if (val & flags[i].mask) {				val &= ~flags[i].mask;				fprintf(fp, "FL %s\n",flags[i].name);			}		fprintf(fp, "PID%d\n",p->pid);		fprintf(fp, "EXS%u\n",p->exstat);		for(i = 0; actions[i].act; i++)			if (actions[i].act == p->action) {				fprintf(fp, "AC %s\n", actions[i].name);				break;			}		fprintf(fp, "CMD%s\n", p->process);		fprintf(fp, "EOR\n");	}	fprintf(fp, "END\n");	fclose(fp);}/* *	Read a string from a file descriptor. *	FIXME: why not use fgets() ? */static int get_string(char *p, int size, FILE *f){	int	c;	while ((c = getc(f)) != EOF && c != '\n') {		if (--size > 0)			*p++ = c;	}	*p = '\0';	return (c != EOF) && (size > 0);}/* *	Read trailing data from the state pipe until we see a newline. */static int get_void(FILE *f){	int	c;	while ((c = getc(f)) != EOF && c != '\n')		;	return (c != EOF);}/* *	Read the next "command" from the state pipe. */static int get_cmd(FILE *f){	char	cmd[4] = "   ";	int	i;	if (fread(cmd, 1, sizeof(cmd) - 1, f) != sizeof(cmd) - 1)		return C_EOF;	for(i = 0; cmds[i].cmd && strcmp(cmds[i].name, cmd) != 0; i++)		;	return cmds[i].cmd;}/* *	Read a CHILD * from the state pipe. */static CHILD *get_record(FILE *f){	int	cmd;	char	s[32];	int	i;	CHILD	*p;	do {		switch (cmd = get_cmd(f)) {			case C_END:				get_void(f);				return NULL;			case 0:				get_void(f);				break;			case C_REC:				break;			case D_RUNLEVEL:				fscanf(f, "%c\n", &runlevel);				break;			case D_THISLEVEL:				fscanf(f, "%c\n", &thislevel);				break;			case D_PREVLEVEL:				fscanf(f, "%c\n", &prevlevel);				break;			case D_GOTSIGN:				fscanf(f, "%u\n", &got_signals);				break;			case D_WROTE_WTMP_REBOOT:				fscanf(f, "%d\n", &wrote_wtmp_reboot);				break;			case D_WROTE_UTMP_REBOOT:				fscanf(f, "%d\n", &wrote_utmp_reboot);				break;			case D_SLTIME:				fscanf(f, "%d\n", &sltime);				break;			case D_DIDBOOT:				fscanf(f, "%d\n", &did_boot);				break;			default:				if (cmd > 0 || cmd == C_EOF) {					oops_error = -1;					return NULL;				}		}	} while (cmd != C_REC);	p = imalloc(sizeof(CHILD));	get_string(p->id, sizeof(p->id), f);	do switch(cmd = get_cmd(f)) {		case 0:		case C_EOR:			get_void(f);			break;		case C_PID:			fscanf(f, "%d\n", &(p->pid));			break;		case C_EXS:			fscanf(f, "%u\n", &(p->exstat));			break;		case C_LEV:			get_string(p->rlevel, sizeof(p->rlevel), f);			break;		case C_PROCESS:			get_string(p->process, sizeof(p->process), f);			break;		case C_FLAG:			get_string(s, sizeof(s), f);			for(i = 0; flags[i].name; i++) {				if (strcmp(flags[i].name,s) == 0)					break;			}			p->flags |= flags[i].mask;			break;		case C_ACTION:			get_string(s, sizeof(s), f);			for(i = 0; actions[i].name; i++) {				if (strcmp(actions[i].name, s) == 0)					break;			}			p->action = actions[i].act ? actions[i].act : OFF;			break;		default:			free(p);			oops_error = -1;			return NULL;	} while( cmd != C_EOR);	return p;}/* *	Read the complete state info from the state pipe. *	Returns 0 on success */int receive_state(int fd){	FILE	*f;	char	old_version[256];	CHILD	**pp;	f = fdopen(fd, "r"); 	if (get_cmd(f) != C_VER)		return -1;	get_string(old_version, sizeof(old_version), f);	oops_error = 0;	for (pp = &family; (*pp = get_record(f)) != NULL; pp = &((*pp)->next))		;	fclose(f);	return oops_error;}/* *	Set the process title. */#ifdef __GNUC____attribute__ ((format (printf, 1, 2)))#endifstatic int setproctitle(char *fmt, ...){	va_list ap;	int len;	char buf[256];	buf[0] = 0;	va_start(ap, fmt);	len = vsnprintf(buf, sizeof(buf), fmt, ap);	va_end(ap);	if (maxproclen > 2) {		memset(argv0, 0, maxproclen);		strncpy(argv0, buf, maxproclen - 2);	}	return len;}/* *	Set console_dev to a working console. */void console_init(void){	int fd;	int tried_devcons = 0;	int tried_vtmaster = 0;	char *s;	if (user_console) {		console_dev = user_console;	} else if ((s = getenv("CONSOLE")) != NULL)		console_dev = s;	else {		console_dev = CONSOLE;		tried_devcons++;	}	while ((fd = open(console_dev, O_RDONLY|O_NONBLOCK)) < 0) {		if (!tried_devcons) {			tried_devcons++;			console_dev = CONSOLE;			continue;		}		if (!tried_vtmaster) {			tried_vtmaster++;			console_dev = VT_MASTER;			continue;		}		break;	}	if (fd < 0)		console_dev = "/dev/null";	else		close(fd);}/* *	Open the console with retries. */int console_open(int mode){	int f, fd = -1;	int m;	/*	 *	Open device in nonblocking mode.	 */	m = mode | O_NONBLOCK;	/*	 *	Retry the open five times.	 */	for(f = 0; f < 5; f++)		if ((fd = open(console_dev, m)) >= 0) break;	if (fd < 0) return fd;	/*	 *	Set original flags.	 */	if (m != mode)  		fcntl(fd, F_SETFL, mode);	return fd;}/* *	We got a signal (HUP PWR WINCH ALRM INT) */void signal_handler(int sig){	ADDSET(got_signals, sig);}/* *	SIGCHLD: one of our children has died. */void chld_handler(){	CHILD		*ch;	int		pid, st;	int		saved_errno = errno;	/*	 *	Find out which process(es) this was (were)	 */	while((pid = waitpid(-1, &st, WNOHANG)) != 0) {		if (errno == ECHILD) break;		for( ch = family; ch; ch = ch->next )			if ( ch->pid == pid && (ch->flags & RUNNING) ) {				INITDBG(L_VB,					"chld_handler: marked %d as zombie",					ch->pid);				ADDSET(got_signals, SIGCHLD);				ch->exstat = st;				ch->flags |= ZOMBIE;				if (ch->new) {					ch->new->exstat = st;					ch->new->flags |= ZOMBIE;				}				break;			}		if (ch == NULL)			INITDBG(L_VB, "chld_handler: unknown child %d exited.",				pid);	}	errno = saved_errno;}/* *	Linux ignores all signals sent to init when the *	SIG_DFL handler is installed. Therefore we must catch SIGTSTP *	and SIGCONT, or else they won't work.... * *	The SIGCONT handler */void cont_handler(){	got_cont = 1;}/* *	Fork and dump core in /. */void coredump(void){	static int		dumped = 0;	struct rlimit		rlim;	sigset_t		mask;	if (dumped) return;	dumped = 1;	if (fork() != 0) return;	sigfillset(&mask);	sigprocmask(SIG_SETMASK, &mask, NULL);	rlim.rlim_cur = RLIM_INFINITY;	rlim.rlim_max = RLIM_INFINITY;	setrlimit(RLIMIT_CORE, &rlim);	chdir("/");	signal(SIGSEGV, SIG_DFL);	raise(SIGSEGV);	sigdelset(&mask, SIGSEGV);	sigprocmask(SIG_SETMASK, &mask, NULL);	do_sleep(5);	exit(0);}/* *	OOPS: segmentation violation! *	If we have the info, print where it occured. *	Then sleep 30 seconds and try to continue. */#if defined(STACK_DEBUG) && defined(__linux__)void segv_handler(int sig, struct sigcontext ctx){	char	*p = "";	int	saved_errno = errno;	if ((void *)ctx.eip >= (void *)do_sleep &&	    (void *)ctx.eip < (void *)main)		p = " (code)";	initlog(L_VB, "PANIC: segmentation violation at %p%s! "		  "sleeping for 30 seconds.", (void *)ctx.eip, p);	coredump();	do_sleep(30);	errno = saved_errno;}#elsevoid segv_handler(){	int	saved_errno = errno;	initlog(L_VB,		"PANIC: segmentation violation! sleeping for 30 seconds.");	coredump();	do_sleep(30);	errno = saved_errno;}#endif/* *	The SIGSTOP & SIGTSTP handler */void stop_handler(){	int	saved_errno = errno;	got_cont = 0;

⌨️ 快捷键说明

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