天天看點

嵌入式Linux使用Busybox init程序啟動過程分析

一、Busybox     Busybo是一個遵循GPLv2協定的開源項目。 Busybox将衆多的Linux指令集合進一個很小的可執行程式中,可以用來替換GNU fileutils shellutils等工具集。Busybox中各種指令與相應的GNU工具相比,所能提供的選項較少,但是能夠滿足一般應用。 Busybox為各種小型 的或者嵌入式系統提供了一個比較完完全的工具集。

Busybox在編寫過程中對檔案大小進行了優化,并考慮了系統資源有限的情況。與一般的GNU 工具集動辄幾MB的體積相比,動态連接配接的Busybox隻有幾百KB,即使靜态連接配接也隻有1MB左右。有人将Busybox比喻成Linux工具中的瑞士 軍刀,簡單的說就是好像是Linux的一個大的工具集,包括了Linux中的大部分指令和工具。嵌入式根目錄下的bin,sbin和usr目錄以及 linuxc通常就是Busybox。Busybox會根據配置的不同自動的生成一些檔案,但是有些根檔案系統下的檔案還是需要使用者自己來建立。 二、Busybox啟動流程分析    init程序是由核心啟動的第一個也是惟一的一個使用者程序,它根據配置檔案決定啟動哪些程式,比如執行某些腳本,啟動shell,運作使用者指定的程式等。 init程序是後續所有程序的發起者,比如init程序啟動/bin/sh程式後,才能夠在控制台上輸入各種指令。

   init程序的執行程式通常是sbin/init,上面講述的init程序的作用隻不過是/sbin/init這個程式的功能。在嵌入式領域,通常使用 Busybox內建的init程式.嵌入式根目錄下的bin,sbin和usr目錄以及linuxc通常就是Busybox。 1、在kernel/init/main.c的init函數中有如下代碼:

 if(execute_command)

 execve(execute_command,argv_init,envp_init);

 execve("/sbin/init",argv_init,envp_init);

bootloader會傳給核心的main函數 init=/linuxrc這個參數,于是就會執行下面的這句

execute_command = "linuxrc",busybox中_install目錄下的linuxrc是Busybox的一個軟連結,指向/bin/busybox,而 /sbin/init也是/bin/busybox的符号連結,是以這個linxrc基本沒有實際的意義隻是一個連接配接作用。我們可以重寫linuxrc, 添加自己的一些初始化的東西。這樣就可以把Linux核心中的init程式和Busybox中的init程式結合起來了。 2、Busybox init程序啟動流程    Busybox是目标闆系統上執行的第一個應用程式,當調用Busybox它會執行Busybox自身的init程序。

 Busybox initt 程式對應的代碼在init/init.c檔案中。其對應的流程圖如下:    

嵌入式Linux使用Busybox init程式啟動過程分析

    其中與建構根檔案系統關系密切的是控制台的初始化,對inittab檔案的解釋及執行。從圖中我們可以 看出, Busybox init啟動的第一個函數是int init_main(int argc UNUSED_PARAM, char **argv),在這裡可以設定信号的處理函數,初始化控制台,最重要的是解析inittab中内容。  在init_main()函數中會調用parse_inittab(void)函數,parse_inittab(void)函數可以使用一些預設的配置,當/etc/inittab沒有配置時。

static void parse_inittab(void) { #if ENABLE_FEATURE_USE_INITTAB     char *token[4];     parser_t *parser = config_open2("/etc/inittab", fopen_for_read);     if (parser == NULL) #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);                  new_init_action(SYSINIT, INIT_SCRIPT, "");         return;  }

..............    }

    其中最重要的一個是其中,最重要的一個,就是 new_init_action(SYSINIT, INIT_SCRIPT, ""),也就決定了接下去初始化的腳本是INIT_SCRIPT所定義的值。這個宏的預設值是"/etc/init.d/rcS".

#define INITTAB "/etc/inittab"     #ifndef INIT_SCRIPT #define INIT_SCRIPT "/etc/init.d/rcS"     #endif

  1)下面是分析檔案系統中/etc/init.d/rcS的内容,這是我的rcS檔案中的内容。這個檔案會在inittab中使用。在inittab後啟動rcS.

#!/bin/sh  PATH=/sbin:/bin:/usr/sbin:/usr/bin  runlevel=S  prevlevel=N  umask 022  export PATH runlevel prevlevel  //上面幾句為啟動環境設定必要的環境變量 echo "----------munt all----------------"  mount -a  //加載檔案/etc/fstab檔案中的選項, echo /sbin/mdev>/proc/sys/kernel/hotplug  mdev -s  //在/dev 目錄下建立必要的裝置節點; echo "***********************************************"  echo "****************Studying ARM Embedded ********************* echo "Kernel version:linux-2.6.32.1"  echo "Author frank"  echo "Date:2010.4.19"  echo "***********************************************

