openwrt啟動過程詳細分析


OpenWrt是一個開放的linux平台,主要用於帶wifi的無線路由上。類似於Ubuntu、Red Hat、之類的linux發行版本,它也有一套自己的啟動流程。本文主要介紹了openwrt啟動過程及詳細分析。

  1、概述

  在linux的發展過程中,linux的啟動程序也在發展,從sysv init到現在的upstart、systemd,通常該程序是進程號為1的進程,該程序在linux系統有着舉足輕重的地方。在openwrt中,使用了另外一種啟動程序叫做procd,本文的重點並不在於介紹procd,本文主要介紹並解析procd、preinit及各種腳本如何完成整個系統的初始化。

  2、軟件環境

  Linux發行版:ubuntu14.04 LTS

  Openwrt版本:barrier break 14.07 r42635 (linux kernel 3.10.49)

  硬件:MPR-A2模塊(rt5350)

  在查看linux內核代碼及根文件系統下的腳本之前,需要對openwrt進行配置,運行make menuconfig,在Target System中選擇Ralink RT288x/RT3xxx,Subtarget中選擇RT3x5x/RT5350based boards,Target Profile選擇HAME MPR-A2,然后make完成openwrt的編譯。打完patch的內核代碼在build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_rt305x/目錄下,根文件系統目錄在build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/root-ramips/。

  3、啟動分析

  3.1 內核啟動點

  Linux的啟動入口為start_kernel()(init/main.c),該函數的最后會調用rest_init()(init/main.c),該函數創建兩個內核線程init和kthreadd之后,進入死循環,即所謂的0號進程。init線程執行kenrel_init()(init/main.c)函數,在kernel_init函數中,首先會檢查內核的啟動參數中是否有設置init參數,如果有,則會使用該參數指定的程序作為init程序,否則會按照如下代碼(打上patch后的)中所示的順序依次嘗試啟動,如果都無法啟動就會導致kernel panic。

  if (!run_init_process(“/etc/preinit”) ||

  !run_init_process(“/sbin/init”) ||

  !run_init_process(“/etc/init”) ||

  !run_init_process(“/bin/init”) ||

  !run_init_process(“/bin/sh”))

  return 0;

  在目前的環境下,內核啟動參數未設置init參數,所以會以/etc/preinit程序作為init程序,preinit實際為shell腳本。

  3.2 相關文件

  3.2.1 腳本文件

  /etc/preinit

  /lib/functions.sh

  /lib/functions/preinit.sh

  /lib/functions/system.sh

  /lib/preinit/下所有腳本

  3.2.2 init程序

  在proc程序包中,編譯完會生成兩個可執行程序:init和procd,均在目 錄/sbin下,這兩個程序均會使用到。

  3.3 過程分析

  這個初始化過程遵循如下主線:

  openwrt啟動過程詳細分析

  下面我們一步一步分析這個過程。

  在/etc/preinit腳本中,第一條命令如下:

  [ -z “$PREINIT” ] && exec /sbin/init

  在從內核執行這個腳本時,PREINIT這個變量時沒有定義的,所以會直接執行/sbin/init。/sbin/init程序主要做了一些初始化工作,如環境變量設置、文件系統掛載、內核模塊加載等,之后會創建兩個進程,分別執行/etc/preinit和/sbin/procd,執行/etc/preinit之前會設置變量PREINIT,/sbin/procd會帶-h的參數,當procd退出后會調用exec執行/sbin/proc替換當前init進程(具體過程可參見procd程序包中的init和procd程序)。這就是系統啟動完成后,ps命令顯示的進程號為1的進程名最終為/sbin/procd的由來,中間是有幾次變化的。

  繼續看/etc/preinit腳本,出來變量設置外,接下來是執行了三個shell腳本:

  /lib/functions.sh

  /lib/functions/preinit.sh

  /lib/functions/system.sh

  注意“。”和“/”之間是有空格的,這里的點相當與souce命令,但souce是bash特有的,並不在POSIX標准中,“。”

  是通用的用法。使用“。”的意思是在當前shell環境下運行,並不會在子shell中運行。這幾個shell腳本主要定義了shell函數,

  特別是preinit.sh中,定義了hook相關操作的函數。

  之后會使用boot_hook_init定義五個hook結點如下:

  boot_hook_init preinit_essential

  boot_hook_init preinit_main

  boot_hook_init failsafe

  boot_hook_init initramfs

  boot_hook_init preinit_mount_root

  之后會向這些結點中添加hook函數。

  在之后就是一個循環,依次在當前shell下執行/lib/preinit/目錄下的腳本,

  for pi_source_file in /lib/preinit/*; do

  $pi_source_file

  done

  /lib/preinit/目錄下的腳本具體類似的格式,定義要添加到hook結點的函數,然后通過boot_hook_add將該函數添加到對應的hook結點。

  最后,/etc/preinit就會執行boot_run_hook函數執行對應hook結點上的函數。在當前環境下只執行了preinit_essential和

  preinit_main結點上的函數,如下:

  boot_run_hook preinit_essential

  boot_run_hook preinit_main

  到此,/etc/preinit執行完畢並退出。如果需要跟蹤調試這些腳本,可以 在/etc/preinit的最開始添加一條命令set -x,這樣就會打印出執行命令的過程, 當並不會真正執行。

  至於系統服務程序的啟動及初始化將全由procd完成,procd的功能不僅在於此,它還集成更多其他功能,具體可參見procd的資料。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM