本系列导航:
OpenWRT 启动流程(一) /sbin/init 进程分析
OpenWRT 启动流程(二) /etc/preinit 脚本分析
OpenWRT 启动流程(三) /sbin/procd 分析
前面分析了 /sbin/init 最终是执行了 /etc/preinit 脚本
接着分析 /etc/preinit
同样是围绕下面两个问题:
1./etc/preinit 是怎么来的?
2./etc/preinit 做了些什么?
它来自package/base-files/files/etc/preinit
#!/bin/sh
# Copyright (C) 2006-2016 OpenWrt.org
# Copyright (C) 2010 Vertical Communications
[ -z "$PREINIT" ] && exec /sbin/init
export PATH="/usr/sbin:/usr/bin:/sbin:/bin"
. /lib/functions.sh
. /lib/functions/preinit.sh
. /lib/functions/system.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
先来看几个相关的函数定义,位于/lib/functions/preinit.sh
1.boot_hook_init
2.boot_hook_add
3.boot_hook_shift
4.boot_run_hook
boot_hook_init() {
local hook="${1}_hook"
export -n "PI_STACK_LIST=${PI_STACK_LIST:+$PI_STACK_LIST }$hook"
export -n "$hook="
}
例如:
执行 boot_hook_init preinit_main
环境变量中会有 preinit_main_book=未赋值
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"
}
}
例如:
执行
boot_hook_add preinit_main func1
boot_hook_add preinit_main func2
环境变量中会有 preinit_main_book=func1 func2
boot_hook_shift() {
local hook="${1}_hook"
local rvar="${2}"
local v; eval "v=\$$hook"
[ -n "$v" ] && {
local first="${v%% *}" #取出第一个值
[ "$v" != "${v#* }" ] && \
export -n "$hook=${v#* }" || \ #删除第一个值
export -n "$hook="
export -n "$rvar=$first"
return 0
}
return 1
}
boot_run_hook() {
local hook="$1"
local func
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
}
再回头看/etc/preinit
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
例如:/lib/preinit/02_default_set_state
define_default_set_state() {
. /etc/diag.sh
}
boot_hook_add preinit_main define_default_set_state
将define_default_set_state函数追加到preinit_main_book中
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
/lib/preinit/* 里定义的函数最终在这被调用执行。
那么/etc/preinit 做了些什么?具体就要看/lib/preinit/里的文件了。
/lib/preinit/
├── 00_preinit.conf
├── 02_default_set_state
├── 02_sysinfo
├── 03_b53_hack.sh
├── 10_indicate_failsafe
├── 10_indicate_preinit
├── 30_failsafe_wait
├── 40_run_failsafe_hook
├── 50_indicate_regular_preinit
├── 70_initramfs_test
├── 79_move_config
├── 80_mount_root
├── 81_urandom_seed
├── 99_10_failsafe_login
└── 99_10_run_init