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

📄 init.c

📁 手机嵌入式Linux下可用的busybox源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* vi: set sw=4 ts=4: *//* * Mini init implementation for busybox * * * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>. * Copyright (C) 1999-2002 Erik Andersen <andersee@debian.org> * Adjusted by so many folks, it's impossible to keep track. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *//* Turn this on to disable all the dangerous    rebooting stuff when debugging.#define DEBUG_INIT*/#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <paths.h>#include <signal.h>#include <stdarg.h>#include <string.h>#include <termios.h>#include <unistd.h>#include <limits.h>#include <sys/fcntl.h>#include <sys/ioctl.h>#include <sys/mount.h>#include <sys/types.h>#include <sys/wait.h>#include "busybox.h"#ifdef BB_SYSLOGD# include <sys/syslog.h>#endif#define INIT_BUFFS_SIZE 256/* From <linux/vt.h> */struct vt_stat {	unsigned short v_active;        /* active vt */	unsigned short v_signal;        /* signal to send */	unsigned short v_state;         /* vt bitmask */};static const int VT_GETSTATE = 0x5603;  /* get global vt state info *//* From <linux/serial.h> */struct serial_struct {	int     type;	int     line;	int     port;	int     irq;	int     flags;	int     xmit_fifo_size;	int     custom_divisor;	int     baud_base;	unsigned short  close_delay;	char    reserved_char[2];	int     hub6;	unsigned short  closing_wait; /* time to wait before closing */	unsigned short  closing_wait2; /* no longer used... */	int     reserved[4];};#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__)   #include <sys/reboot.h>  #define init_reboot(magic) reboot(magic)#else  #define init_reboot(magic) reboot(0xfee1dead, 672274793, magic)#endif#ifndef _PATH_STDPATH#define _PATH_STDPATH	"/usr/bin:/bin:/usr/sbin:/sbin"#endif#if defined BB_FEATURE_INIT_COREDUMPS/* * When a file named CORE_ENABLE_FLAG_FILE exists, setrlimit is called  * before processes are spawned to set core file size as unlimited. * This is for debugging only.  Don't use this is production, unless * you want core dumps lying about.... */#define CORE_ENABLE_FLAG_FILE "/.init_enable_core"#include <sys/resource.h>#include <sys/time.h>#endif#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))#if __GNU_LIBRARY__ > 5	#include <sys/kdaemon.h>#else	extern int bdflush (int func, long int data);#endif#define SHELL        "/bin/sh"	     /* Default shell */#define LOGIN_SHELL  "-" SHELL	     /* Default login shell */#define INITTAB      "/etc/inittab"  /* inittab file location */#ifndef INIT_SCRIPT#define INIT_SCRIPT  "/etc/init.d/rcS"   /* Default sysinit script. */#endif#define MAXENV	16		/* Number of env. vars *//* Allowed init action types */#define SYSINIT     0x001#define RESPAWN     0x002#define ASKFIRST    0x004#define WAIT        0x008#define ONCE        0x010#define CTRLALTDEL  0x020#define SHUTDOWN    0x040#define RESTART     0x080/* A mapping between "inittab" action name strings and action type codes. */struct init_action_type {	const char *name;	int action;};static const struct init_action_type actions[] = {	{"sysinit", SYSINIT},	{"respawn", RESPAWN},	{"askfirst", ASKFIRST},	{"wait", WAIT},	{"once", ONCE},	{"ctrlaltdel", CTRLALTDEL},	{"shutdown", SHUTDOWN},	{"restart", RESTART},	{0, 0}};/* Set up a linked list of init_actions, to be read from inittab */struct init_action {	pid_t pid;	char command[INIT_BUFFS_SIZE];	char terminal[INIT_BUFFS_SIZE];	struct init_action *next;	int action;};/* Static variables */static struct init_action *init_action_list = NULL;static int  kernelVersion  = 0;static char termType[32]   = "TERM=linux";static char console[32]    = _PATH_CONSOLE;#ifndef BB_SYSLOGDstatic char *log           = VC_5;#endifstatic sig_atomic_t got_cont = 0;static const int LOG = 0x1;static const int CONSOLE = 0x2;#if defined BB_FEATURE_EXTRA_QUIETstatic const int MAYBE_CONSOLE = 0x0;#else#define MAYBE_CONSOLE	CONSOLE#endif#ifndef RB_HALT_SYSTEMstatic const int RB_HALT_SYSTEM = 0xcdef0123;static const int RB_ENABLE_CAD = 0x89abcdef;static const int RB_DISABLE_CAD = 0;#define RB_POWER_OFF    0x4321fedcstatic const int RB_AUTOBOOT = 0x01234567;#endif/* Function prototypes */static void delete_init_action(struct init_action *a);static int waitfor(struct init_action *a);static void loop_forever(void){	while (1)		sleep (1);}/* Print a message to the specified device. * Device may be bitwise-or'd from LOG | CONSOLE */#ifdef DEBUG_INITstatic inline messageND(int device, char *fmt, ...) { }#else #define messageND message#endifstatic void message(int device, char *fmt, ...) __attribute__ ((format (printf, 2, 3)));static void message(int device, char *fmt, ...){	va_list arguments;	int fd;#ifdef BB_SYSLOGD	/* Log the message to syslogd */	if (device & LOG) {		char msg[1024];		va_start(arguments, fmt);		vsnprintf(msg, sizeof(msg), fmt, arguments);		va_end(arguments);		syslog_msg(LOG_USER, LOG_INFO, msg);	}#else	static int log_fd = -1;	/* Take full control of the log tty, and never close it.	 * It's mine, all mine!  Muhahahaha! */	if (log_fd < 0) {		if ((log_fd = device_open(log, O_RDWR|O_NDELAY)) < 0) {			log_fd = -2;			fprintf(stderr, "Bummer, can't write to log on %s!\n", log);			device = CONSOLE;		} else {			fcntl(log_fd, F_SETFD, FD_CLOEXEC);		}	}	if ((device & LOG) && (log_fd >= 0)) {		va_start(arguments, fmt);		vdprintf(log_fd, fmt, arguments);		va_end(arguments);	}#endif	if (device & CONSOLE) {		/* Always send console messages to /dev/console so people will see them. */		if (			(fd =			 device_open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) {			va_start(arguments, fmt);			vdprintf(fd, fmt, arguments);			va_end(arguments);			close(fd);		} else {			fprintf(stderr, "Bummer, can't print: ");			va_start(arguments, fmt);			vfprintf(stderr, fmt, arguments);			va_end(arguments);		}	}}/* Set terminal settings to reasonable defaults */static void set_term(int fd){	struct termios tty;	tcgetattr(fd, &tty);	/* set control chars */	tty.c_cc[VINTR]  = 3;	/* C-c */	tty.c_cc[VQUIT]  = 28;	/* C-\ */	tty.c_cc[VERASE] = 127; /* C-? */	tty.c_cc[VKILL]  = 21;	/* C-u */	tty.c_cc[VEOF]   = 4;	/* C-d */	tty.c_cc[VSTART] = 17;	/* C-q */	tty.c_cc[VSTOP]  = 19;	/* C-s */	tty.c_cc[VSUSP]  = 26;	/* C-z */	/* use line dicipline 0 */	tty.c_line = 0;	/* Make it be sane */	tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;	tty.c_cflag |= CREAD|HUPCL|CLOCAL;	/* input modes */	tty.c_iflag = ICRNL | IXON | IXOFF;	/* output modes */	tty.c_oflag = OPOST | ONLCR;	/* local modes */	tty.c_lflag =		ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;	tcsetattr(fd, TCSANOW, &tty);}/* How much memory does this machine have?   Units are kBytes to avoid overflow on 4GB machines */static int check_free_memory(void){	struct sysinfo info;	unsigned int result, u, s=10;	if (sysinfo(&info) != 0) {		perror_msg("Error checking free memory");		return -1;	}	/* Kernels 2.0.x and 2.2.x return info.mem_unit==0 with values in bytes.	 * Kernels 2.4.0 return info.mem_unit in bytes. */	u = info.mem_unit;	if (u==0) u=1;	while ( (u&1) == 0 && s > 0 ) { u>>=1; s--; }	result = (info.totalram>>s) + (info.totalswap>>s);	result = result*u;	if (result < 0) result = INT_MAX;	return result;}static void console_init(void){	int fd;	int tried_devcons = 0;	int tried_vtprimary = 0;	struct vt_stat vt;	struct serial_struct sr;	char *s;	if ((s = getenv("TERM")) != NULL) {		snprintf(termType, sizeof(termType) - 1, "TERM=%s", s);	}	if ((s = getenv("CONSOLE")) != NULL) {		safe_strncpy(console, s, sizeof(console));	}#if #cpu(sparc)	/* sparc kernel supports console=tty[ab] parameter which is also 	 * passed to init, so catch it here */	else if ((s = getenv("console")) != NULL) {		/* remap tty[ab] to /dev/ttyS[01] */		if (strcmp(s, "ttya") == 0)			safe_strncpy(console, SC_0, sizeof(console));		else if (strcmp(s, "ttyb") == 0)			safe_strncpy(console, SC_1, sizeof(console));	}#endif	else {		/* 2.2 kernels: identify the real console backend and try to use it */		if (ioctl(0, TIOCGSERIAL, &sr) == 0) {			/* this is a serial console */			snprintf(console, sizeof(console) - 1, SC_FORMAT, sr.line);		} else if (ioctl(0, VT_GETSTATE, &vt) == 0) {			/* this is linux virtual tty */			snprintf(console, sizeof(console) - 1, VC_FORMAT, vt.v_active);		} else {			safe_strncpy(console, _PATH_CONSOLE, sizeof(console));			tried_devcons++;		}	}	while ((fd = open(console, O_RDONLY | O_NONBLOCK)) < 0) {		/* Can't open selected console -- try /dev/console */		if (!tried_devcons) {			tried_devcons++;			safe_strncpy(console, _PATH_CONSOLE, sizeof(console));			continue;		}		/* Can't open selected console -- try vt1 */		if (!tried_vtprimary) {			tried_vtprimary++;			safe_strncpy(console, VC_1, sizeof(console));			continue;		}		break;	}	if (fd < 0) {		/* Perhaps we should panic here? */		safe_strncpy(console, "/dev/null", sizeof(console));	} else {		/* check for serial console */		if (ioctl(0, TIOCGSERIAL, &sr) == 0) {			/* Force the TERM setting to vt102 for serial console --			 * if TERM is set to linux (the default) */			if (strcmp( termType, "TERM=linux" ) == 0)				safe_strncpy(termType, "TERM=vt102", sizeof(termType));		}		close(fd);	}	message(LOG, "console=%s\n", console);}	static void fixup_argv(int argc, char **argv, char *new_argv0){	int len;	/* Fix up argv[0] to be certain we claim to be init */	len = strlen(argv[0]);	memset(argv[0], 0, len);	safe_strncpy(argv[0], new_argv0, len + 1);	/* Wipe argv[1]-argv[N] so they don't clutter the ps listing */	len = 1;	while (argc > len) {		memset(argv[len], 0, strlen(argv[len]));		len++;	}}/* Make sure there is enough memory to do something useful. * * Calls "swapon -a" if needed so be sure /etc/fstab is present... */static void check_memory(void){#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__)	struct stat statBuf;#endif	if (check_free_memory() > 1000)		return;#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__)	if (stat("/etc/fstab", &statBuf) == 0) {		/* swapon -a requires /proc typically */		system("/bin/mount -t proc proc /proc");		/* Try to turn on swap */		system("/sbin/swapon -a");		if (check_free_memory() < 1000)			goto goodnight;	} else		goto goodnight;	return;  goodnight:#endif	message(CONSOLE,			"\rSorry, your computer does not have enough memory.\n");	loop_forever();}static pid_t run(struct init_action *a){	struct stat sb;	int i, j, junk;	pid_t pid, pgrp, tmp_pid;	char *s, *tmpCmd, *cmd[INIT_BUFFS_SIZE], *cmdpath;	char buf[INIT_BUFFS_SIZE+6];    /* INIT_BUFFS_SIZE+strlen("exec ")+1 */	sigset_t nmask, omask;	char *environment[MAXENV+1] = {		termType,		"HOME=/",		"PATH=" _PATH_STDPATH,		"SHELL=" SHELL,		"USER=root",		NULL	};	static const char press_enter[] =#ifdef CUSTOMIZED_BANNER#include CUSTOMIZED_BANNER#endif		"\nPlease press Enter to activate this console. ";#if __GNUC__	/* Avoid longjmp clobbering */	(void) &tmp_pid;#endif	/* inherit environment to the child, merging our values -andy */	for (i=0; environ[i]; i++) {		for (j=0; environment[j]; j++) {			s = strchr(environment[j], '=');			if (!strncmp(environ[i], environment[j], s - environment[j]))				break;		}		if (!environment[j]) {			environment[j++] = environ[i];			environment[j] = NULL;		}	}	/* Block sigchild while forking.  */	sigemptyset(&nmask);	sigaddset(&nmask, SIGCHLD);	sigprocmask(SIG_BLOCK, &nmask, &omask);	if ((pid = fork()) == 0) 	{		/* Clean up */		close(0);		close(1);		close(2);		sigprocmask(SIG_SETMASK, &omask, NULL);		/* Reset signal handlers that were set by the parent process */		signal(SIGUSR1, SIG_DFL);		signal(SIGUSR2, SIG_DFL);		signal(SIGINT,  SIG_DFL);		signal(SIGTERM, SIG_DFL);		signal(SIGHUP,  SIG_DFL);		signal(SIGCONT, SIG_DFL);		signal(SIGSTOP, SIG_DFL);		signal(SIGTSTP, SIG_DFL);		/* Create a new session and make ourself the process		 * group leader */		setsid();		/* Open the new terminal device */		if ((device_open(a->terminal, O_RDWR)) < 0) {			if (stat(a->terminal, &sb) != 0) {				message(LOG | CONSOLE, "\rdevice '%s' does not exist.\n",						a->terminal);				_exit(1);			}			message(LOG | CONSOLE, "\rBummer, can't open %s\n", a->terminal);			_exit(1);		}		/* Make sure the terminal will act fairly normal for us */		set_term(0);		/* Setup stdout, stderr for the new process so		 * they point to the supplied terminal */		dup(0);		dup(0);		/* If the init Action requires us to wait, then force the		 * supplied terminal to be the controlling tty. */		if (a->action & (SYSINIT|WAIT|CTRLALTDEL|SHUTDOWN|RESTART)) {			/* Now fork off another process to just hang around */			if ((pid = fork()) < 0) {				message(LOG | CONSOLE, "Can't fork!\n");				_exit(1);			}			if (pid > 0) {				/* We are the parent -- wait till the child is done */				signal(SIGINT, SIG_IGN);				signal(SIGTSTP, SIG_IGN);				signal(SIGQUIT, SIG_IGN);				signal(SIGCHLD, SIG_DFL);				/* Wait for child to exit */				while ((tmp_pid = waitpid(pid, &junk, 0)) != pid)					;				/* See if stealing the controlling tty back is necessary */				pgrp = tcgetpgrp(0);				if (pgrp != getpid())					_exit(0);				/* Use a temporary process to steal the controlling tty. */				if ((pid = fork()) < 0) {					message(LOG | CONSOLE, "\rCan't fork!\n");					_exit(1);				}       				if (pid == 0) {					setsid();					ioctl(0, TIOCSCTTY, 1);					_exit(0);				}       				while((tmp_pid = waitpid(pid, &junk, 0)) != pid) {					if (tmp_pid < 0 && errno == ECHILD)						break;				}				_exit(0);			}			/* Now fall though to actually execute things */		}		/* See if any special /bin/sh requiring characters are present */		if (strpbrk(a->command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) {			cmd[0] = SHELL;			cmd[1] = "-c";			strcat(strcpy(buf, "exec "), a->command);			cmd[2] = buf;			cmd[3] = NULL;		} else {			/* Convert command (char*) into cmd (char**, one word per string) */			strcpy(buf, a->command);			s = buf;			for (tmpCmd = buf, i = 0;					(tmpCmd = strsep(&s, " \t")) != NULL;) {				if (*tmpCmd != '\0') {					cmd[i] = tmpCmd;					i++;				}

⌨️ 快捷键说明

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