BusyBox init及其inittab文件分析
来源:互联网 发布:oracle sql删除字段 编辑:程序博客网 时间:2024/06/07 18:21
由于BusyBox自身的一些特点,BusyBox init非常适合在嵌入式系统开发中使用,被誉为“嵌入式linux的瑞士军刀”,它可以为嵌入式系统提供只要的init功能,并且通过定制可以做得非常 精炼。inittab是帮助init完成系统配置的主要文件。
/* Line is: "id:runlevel_ignored:action:command" */
static const char actions[ ] =
STR_SYSINIT "sysinit/0"
STR_RESPAWN "respawn/0"
STR_ASKFIRST "askfirst/0"
STR_WAIT "wait/0"
STR_ONCE "once/0"
STR_CTRLALTDEL "ctrlaltdel/0"
STR_SHUTDOWN "shutdown/0"
STR_RESTART "restart/0"
;
# define STR_SYSINIT "/x01"
# define STR_RESPAWN "/x02"
# define STR_ASKFIRST "/x04"
# define STR_WAIT "/x08"
# define STR_ONCE "/x10"
# define STR_CTRLALTDEL "/x20"
# define STR_SHUTDOWN "/x40"
# define STR_RESTART "/x80"
/* Set up a linked list of init_actions, to be read from inittab */
/* inittab文件的每一行都会保存为一个init_action节点,并且所有 init_action节点会被链接成一个叫init_action_list的列表*/
struct init_action {
struct init_action * next;
pid_t pid; /* 实际执行该command的进程ID*/
uint8_t action_type; /* action的类型 */
char terminal[ CONSOLE_NAME_SIZE] ; /* 运行该command的终端 */
char command[ COMMAND_SIZE] ; /* 保存command字段(含命令行选项)*/
} ;
/* Static variables */
static struct init_action * init_action_list = NULL ;
if ( ENABLE_FEATURE_USE_INITTAB)
file = fopen ( INITTAB, "r" ) ;
else
file = NULL ;
/* No inittab file -- set up some default behavior */
if ( file = = NULL ) {
/* Reboot on Ctrl-Alt-Del */
new_init_action( CTRLALTDEL, "reboot" , "" ) ;
/* Umount all filesystems on halt/reboot */
new_init_action( SHUTDOWN , "umount -a -r" , "" ) ;
/* Swapoff on halt/reboot */
if ( ENABLE_SWAPONOFF)
new_init_action( SHUTDOWN , "swapoff -a" , "" ) ;
/* Prepare to restart init when a QUIT is received */
new_init_action( RESTART, "init" , "" ) ;
/* Askfirst shell on tty1-4 */
new_init_action( ASKFIRST, bb_default_login_shell, "" ) ;
new_init_action( ASKFIRST, bb_default_login_shell, VC_2) ;
new_init_action( ASKFIRST, bb_default_login_shell, VC_3) ;
new_init_action( ASKFIRST, bb_default_login_shell, VC_4) ;
/* sysinit */
new_init_action( SYSINIT, INIT_SCRIPT, "" ) ;
return ;
}
//循环获取inittab文件中的每一行到buf中
while ( fgets ( buf, COMMAND_SIZE, file ) ! = NULL ) {
//定义action的种类
static const char actions[ ] =
STR_SYSINIT "sysinit/0"
STR_RESPAWN "respawn/0"
STR_ASKFIRST "askfirst/0"
STR_WAIT "wait/0"
STR_ONCE "once/0"
STR_CTRLALTDEL "ctrlaltdel/0"
STR_SHUTDOWN "shutdown/0"
STR_RESTART "restart/0"
;
char tmpConsole[ CONSOLE_NAME_SIZE] ;
char * id, * runlev, * action, * command;
const char * a;
/*通过跳过空格,并截取到换行/n为止,来获取本行的有效内容,并保存于id中*/
/* Skip leading spaces */
id = skip_whitespace( buf) ;
/* Trim the trailing '/n' */
* strchrnul( id, '/n' ) = '/0' ;
//若为注释,跳出本次循环
/* Skip the line if it is a comment */
if ( * id = = '#' | | * id = = '/0' )
continue ;
/* Line is: "id:runlevel_ignored:action:command" */
//获取runlev字段
runlev = strchr ( id, ':' ) ;
if ( runlev = = NULL /*|| runlev[1] == '/0' - not needed */ )
goto bad_entry;
//获取action字段
action = strchr ( runlev + 1, ':' ) ;
if ( action = = NULL /*|| action[1] == '/0' - not needed */ )
goto bad_entry;
//获取command字段
command = strchr ( action + 1, ':' ) ;
if ( command = = NULL | | command[ 1] = = '/0' )
goto bad_entry;
/*循环遍历actions数组,查找数组中与action字段相同的元素。找到后,通过new_init_action方法,将该元素的第一个字符(即action_type编码)和id及command字段作为一init_action节点添加到init_action_list列表中。接着跳到下一行进行处理*/
* command = '/0' ; /* action => ":action/0" now */
for ( a = actions; a[ 0] ; a + = strlen ( a) + 1) {
//查到数组actions中与action字段相同的元素
if ( strcmp ( a + 1, action + 1) = = 0) {
//截取id字段,格式为"id/0"
* runlev = '/0' ;
//若id字段非空
if ( * id ! = '/0' ) {
//若id字段带前缀/dev/,先截掉该前缀
if ( strncmp ( id, "/dev/" , 5) = = 0)
id + = 5;
//复制字符串/dev/到tmpConsole临时缓存区中
strcpy ( tmpConsole, "/dev/" ) ;
/*再将id字段复制到tmpConsole第5个字符之后,即/dev/之后。这样tmpConsole就成为了某一设备文件名(含路径)。对于BusyBox init来说,tmpConsole是终端设备*/
safe_strncpy( tmpConsole + 5, id,
sizeof ( tmpConsole) - 5) ;
/*来到这里,应该就明白为什么BusyBox init的id字段是控制终端*/
id = tmpConsole;
}
//将action_type、command和控制终端id作为一init_action节点,添加到init_action_list列表中。从这里可以看出BusyBox init忽略了runlevel字段
new_init_action( ( uint8_t ) a[ 0] , command + 1, id) ;
goto next_line;
}
}
* command = ':' ;
/* Choke on an unknown action */
bad_entry:
message( L_LOG | L_CONSOLE, "Bad inittab entry: %s" , id) ;
next_line: ;
}
/* Run all commands of a particular type */
static void run_actions( int action_type)
{
struct init_action * a, * tmp; // 遍历init_action_list列表,查找类型为action_type的节点
for ( a = init_action_list; a; a = tmp) {
tmp = a- > next;
//查到类型为action_type的节点
if ( a- > action_type & action_type) {
// Pointless: run() will error out if open of device fails.
///* a->terminal of "" means "init's console" */
//if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) {
// //message(L_LOG | L_CONSOLE, "Device %s cannot be opened in RW mode", a->terminal /*, strerror(errno)*/);
// delete_init_action(a);
//} else
if ( a- > action_type & ( SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART) ){/*若该节点类型为SYSINIT、WAIT、CTRLALTDEL、SHUTDOWN 和RESTART的init_action,init会等待它的command执行完,再继续执行。并且command执行完后,删除该节点*/
waitfor( run( a) ) ;
delete_init_action( a) ;
} else if ( a- > action_type & ONCE) {
/*action_type为ONCE的init_action,init则不会等待它执行完,并且将该节点从init_action_list中删除*/
run( a) ;
delete_init_action( a) ;
} else if ( a- > action_type & ( RESPAWN | ASKFIRST) ) {
/* Only run stuff with pid==0. If they have
* a pid, that means it is still running */
/*当action_type为RESOAWN或ASKFIRST的init_action,且执行该init_action的command的进程已死 (通过a->pid == 0判断,已死RESOAWN或ASKFIRST的command进程,其init_action的pid域都会在init_main方法被置为0,具体见 本文最后一段源码)时,调用run方法fork一子进程(用于执行command),并将run返回的子进程ID保存于init_action的pid 域*/
if ( a- > pid = = 0) {
a- > pid = run( a) ;
}
}
}
}
}
/* Now run everything that needs to be run */
/* First run the sysinit command */
run_actions( SYSINIT) ;
/* Next run anything that wants to block */
run_actions( WAIT) ;
/* Next run anything to be run only once */
run_actions( ONCE) ;
/* Now run the looping stuff for the rest of forever */
while ( 1) {
/* run the respawn/askfirst stuff */
run_actions( RESPAWN | ASKFIRST) ;
/* Don't consume all CPU time -- sleep a bit */
sleep ( 1) ;
/* Wait for any child process to exit */
wpid = wait( NULL ) ;
while ( wpid > 0) {
/* Find out who died and clean up their corpse */
for ( a = init_action_list; a; a = a- > next) {
if ( a- > pid = = wpid) {
/* Set the pid to 0 so that the process gets
* restarted by run_actions() */
a- > pid = 0;
message( L_LOG, "process '%s' (pid %d) exited. "
"Scheduling for restart." ,
a- > command, wpid) ;
}
}
/* see if anyone else is waiting to be reaped */
wpid = wait_any_nohang( NULL ) ;
}
}
}
- BusyBox init及其inittab文件分析
- BusyBox init及其inittab文件分析
- BusyBox init及其inittab文件分析(转)
- busybox inittab文件分析
- BusyBox init及inittab文件详解
- busybox init inittab passwd
- BUSYBOX init级inittab 文件解释
- busybox init进程分析
- busybox init进程分析
- busybox的init分析
- init进程及inittab文件
- /etc/inittab文件分析
- Busybox init启动过程分析
- busybox的init程序分析
- busybox init启动过程分析
- 详细分析 /etc/inittab 文件
- 【Busybox】inittab详解
- 【Busybox】inittab详解
- /etc/inittab文件详解
- www 服务配置
- 关于GDI+,随便写写
- 【转载】POJ 计算几何入门题目推荐
- 使用Java操作CSV文件 .
- BusyBox init及其inittab文件分析
- Winform程序中设置DataGridView的列标题背景色不起作用怎么办
- 在eclipse中配置MOTO真机
- JS调用WebService提示"未定义"的解决方法
- loop循环的几种用法
- 深入浅出之正则表达式
- copy_to_user和copy_from_user两个函数的分析
- hdu1162
- 江城子.记7月2日圆明园荷花节