1. 程式人生 > >根檔案系統之init

根檔案系統之init


title: 根檔案系統之init
tag: arm
date: 2018-11-12 18:53:23
---

引入

在Kernel原始碼分析中,瞭解到init_post是在掛載根檔案系統之後執行應用程式

mark

mark

開啟標準輸入/輸出/錯誤

Linux首先開啟標準輸入scanf,標準輸出printf,標準錯誤err


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);

這裡的sys_dup(0)表示複製開啟的第0個檔案,也就是/dev/console,也就是說準輸入scanf,標準輸出printf,標準錯誤err都定位到/dev/console這個檔案,這個檔案被稱為終端,他可以是串列埠或者液晶鍵盤組合等

執行init程序

接下來會處理U-boot傳遞進來的命令列引數

//run_init_process 一般會正確執行不會返回的程式
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.");

我們搜尋下execute_command,發現如下定義,很明顯和kernel原始碼分析中的命令列引數類似

static int __init init_setup(char *str)
{
    unsigned int i;

    execute_command = str;
    /*
     * In case LILO is going to boot us with default command line,
     * it prepends "auto" before the whole cmdline which makes
     * the shell think it should execute a script with such name.
     * So we ignore all arguments entered _before_ init=... [MJ]
     */
    for (i = 1; i < MAX_INIT_ARGS; i++)
        argv_init[i] = NULL;
    return 1;
}
__setup("init=", init_setup);

也是設定一個段屬性固定的結構體

#define __setup(str, fn)                    \
    __setup_param(str, fn, fn, 0)

#define __setup_param(str, unique_id, fn, early)            \
    static char __setup_str_##unique_id[] __initdata = str; \
    static struct obs_kernel_param __setup_##unique_id  \
        __attribute_used__              \
        __attribute__((__section__(".init.setup"))) \
        __attribute__((aligned((sizeof(long)))))    \
        = { __setup_str_##unique_id, fn, early }

也就是構造了一個和root=/dev/mtdblock3類似的

static char __setup_str_init_dev_setup[] __initdata = "init=";
static struct obs_kernel_param __setup_init_dev_setup 
    __attribute_used__
    __attribute__((__section__(".init.setup"))) 
    __attribute__((aligned((sizeof(long)))))    
    ={
        __setup_str_init_dev_setup,root_init_setup,init_dev_setup,0
    }
    
這個結構體的原型如下
struct obs_kernel_param 
{
    const char *str;
    int (*setup_func)(char *);
    int early;
};

也就是說execute_command=/linuxrc,因為u-boot傳遞的引數是init=/linuxrc,程式會使用run_init_process(execute_command);來處理這個命令列

注意 函式run_init_process一般會正確執行不會返回的程式,也就是說如果能夠正確執行u-boot傳遞的引數,將不會執行以下

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.");

小結測試

(一)

燒錄u-boot,燒錄Linux,擦除根檔案系統nand erase root,也就是不放根檔案系統,系統會有如下提示

VFS: Mounted root (yaffs filesystem).       
掛接了根檔案系統,但是flash是空的,預設識別為yaffs
Freeing init memory: 140K
Warning: unable to open an initial console.
flash是空的,無法啟動應用程式
Failed to execute /linuxrc.  Attempting defaults...
錯誤指示--命令列
Kernel panic - not syncing: No init found.  Try passing init= option to kernel.

因為格式化了flash,系統可以識別為任意的檔案系統,預設識別為yaffs,但是由於沒有根檔案系統,所以無法開啟標準輸入輸出,按照程式碼所寫的提示錯誤

printk(KERN_WARNING "Warning: unable to open an initial console.\n");

同時也就無法開啟init程序,提示

panic("No init found.  Try passing init= option to kernel.");

(二)

燒入根檔案系統,在u-boot下輸入y,下載檔案系統fs_mini.yaffs2,然後啟動.輸入ps看下啟動的應用程式

# ps
  PID  Uid        VSZ Stat Command
    1 0          3092 S   init
    2 0               SW< [kthreadd]
    3 0               SWN [ksoftirqd/0]
    4 0               SW< [watchdog/0]
    5 0               SW< [events/0]
    6 0               SW< [khelper]
   55 0               SW< [kblockd/0]
   56 0               SW< [ksuspend_usbd]
   59 0               SW< [khubd]
   61 0               SW< [kseriod]
   73 0               SW  [pdflush]
   74 0               SW  [pdflush]
   75 0               SW< [kswapd0]
   76 0               SW< [aio/0]
  710 0               SW< [mtdblockd]
  745 0               SW< [kmmcd]
  767 0          3096 S   -sh
  769 0          3096 R   ps

這裡init就是啟動的第一個程序sh也就是終端接收輸入以及列印的輸出

init實現

在嵌入式Linux中的一些基礎命令例如ls,cp等實際上也是一個個App,這些基本命令一般由busybox編譯得到一個名為busybox的應用程式.然後ls,cd,cp等命令一般是其連結.可以使用ls-l xxx來檢視其連結屬性.可以先用which xxx檢視其位置,然後看屬性

# ls -l /bin/ls
lrwxrwxrwx    1 1000     1000            7 Jan  6  2010 /bin/ls -> busybox

# ls
bin         lib         mnt         sbin        usr
dev         linuxrc     proc        sys
etc         lost+found  root        tmp

# busybox ls
bin         lib         mnt         sbin        usr
dev         linuxrc     proc        sys
etc         lost+found  root        tmp

其實,/sbin/init也是到busybox的連結

run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");


# which init
/sbin/init
# ls -l /sbin/init
lrwxrwxrwx    1 1000     1000           14 Jan  6  2010 /sbin/init -> ../bin/busybox