您的位置:首页 > 运维架构

Openwrt启动之preinit流程分析

2015-06-05 22:42 369 查看
首先上代码 /etc/preinit文件

#!/bin/sh
# Copyright (C) 2006 OpenWrt.org
# Copyright (C) 2010 Vertical Communications

export PATH=/bin:/sbin:/usr/bin:/usr/sbin

pi_ifname=
pi_ip=192.168.1.1
pi_broadcast=192.168.1.255
pi_netmask=255.255.255.0

fs_failsafe_ifname=
fs_failsafe_ip=192.168.1.1
fs_failsafe_broadcast=192.168.1.255
fs_failsafe_netmask=255.255.255.0

fs_failsafe_wait_timeout=2

pi_suppress_stderr="y"
pi_init_suppress_stderr="y"
pi_init_path="/bin:/sbin:/usr/bin:/usr/sbin"
pi_init_cmd="/sbin/init"

. /lib/functions.sh
. /lib/functions/boot.sh

boot_hook_init preinit_essential
boot_hook_init preinit_main
boot_hook_init failsafe
boot_hook_init initramfs
boot_hook_init preinit_mount_root

for pi_source_file in /lib/preinit/*; do
. $pi_source_file
done

boot_run_hook preinit_essential

pi_mount_skip_next=false
pi_jffs2_mount_success=false
pi_failsafe_net_message=false

boot_run_hook preinit_main


在/etc/preinit中首先初始化一些参数,这些参数其实是供hook链上函数调用的,这里不多解释。重要的是五个hook链(名字分别见代码),使用boot_hook_init进行初始化,需要用到/lib/function/boot.sh中的函数,代码如下:

boot_hook_init() {
local hook="${1}_hook" #将链名后带hook后缀
export -n "PI_STACK_LIST=${PI_STACK_LIST:+$PI_STACK_LIST }$hook"
export -n "$hook="
}


这个函数中主要用到了export -n命令, export –n含义是删除指定的环境变量,但并非真正删除,只是在环境变量表中去除了,不能传递给子环境,变量本身还在,在本shell的其他函数中还可调用,相当于要本环境中声明了全局变量。

初始化后去/lib/preinit/目录下依次执行每一个文件,文件太多,且格式相同,我就以标准格式举例,如下:

function_name() {
#TODO
}
boot_hook_add hook_name function_name


前面可以写一个或多个函数,后面使用boot_hook_add加入到对应的hook链中,hook_name是链名,function_name是前面定义的函数。若有多个函数可使用多行boot_hook_add。下面上代码:

boot_hook_add() {
local hook="${1}_hook${PI_HOOK_SPLICE:+_splice}"
local func="${2}"

[ -n "$func" ] && {
local v; eval "v=\$$hook"
export -n "$hook=${v:+$v }$func" #将每个func挂到各自的链上
}
}


将所有函数挂到对应的hook链上后,使用boot_run_hook运行指定链上所有函数。

boot_run_hook() {
local hook="$1"
local func
#下面调用boot_hook_shift,作用是依次执行链上的每一个函数,直到链末。不到链末时一直return 0,即true,当到链末时return 1,即false,while循环结束。
while boot_hook_shift "$hook" func; do
local ran; eval "ran=\$PI_RAN_$func"
[ -n "$ran" ] || {
export -n "PI_RAN_$func=1"
$func "$1" "$2"  #执行函数
}
done
}


boot_hook_run中一个重要的函数如下:

boot_hook_shift() {
local hook="${1}_hook"
local rvar="${2}"

local v; eval "v=\$$hook" #$hook指的是preinit_main_hook(例),而$$hook指的是preinit_main_hook链,其上包含了一串func函数
[ -n "$v" ] && {
local first="${v%% *}"  #每次取出链上的第一个函数

[ "$v" != "${v#* }" ] && \
export -n "$hook=${v#* }" || \
export -n "$hook="

export -n "$rvar=$first" #将第一个函数通过export –n传出,供调用它的函数使用
return 0  #这里很迷惑人,其实shell中函数最后会返回上一个执行命令的返回值(可使用echo $?),也可用return num指定(return只能出现在函数体内),返回值0表示真,即true,非0表示假,即false。
}

return 1
}


下面是各个hook链及挂在上面的函数:

preinit_main_hook define_default_set_state do_ar71xx preinit_enable_reset_button preinit_set_mac_address set_preinit_iface init_tuxera_fs preinit_ip pi_indicate_preinit failsafe_wait run_failsafe_hook indicate_regular_preinit init_hotplug initramfs_test do_mount_root do_load_ath10k_board_bin restore_config load_qos_modules run_init

preinit_mount_root_hook check_for_mtd check_for_jffs2 do_mount_jffs2 do_mount_ubifs merge_overlay_hooks determine_external_root determine_extroot_sysupgrade external_root_pivot rootfs_pivot_jffs2 rootfs_pivot_ubifs do_mount_no_jffs2 do_make_flash_dev do_mount_no_mtd

failsafe_hook indicate_failsafe failsafe_netlogin failsafe_shell

preinit_essential_hook do_mount_procfs do_mount_sysfs do_mount_tmpfs choose_device_fs init_device_fs init_shm init_devpts do_mount_devpts choose_console init_console

preinit_mount_root_hook check_for_mtd check_for_jffs2 do_mount_jffs2 do_mount_ubifs merge_overlay_hooks determine_external_root determine_extroot_sysupgrade external_root_pivot rootfs_pivot_jffs2 rootfs_pivot_ubifs do_mount_no_jffs2

后面讲一下执行的最后一个函数,脚本如下:

#!/bin/sh
# Copyright (C) 2006 OpenWrt.org
# Copyright (C) 2010 Vertical Communications

run_init() {
preinit_echo "- init -"
preinit_ip_deconfig
if [ "$pi_init_suppress_stderr" = "y" ]; then
exec env - PATH=$pi_init_path $pi_init_env $pi_init_cmd 2>&0  #$pi_init_cmd为/sbin/init
else
exec env - PATH=$pi_init_path $pi_init_env $pi_init_cmd
fi
}

boot_hook_add preinit_main run_init


run_init函数处于preinit_main_hook链上,这个函数的功能就是当完成preinit后执行/sbin/init,开始openwrt启动的下一流程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: