busybox 的init主要用于嵌入式系統,是以沒有運作級别。
::respawn:-/bin/login -froot 自動作為root使用者登入。
在Linux核心中找到/init/main.c 看到如下内容:
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
這裡就是執行系統的啟動,當滿足上面其中之一後,系統就會執行啟動程序。一般通過busybox編譯後的init在/sbin/下,是以通過第一條指令,下面就需要找到init,分析源碼。
在busybox源碼的/init/init.c中,有#define INITTAB "/etc/inittab"的定義,inittab的作用自不必再說了,系統會根據inittab的提示進行啟動加載。但在在解析inittab時,若沒有該檔案,便會執行新的啟動腳本#defineINIT_SCRIPT "/etc/init.d/rcS"。
rcS就是整個系統啟動的關鍵。
在核心初始化完成後,嵌入式linux 檔案系統的啟動過程主要包含以下幾個步驟:
1. 執行/sbin/init 檔案
2. 執行/etc/inittab 檔案
3. 執行/etc/init.d/rcS 檔案
4. 執行挂載檔案系統腳本
5. 執行核心子產品腳本
6. 執行網絡初始化腳本
7. 執行應用程式啟動等腳本,如qtopia 的啟動
系統啟動流程圖:
1. 核心啟動init
核心啟動的最後一步就是啟動init 程序,init 程序是由核心啟動的第一個(也是唯一一個和)使用者程序(程序ID 為1),它根據配置檔案決定啟動哪些程式,比如某些腳本, 啟動shell ,運作使用者指定的程式等,,那麼init程序又是怎麼啟動的呢---是由核心調用/sbin/init 檔案而啟動的,那有人就有人想知道核心是如何找到需要執行的init檔案呢。下面看一下核心代碼中init/main.c ,如下所示:
static int noinline init_post(void)
{
free_initmem();
unlock_kernel();
mark_rodate_ro();
system_state=SYSTEM_RUNNING;
numa_default_policy();
if(sys_open((const char __user*) “/dev/console”,O_RDWR,0)<0)
printk(KERN_WARNING “Waring :unable to open an initialconsole.\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\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.”);
核心啟動init 程序的過程如下:
先打開控制台裝置/dev/console ,并複制了兩個handle, 這樣stdout,stdin,stderr都指向/dev/console,這樣就打開了标準裝置輸入,輸出,标準錯誤裝置,然後執行幾個外部程式。這幾個程式中任何一個加載成功就進入了使用者态,核心啟動就宣告結束。
2. 執行/etc/inittab 檔案
當init 啟動成功後,需要做的就是分析/etc/inittab 檔案并執行它。其内容如下:
# /etc/inittab
::sysinit:/etc/init.d/rcS
# 啟動shell 以/dev/ttySAC0 作為控制台
ttySAC0::askfirst:-/bin/sh
# 按下ctrl+alt+del 之後執行的程式,不過在序列槽控制台中無法輸入ctrl+alt+del 組合鍵
::ctrlaltdel:/sbin/reboot
# 重新開機關機前執行的程式
::shutdown:/bin/umount -a -r
3. 執行/etc/init.d/rcS 檔案
這是一個腳本檔案,可以在裡面添加想自動運作的指令。内容如下:
#! /bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:
runlevel=S
prevlevel=N
umask 022
export PATH runlevel prevlevel
# 網絡配置腳本
. /etc/init.d/network.sh
# load zlg_fs
insmod /bin/zlg_fs.ko
insmod /bin/zlg_ffs.ko
mknod /dev/zlg_fsa b 125 0
mknod /dev/zlg_fsa1 b 125 1
mknod /dev/zlg_fsa2 b 125 2
mount -t vfat /dev/zlg_fsa /usr
mount -a
4. 執行/etc/fstab( 挂載檔案系統腳本)
在檔案 /etc/init.d/rcS 中執行 mount –a 時,就會按照檔案 /etc/fstab 内容挂載相應的檔案系統.
#device mount-point type options dump fsck order
none /proc proc defaults 0 0
none /dev/pts devpts mode=0622 0 0
tmpfs /dev/shm tmpfs defaults 0 0
(1)device : 要挂接的裝置,如 /dev/hda2
mount-point: 挂接點
type: 檔案系統類型,如 pro,jffs2,nfs
options: 挂接參數,以逗号隔開
dump 和 fsck order :用來決定控制 dump,fsck 程式的行為。
5. 接着就會執行一些核心子產品和網絡俄配置腳本,最後執行應用程式啟動等腳本,如 qtopia 的啟動。
==================================================================================
按啟動順序依次介紹相關的檔案:
一、核心啟動完之後,首先運作/linuxrc。
/linuxrc内容:
#!/bin/sh
echo "mount /etc as ramfs"
/bin/mount -n -t ramfs ramfs/etc
/bin/cp -a /mnt/yaffs/etcetc
/etc成為可寫目錄後,将所有/mnt/yaffs/etc中的配置檔案拷貝到/etc/中,這說明你的ramfs可能是一個空的ramfs,沒有配置檔案,或者配置檔案比較老。同時也說明你這個系統是一個隻讀系統,每次系統運作中寫入的配置不會保留。
将以前mount的那些資訊重新寫到/etc/mtab中,指令就是下面這些。
3. /bin/mount -f -t cramfs -oremount,ro /dev/mtdblock/2 /
/bin/mount -f -t ramfs ramfs/etc
這些指令隻是将這些mount資訊寫到/etc/mtab中,不會實際去mount這些blockdevice,說明你的根檔案系統依然是以前的那個/dev/bon/2
4. exec/sbin/init
執行根檔案系統中的init執行程式,使其成為1号程序。shell正式運作。
###################################################################################
/etc/mtab介紹:
mtab同/etc/fstab的格式一樣,它用于記錄已經挂載的分區資訊。
注意:
如果沒有/linuxrc這個檔案,系統預設首先運作/sbin/init。
###################################################################################
二、從/linuxrc檔案中我們看到它最後運作了/sbin/init,而init又會根據/etc/inittab來運作。
inittab 檔案條目格式:
id:runlevels:action:process
id:
inittab 檔案中條目的唯一辨別, 限于 1-4 個字元 (如果是用版本号小于 5.2.18 或 a.out 的庫編譯生成的sysvinit 程式, 則僅限于 2 個字元).
注意: 對于 getty 或其它的注冊程序, id 必須是響應的終端線路的 tty 字尾, 如 1 響應 tty1, 否則,注冊過程不能正常的工作.
runlevels:
# 0 - halt (Do NOT setinitdefault to this)
# 1 - Single usermode
# 2 - Multiuser, without NFS(The same as 3, if you do not have networking)
# 3 - Full multiusermode
# 4 - unused
# 5 - X11
# 6 - reboot (Do NOT setinitdefault to this)
action
描述要發生的動作.
process
要執行的程序. 如果 process 域以一個 `+' 開頭, init 不會在 utmp 和 wtmp 檔案中為此程序記帳.這是由于 getty 自己主持 utmp/wtmp 記帳的需要, 同時這也是一個曆史遺留的漏洞.
runlevels 域可以包含表示不同運作級的多個字元, 例如 123 表示本程序在運作級為 1, 2 和 3 時都要啟動. 用于ondemand 條目的 runlevels 域可以包含 A, B, 或 C. 用于 sysinit, boot, 和bootwait 條目的 runlevels 域被忽略.
當改變運作級時, 在新運作級中沒有給出的那些正在運作的程序被殺死, 先使用 SIGTERM 信号, 然後是SIGKILL.
action域可以使用的動作有:
- respawn:
該程序隻要終止就立重新啟動 (如 getty).
- wait
隻要進入指定的運作級就啟動本程序, 并且 init 等待該程序的結束.
- once
隻要進入指定的運作級就啟動一次本程序.
- boot
在系統引導期間執行本程序. runlevels 域被忽略.
- bootwait
在系統引導期間執行本程序. 并且 init 等待該程序的結束 (如 /etc/rc). runlevels域被忽略.
- off
什麼也不做.
- ondemand
在進入 ondemand 運作級時才會執行标記為 ondemand 的那些程序. 無論怎樣, 實際上沒有改變運作級 (ondemand運作級就是 `a', `b', 和 `c').
- initdefault
initdefault 條目給出系統引導完成後進入的運作級, 如果不存在這樣的條目, init 就會在控制台詢問要進入的運作級.process 域被忽略.
- sysinit
系統引導期間執行此程序. 本程序會在 boot 或 bootwait 條目之前得到執行. runlevels域被忽略.
- powerwait
本程序在電源不足時執行. 通常在有程序把 UPS 和計算機相連時通知 init 程序, Init在繼續其它工作之前要等待此程序結束.
- powerfail
類似 powerwait, 但是init 不等待此程序完成.
- powerokwait
在 init 收到電源已經恢複的通知後立即執行此程序.
- powerfailnow
本程序在 init 被告知 UPS 電源快耗盡同時外部電源失敗 (無效) 時被執行. (假設 UPS和監視程序能夠發現這樣的情況).
- ctrlaltdel
在 init 收到 SIGINT 信号時執行此程序. 這意味着有人在控制台按下了 CTRL-ALT-DEL 組合鍵, 典型地,可能是想執行類似 shutdown 然後進入單使用者模式或重新開機機器.
- kbrequest
本程序在 init 收到一個從控制台鍵盤産生的特殊組合按鍵信号時執行.
inittab執行個體:
#/etc/inittab
::sysinit:/etc/init.d/rcS
tty0::respawn:/sbin/getty 38400 tty0
tty2::askfirst:/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/cp /etc /mnt/yaffs/etc-ra //因為我們的根檔案系統隻讀,需要儲存/etc的内容
::shutdown:/bin/umount ar
::shutdown:/bin/mount / o remount,ro //mount -o remount就是重新加載的意思
三、從inittab中我們可以看到現在系統啟動/etc/init.d/rcS!
下面我們介紹一下rcS檔案
//rcS的内容
#!/bin/sh
/bin/mount -a
/sbin/ifconfig 192.168.0.1
/bin/echo "I am xiaoshou! "
首先我們看到 mount -a這個指令。這個指令依據/etc/fstab來進行挂載的操作。
接着我們來看看/etc/fstab這個檔案。
#/etc/fstab
none /proc proc defaults 0 0
none /dev/pts devpts mode=0622 0 0
tmpfs /dev/shm tmpfs defaults 0 0
現在介紹一下此檔案的格式:
# fstab檔案的作用
檔案/etc/fstab存放的是系統中的檔案系統資訊。當正确的設定了該檔案,則可以通過"mount/directoryname"指令來加載一個檔案系統,每種檔案系統都對應一個獨立的行,每行中的字段都有空格或tab鍵分開。同時fsck、mount、umount的等指令都利用該程式。
# fstab檔案格式
下面是/etc/fatab檔案的一個示例行:
fs_spec | fs_file| fs_type|fs_options| fs_dump| fs_pass
/dev/hda1 | / | ext2 | defaults | 1 | 1
fs_spec -該字段定義希望加載的檔案系統所在的裝置或遠端檔案系統,對于一般的本地塊裝置情況來說:IDE裝置一般描述為/dev/hdaXN,X是IDE裝置通道(a, b, orc),N代表分區号;SCSI裝置一描述為/dev/sdaXN。對于NFS情況,格式一般為<host>:<dir>,例如:`knuth.aeb.nl:/'。對于procfs,使用`proc'來定義。
fs_file -該字段描述希望的檔案系統加載的目錄點,對于swap裝置,該字段為none;對于加載目錄名包含空格的情況,用40來表示空格。
fs_type -定義了該裝置上的檔案系統,一般常見的檔案類型為ext2(Linux裝置的常用檔案類型)、vfat(Windows系統的fat32格式)、NTFS、iso9600等。
fs_options -指定加載該裝置的檔案系統是需要使用的特定參數選項,多個參數是由逗号分隔開來。對于大多數系統使用"defaults"就可以滿足需要。其他常見的選項包括:
選項 含義
ro 以隻讀模式加載該檔案系統
sync 不對該裝置的寫操作進行緩沖處理,這可以防止在非正常關機時情況下破壞檔案系統,但是卻降低了計算機速度
user 允許普通使用者加載該檔案系統
quota 強制在該檔案系統上進行磁盤定額限制
noauto 不再使用mount-a指令(例如系統啟動時)加載該檔案系統
fs_dump -該選項被"dump"指令使用來檢查一個檔案系統應該以多快頻率進行轉儲,若不需要轉儲就設定該字段為0
fs_pass -該字段被fsck指令用來決定在啟動時需要被掃描的檔案系統的順序,根檔案系統"/"對應該字段的值應該為1,其他檔案系統應該為2。若該檔案系統無需在啟動時掃描則設定該字段為0
四、在挂載完所有分區後,我們可以在/etc/init.d/rcS檔案中添加我們自己的指令。
如:/sbin/ifconfig eth0192.168.0.1
/sbin/ifconfig lo 127.0.0.1
版權聲明:本文為CSDN部落客「x123niuniuniu」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。
原文連結:https://blog.csdn.net/x123niuniuniu/article/details/7601787