/bin/hostname -F /etc/sysconfig/HOSTNAME  //設定主機的名字

//下面這一句是設定核心的hotplug handler 為 mdev, 即當裝置熱插拔時,由 mdev 接收來自核心的消息并作出相應的回應, 比如挂載U盤。

echo /sbin/mdev>/proc/sys/kernel/hotplug

2)下面是inittab檔案的分析:如果存在/etc/inittab檔案,Busybox init程式解析它,然後按照它的訓示各種子程序,否則使用預設的配置建立子程序

#etc/inittab ::sysinit:/etc/init.d/rcS    //作為系統初始化檔案. s3c2410_serial0::askfirst:-/bin/sh  在序列槽啟動一個登入會話 ::ctrlaltdel:/sbin/reboot  //作為init重新開機執行程式. ::shutdown:/bin/umount -a –r

   //告訴init在關機時運作umount指令解除安裝所有的檔案系統,如果解除安裝失敗,試圖以隻讀方式重新挂載。

/etc/inittab 檔案中每個條目用來定義一個子程序,并确定它的啟動方法,格式如下 :

<id>:<runlevels>:<action>:<process>

例如:

ttySAC0:askfirst:-/bin/sh

(1)<id>:表示這個程序要使用的控制台(即标準輸入、标準輸出、标準錯誤裝置)。如果省略,則使用與init程序一樣的控制台。

(2)<runlevels>:對于Busybox init程式,這個字段滑意義,可以省略。

(3)<action>:表示init程式如何控制這個子程序,

(4)<process>: 要執行的程式,它可以是可執行程式,也可以是腳本

如果<process>:字段有"-"字元,表示這個程式被稱為“互動的”。在/etc/inittab/檔案的控制下,init程序的行為總結如下:

(1)在系統啟動前期,init程序首先啟動<action>為sysinit wait once的3類子程序。

(2)在系統正常運作期間,init程式首先啟動,<action>為respawn askfirst的兩類子程序,并監視它們,發現某個子程序退出時重新啟動它。

(3) 在系統退出時,執行<action> 為shutdown restart ctrlaltdel的3類子程序之一或全部。

如果根檔案系統中沒有/etc/initab檔案,Busybox init程式将使用如下預設的inittab條目。

             /etc/inittab檔案中<action>字段的意義

Action 名稱 執行條件 說明
Sysinit 系統啟動後最先執行 隻執行一次, init 程序等待它結束才繼續執行其它動作
Wait 系統執行完 sysinit 程序後 隻執行一次, init 程序等待它結束才繼續執行其它動作
Once 系統執行完 wait 程序後 隻執行一次 ,init 程序不等待它結束
Respawn 啟動完 once 程序後 Init 程序監測發現子程序退出時,重新啟動它
Askfirst 啟動完 respawn 程序後 與 respawn 類似,不過 init 程序先輸出“ Please press Enter to actvie this console ”,等使用者輸入駕車鍵之後才啟動子程序
Shutdown 當系統關機時 即重新開機關閉系統指令時
Restart Busybox 中配置了CONFIG_FEATURE_USE_INITTAB,并且 init 程序接收到 SIGHUP 信号時 先重新讀取,解析 /etc/initab 檔案,再執行 restart 程式
Ctrlatldel 按下 Ctr+Alt+del 組合鍵時

3)下面是etc/fstab檔案内容,表示執行完“mount -a”指令後将挂載proc tmpfs等系統  

#device mount-point type option dump fsck order proc /proc proc defaults 0 0 temps /tmp rpoc defaults 0 0 none /tmp ramfs defaults 0 0 sysfs /sys sysfs defaults 0 0 mdev /dev ramfs defaults 0 0

4)/etc/profile檔案 

這個檔案是 sh 用的,當使用者獲得一個 shell 後, sh 就會根據這個檔案配置使用者的登陸環境,下面是我的profile 檔案。

# Ash profile # vim: syntax= sh # No core file by defaults # ulimit - S - c 0> / dev/ null 2> & 1 USER= "id -un"  LOGNAME= $ USER PS1= '[/u@/h=W]#'  PATH= $ PATH HOSTNAME= '/bin/hostname'  export USER LOGNAME PS1 PATH

    其中PATH環境變量指定當使用者鍵入一個指令時,sh尋找這個指令的路徑。PS1指定sh提示符的格式。其它的 export 指令, alias 指令, busybox 裡面的 ash 和 bash 非常相似 

    這樣, Busybox所需的基本的配置檔案就完成了。這也是Busybox最基本的檔案,當然還可以配置更多的檔案,增強Busybox的功能。

繼續閱讀