天天看點

嵌入式linux 根檔案系統的啟動及配置

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

繼續閱讀