现在的位置: 首页 > 综合 > 正文

文件系统分析和制作的整个过程

2013年10月16日 ⁄ 综合 ⁄ 共 6350字 ⁄ 字号 评论关闭

/etc/inittab文件的作用

Linux启动之后运行的第一个进程init会从/etc/inittab 文件中读取配置并做一些初始化的工作

格式:

id:runlevels:action:process

大致的含义就是init初始化程序以一定的方式(action)在哪些运行级别(runlevels)下执行某个程序(process)

 

id

用于表示该配置项的id,长度为1~4个字符,id必须在本文件内唯一,如果有重复id,则init启动的时候会报duplicate id的错误,且后面的重复项配置将无效。这边可以将每一条配置项看作数据库中的一条记录,分号分割的部分为各个字段,将id号则可以看作记录的Primary Key。

runlevels

程序执行的运行级别。

action

常见的action如下所示:

* initdefault: 该配置项指定系统的默认运行级。
* respawn: 该配置项所指定的进程如果被结束,则重新启动该进程。
* wait: 该配置项指定的进程在运行结束之前不要执行下一条配置项。
* once: 切换到对应的运行级之后,仅执行指定的进程一次。
* sysinit: 无论以什么运行级启动,系统启动时都要执行该配置项指定的进程。
* boot: 仅在系统启动时执行一次。
* bootwait: 仅在系统启动时执行一次,在执行结束之前不执行下一条配置项
* powerfail: 当接收到UPS的断电通知时执行该项指定的进程。
* powerwait: 与powerfail相同,但init会等待进程执行结束。
* powerokwait: 接收到UPS的供电通知时执行。
* ctrlaltdel: 当用户同时按下 Ctrl+Alt+Del 时执行该项指定的进程。

process:

指定的程序路径和参数

 

例子

举一个最常见的例子,就是默认地我们可以使用Ctrl+Alt+F1~F6切换的虚拟终端功能就是在此文件中定义的:

1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6

id列可以用数字,也可以用字符,当然数字也是当字符来看,只要确保本文件唯一即可。

runlevel定义了在2~5的运行级别都存在对应的虚拟终端,所以在2~5的运行级别下可以通过Ctrl+Alt+F1~F6进行终端的切换,而在s[单用户模式]和运行级别为1的时候则无法使用虚拟终端[虽然可以通过Ctrl+Alt+F1~F6进行切换,但终端已经被挂起]。

respawn则定义了如果mingetty进程结束,则重启该进程。

/sbin/mingetty ttyn定义了执行的程序和参数。

 

要想/etc/inittab即时生效,可以通过以下命令让init进程重新读取此文件:

init q

 

 

 

###############################

内核函数:要执行的第一个应程序函数:
###############################

static int noinline init_post(void)
{
 free_initmem();
 unlock_kernel();
 mark_rodata_ro();
 system_state = SYSTEM_RUNNING;
 numa_default_policy();
 if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
  printk(KERN_WARNING "Warning: unable to open an initial console.\n");
 (void) sys_dup(0);
 (void) sys_dup(0);

 if (ramdisk_execute_command) {
  run_init_process(ramdisk_execute_command);
  printk(KERN_WARNING "Failed to execute %s\n",
    ramdisk_execute_command);
 }
 if (execute_command) {
  run_init_process(execute_command);
  printk(KERN_WARNING "Failed to execute %s.  Attempting "
     "defaults...\n", execute_command);
 }
 run_init_process("/sbin/init");
 run_init_process("/etc/init");
 run_init_process("/bin/init");
 run_init_process("/bin/sh");
 panic("No init found.  Try passing init= option to kernel.");
}
###############################################

《大致过程》

第一、open()所以创建/dev/console与/dev/null目录
 因为执行应用程序,就得先打开设备节点
 /dev/null是用来不设置ID是(在inittab格式)时,标准输入,输出,错误等久会定位到它去;
第二、设置配置文件/etc/inittab
第三、配置文件里指定用户应用程序
第四、C库(因为我们写应用程序时,printf,read等都是C库实现的)
第五、init(busybox编译)
###############################################

《busybox分析》

busybox->init.c->init_main()函数

---------------------------------------------------------
 init_mian(){
parse_inittab()

       1.parser_t *parser =config_open2("/etc/inittab", fopen_for_read);
       2.new_init_action()

                           /*1.创建init_action结构体,用inittab内容去填充
                            *2.然后把这个结构体放入链表init_action_list中去
                            */
run_actions(SYSINIT);
   1.waitfor(a,0);    /*执行应用程序,等待它执行完毕*/
         run(a);    /*创建process子进程*/
         waitpid(runpid,&status,0);/*等待它结束*/
   2.delete_init_actin(a);/*在init_action_list链表里删除*/
run_actions(WAIT);
   1.waitfor(a,0);    /*执行应用程序,等待它执行完毕*/
         run(a);    /*创建process子进程*/
         waitpid(runpid,&status,0);/*等待它结束*/
   2.delete_init_actin(a);/*在init_action_list链表里删除*/
run_actions(ONCE);
   1.run(a);    /*创建process子进程*/
   2.delete_init_actin(a);/*在init_action_list链表里删除*/
while (1) {
 run_actions(RESPAWN | ASKFIRST);

  {
         if (a->pid == 0){
         a->pid = run(a);}
附:RESPAWN | ASKFIRST区别:
    ASKFIRST:1.打印信息 2.等待回车 3.创建进程
    wpid=wait(NULL);//等待子进程退出
 whlie(wpid>0){
  a->pid=0;//退出后,设置pid=0;  }

  }
}
########################################

《int_mian()->parse_inittab源代码分析》

 

static void parse_inittab(void)
{
#if ENABLE_FEATURE_USE_INITTAB
 char *token[4];
**************第一,打开配置文件(/etc/inittab)************
**********************************************************
parser_t *parser = config_open2("/etc/inittab", fopen_for_read);
 -----------------------------------------------
 /*打开配置文件----配置文件有什么内容(就是按什么格式来写的)*/
 -----------------------------------------------
 《inittab配置文件格式》:
 <id>:<runlevels>:<action>:<process>
 <id:>:         用作终端;如标准IO(stdin,stdout,stderr,printf,scanf等)
 <renlevles>:   运行级别->完全可以忽略
 <action>:      执行时机(包含的选项:sysinit ,respawn ,askfirst,wait,oncerestart,ctrlaltdel, shutdown)
 <process>:    应用程序或脚本(都为可执行文件)
 ---------------------------------------------

****************第二、解析配置文件**********************
********************************************************
《如何解析配置文件》
如:new_init_action(ASKFIRST, bb_default_login_shell,  VC_2  );
  ==new_init_action(ASKFIRST,    "-/bin/sh",      "/dev/tty2");
    new_init_action作用:
   1.创建init_action结构体,用inittab内容去填充
   2.然后把这个结构体放入链表init_action_list中去
********************************************************
if (parser == NULL)
/////*1.若没有配置文件传进来,则就执行<系统默认inittab配置文件>*/////
#endif          
 {
  new_init_action(CTRLALTDEL, "reboot", "");
  new_init_action(SHUTDOWN, "umount -a -r", ""); 
  if (ENABLE_SWAPONOFF)
   new_init_action(SHUTDOWN, "swapoff -a", ""); 
  new_init_action(RESTART, "init", "");
  new_init_action(ASKFIRST, bb_default_login_shell, "");
//TODO: VC_1 instead of ""? "" is console -> ctty problems -> angry users
  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配置文件>内容:
 ---------------------------------------------
 ::ctrlaltdel:reboot
 ::shutdown:umount -a -r
 ::restart:init
 ::askfirst:-/bin/sh
 tty2:askfirst:-/bin/sh
 tty3:askfirst:-/bin/sh
 tty4:askfirst:-/bin/sh
 ---------------------------------------------
////*2.若有配置传进来,则就执行如下*/////
#if ENABLE_FEATURE_USE_INITTAB
 while (config_read(parser, token, 4, 0, "#:",
    PARSE_NORMAL & ~(PARSE_TRIM | PARSE_COLLAPSE))) {
  /* order must correspond to SYSINIT..RESTART constants */
  static const char actions[] ALIGN1 =
   "sysinit\0""wait\0""once\0""respawn\0""askfirst\0"
   "ctrlaltdel\0""shutdown\0""restart\0";
  int action;
  char *tty = token[0];

  if (!token[3]) /* less than 4 tokens */
   goto bad_entry;
  action = index_in_strings(actions, token[2]);
  if (action < 0 || !token[3][0]) /* token[3]: command */
   goto bad_entry;
  /* turn .*TTY -> /dev/TTY */
  if (tty[0]) {
   tty = concat_path_file("/dev/", skip_dev_pfx(tty));
  }
  new_init_action(1 << action, token[3], tty);
  if (tty[0])
   free(tty);
  continue;
 bad_entry:
  message(L_LOG | L_CONSOLE, "Bad inittab entry at line %d",
    parser->lineno);
 }
 config_close(parser);
#endif
}

########################

 

 

 

 

 

抱歉!评论已关闭.