Openwrt 启动过程

官方参考:

http://wiki.openwrt.org/doc/techref/process.boot

http://see.sl088.com/wiki/Openwrt_%E5%90%AF%E5%8A%A8%E8%BF%87%E7%A8%8B

 

Jump to: navigation, search

更多研究

Openwrt 启动过程/WR703N Openwrt 启动过程/preinit Openwrt 启动过程/启动脚本
Openwrt 启动过程/复位按钮机制 Openwrt 启动过程/安全模式等待时间 Openwrt 启动过程/预初始化
Openwrt 启动过程/预初始化/调试进入failsafe

想法

  • 将这个过程延长
  • 实现一种傻瓜化的强烈重置做法
  • 当第一次从TP刷写为Openwrt的时候看起来会执行一个firstboot的玩意

有趣

  • 这是启动逻辑
  • 看起来正常init里的rc.d里的玩意启动顺序的决定是
K${STOP}和S${START}

WR703N中的情况

相关文件探索

预处理preinit

  • 预处理preinit
看起来脚本位于:/etc/preinit
[Expand]

preinit的源码

  1. #!/bin/sh
  2. # Copyright (C) 2006 OpenWrt.org
  3. # Copyright (C) 2010 Vertical Communications
  4.  
  5. export PATH=/bin:/sbin:/usr/bin:/usr/sbin
  6.  
  7. pi_ifname=
  8. pi_ip=192.168.1.1
  9. pi_broadcast=192.168.1.255
  10. pi_netmask=255.255.255.0
  11.  
  12. fs_failsafe_ifname=
  13. fs_failsafe_ip=192.168.1.1
  14. fs_failsafe_broadcast=192.168.1.255
  15. fs_failsafe_netmask=255.255.255.0
  16.  
  17. fs_failsafe_wait_timeout=2
  18.  
  19. pi_suppress_stderr="y"
  20. pi_init_suppress_stderr="y"
  21. pi_init_path="/bin:/sbin:/usr/bin:/usr/sbin"
  22. pi_init_cmd="/sbin/init"
  23.  
  24. . /lib/functions.sh
  25. . /lib/functions/boot.sh
  26.  
  27. boot_hook_init preinit_essential
  28. boot_hook_init preinit_main
  29. boot_hook_init failsafe
  30. boot_hook_init initramfs
  31. boot_hook_init preinit_mount_root
  32.  
  33. for pi_source_file in /lib/preinit/*; do
  34.     . $pi_source_file
  35. done
  36.  
  37. boot_run_hook preinit_essential
  38.  
  39. pi_mount_skip_next=false
  40. pi_jffs2_mount_success=false
  41. pi_failsafe_net_message=false
  42.  
  43. boot_run_hook preinit_main
  • 有趣的是有一个安全模式等待时间
fs_failsafe_wait_timeout 2
默认看起来是两秒左右
  • 另外一个有趣的是可以手动执行它来看看效果
/etc/preinit
大概灯会开始一直闪,这说明灯的驱动里有闪烁的玩意
  • 在源码中的位置看起来是
/package/base-files/files/lib/preinit

failsafe模式细节

  • 所在源码位置看起来接近于
trunk/target/linux/x86/base-files/lib/preinit
  • 在编译后已经运作的Openwrt里能看到它吗,是的
cat /lib/preinit/30_failsafe_wait
[Expand]

failsafe的源码

  1. #!/bin/sh
  2. # Copyright (C) 2006-2010 OpenWrt.org
  3. # Copyright (C) 2010 Vertical Communications
  4.  
  5. fs_wait_for_key () {
  6.     local timeout=$3
  7.     local timer
  8.     local do_failsafe
  9.     local keypress_true="$(mktemp)"
  10.     local keypress_wait="$(mktemp)"
  11.     local keypress_sec="$(mktemp)"
  12.     if [ -z "$keypress_wait" ]; then
  13.         keypress_wait=/tmp/.keypress_wait
  14.         touch $keypress_wait
  15.     fi
  16.     if [ -z "$keypress_true" ]; then
  17.         keypress_true=/tmp/.keypress_true
  18.         touch $keypress_true
  19.     fi
  20.     if [ -z "$keypress_sec" ]; then
  21.         keypress_sec=/tmp/.keypress_sec
  22.         touch $keypress_sec
  23.     fi
  24.  
  25.     trap "echo 'true' >$keypress_true; lock -u $keypress_wait ; rm -f $keypress_wait" INT
  26.     trap "echo 'true' >$keypress_true; lock -u $keypress_wait ; rm -f $keypress_wait" USR1
  27.  
  28.     [ -n "$timeout" ] || timeout=1
  29.     [ $timeout -ge 1 ] || timeout=1
  30.     timer=$timeout
  31.     lock $keypress_wait
  32.     {
  33.         while [ $timer -gt 0 ]; do
  34.             echo "$timer" >$keypress_sec
  35.             timer=$(($timer - 1))
  36.             sleep 1
  37.         done
  38.         lock -u $keypress_wait
  39.         rm -f $keypress_wait
  40.     } &
  41.  
  42.     echo "Press the [$1] key and hit [enter] $2"
  43.     # if we're on the console we wait for input
  44.     { 
  45.         while [ -r $keypress_wait ]; do
  46.             timer="$(cat $keypress_sec)"
  47.  
  48.             [ -n "$timer" ] || timer=1
  49.             timer="${timer%%\ *}"
  50.             [ $timer -ge 1 ] || timer=1
  51.             do_failsafe=""
  52.             {
  53.                 read -t "$timer" do_failsafe
  54.                 if [ "$do_failsafe" = "$1" ]; then
  55.                     echo "true" >$keypress_true
  56.                     lock -u $keypress_wait
  57.                     rm -f $keypress_wait
  58.                 fi
  59.             }
  60.         done
  61.     }
  62.     lock -w $keypress_wait
  63.  
  64.     trap - INT
  65.     trap - USR1
  66.  
  67.     keypressed=1
  68.     [ "$(cat $keypress_true)" = "true" ] && keypressed=0
  69.     rm -f $keypress_true
  70.     rm -f $keypress_wait
  71.     rm -f $keypress_sec
  72.  
  73.     return $keypressed
  74. }
  75.  
  76. failsafe_wait() {
  77.     FAILSAFE=
  78.     pi_failsafe_net_message=true
  79.     preinit_net_echo "Please press button now to enter failsafe"
  80.     pi_failsafe_net_message=false
  81.     fs_wait_for_key f 'to enter failsafe mode' $fs_failsafe_wait_timeout && FAILSAFE=true && export FAILSAFE
  82. }
  83.  
  84. boot_hook_add preinit_main failsafe_wait

启动复位按钮

  • 看起来和这里有关系
/lib/preinit/05_enable_reset_button_ar71xx
#
# Copyright (C) 2009 OpenWrt.org
#
 
. /lib/ar71xx.sh
 
 
preinit_enable_reset_button() {
        insmod gpio-button-hotplug
}
 
boot_hook_add preinit_main preinit_enable_reset_button

困扰

已失去困扰

  • 修改等待时间到10,看起来也没啥作用
fs_failsafe_wait_timeout 10
[后来][猜想] /lib/00_preinit.conf 还作用着哩!

随意见识

Slboat ios6 2013-2-27 23.18.18 0.jpg

音频想法


  • openwrt的启动过程可以控制的很多,可以控制的很细节,甚至可以实现这种长按按钮的初始化这也是可以的
    问题看起来在于注入的时候需要一个启动到达载入点

  • openwrt的启动没有完毕的时候,如果执行nfrap之类的命令会失败,因为此时还没有初始化那些东西.
[后来-354天后]->[混沌]nfrap,听起来完全没有这东西.
[后来-354天后]->[文字]感觉,感觉是最大的幻觉,你感觉什么?你已经在幻觉什么了,你想抓住什么?你已经失去了所有了!

见识

backfire/target/linux/x86/base-files/lib/preinit 中的 45_failsafe_x86 – openwrt-dreambox 沿途见识[1]

failsafe_wait() {
	    FAILSAFE=
	    grep -q 'failsafe=' /proc/cmdline && FAILSAFE=true && export FAILSAFE
	    if [ "$FAILSAFE" != "true" ]; then
	        preinit_net_echo "Please press button now to enter failsafe"
	        fs_wait_for_key f 'to enter failsafe mode' $fs_failsafe_wait_timeout && FAILSAFE=true && export FAILSAFE
	    fi
	}

openwrt启动脚本分析_chou_o_ning-ChinaUnix博客 沿途见识[2]

openwrt是通过一系列shell脚本进行启动流程的组织,下面是启动流程的提纲。如
果想详细了解启动的过程,则需要仔细走读脚本文件。

1. 在make menuconfig 选择target平台 Broadcom BCM947xx/953xx [2.4]

2. linux内核的配置文件由下面两个文件组成
target/linux/generic-2.4/config-default
target/linux/brcm-2.4/config-default

3. 在配置文件中可以看到
CONFIG_CMDLINE="root=/dev/mtdblock2 rootfstype=squashfs,jffs2
init=/etc/preinit noinitrd console=ttyS0,115200"
因此,linux内核启动后,首先运行/etc/preinit脚本

4. preinit脚本位置在
package/base-files/files/etc/preinit

5. preinit脚本是一系列脚本的入口,这一系列脚本放在下面的目录:
package/base-files/files/lib/preinit
target/linux/brcm-2.4/base-files/lib/preinit
编译完成后,会统一放在rootfs的/lib/preinit目录下,
03_init_hotplug_failsafe_brcm 40_init_shm
05_failsafe_config_switch_brcm 40_mount_devpts
05_init_interfaces_brcm 40_mount_jffs2
05_mount_skip 40_run_failsafe_hook
05_set_failsafe_switch_brcm 41_merge_overlay_hooks
10_check_for_mtd 50_choose_console
10_essential_fs 50_indicate_regular_preinit
10_indicate_failsafe 60_init_hotplug
10_indicate_preinit 70_initramfs_test
15_mount_proc_brcm 70_pivot_jffs2_root
15_set_preinit_interface_brcm 80_mount_root
20_check_jffs2_ready 90_init_console
20_device_fs_mount 90_mount_no_jffs2
20_failsafe_net_echo 90_restore_config
20_failsafe_set_boot_wait_brcm 99_10_failsafe_login
30_device_fs_daemons 99_10_mount_no_mtd
30_failsafe_wait 99_10_run_init
由于脚本众多,因此openwrt的设计者将这些脚本分成下面几类:
preinit_essential
preinit_main
failsafe
initramfs
preinit_mount_root
每一类函数按照脚本的开头数字的顺序运行。

6. preinit则执行下面的两类脚本
boot_run_hook preinit_essential
boot_run_hook preinit_main

7. preinit执行的最后一个脚本为99_10_run_init,运行
exec env - PATH=$pi_init_path $pi_init_env $pi_init_cmd
pi_init_cmd为
pi_init_cmd="/sbin/init"
因此开始运行busybox的init命令

8. busybox的init命令执行inittab的脚本,该脚本来自
package/base-files/files/etc/inittab
sysinit:/etc/init.d/rcS S boot
shutdown:/etc/init.d/rcS K stop
tts/0::askfirst:/bin/ash --login
ttyS0::askfirst:/bin/ash --login
tty1::askfirst:/bin/ash --login
sysinit为系统初始化运行的 /etc/init.d/rcS S boot脚本
shutdown为系统重启或关机运行的脚本
tty开头的是,如果用户通过串口或者telnet登录,则运行/bin/ash --login
askfirst和respawn相同,只是在运行前提示"Please press Enter to activate
this console."

9. 当前启动转到运行 /etc/init.d/rcS S boot,该脚本来自
package/base-files/files/etc/init.d/rcS
和preinit类似,rcS也是一系列脚本的入口,其运行/etc/rc.d目录下S开头的的所
有脚本(如果运行rcS K stop,则运行K开头的所有脚本)
K50dropbear S02nvram S40network S50dropbear S96led
K90network S05netconfig S41wmacfixup S50telnet S97watchdog
K98boot S10boot S45firewall S60dnsmasq S98sysntpd
K99umount S39usb S50cron S95done S99sysctl
上面的脚本文件来自:
package/base-files/files/etc/init.d
target/linux/brcm-2.4/base-files/etc/init.d
还有一些脚本来自各个模块,在install时拷贝到rootfs,比如dropbear模块
package/dropbear/files/dropbear.init
这些脚本先拷贝到/etc/init.d下,然后通过/etc/rc.common脚本,将init.d的脚
本链接到/etc/rc.d目录下,并且根据 这些脚本中的START和STOP的关键字,添加
K${STOP}和S${START}的前缀,这样就决定了脚本的先后的运行次序。

10.可以看出,openwrt的启动主要是两个阶段,preinit主要是完成系统的初始化
(如文件系统的准备、模块的加载),rcS主要依次 启动各个模块。

附:脚本走读的一些技巧
a. rootfs目录在build_dir/target-mipsel_uClibc-0.9.30.1/root-brcm-2.4,可以直接在该目录下走读shell脚本。
b. openwrt的shell脚本比较复杂,因此看脚本时可以通过添加 set -x和echo等命令,直接看shell脚本的结果,而不要花太多的时间硬看脚本,主要是理解其主要的意思和设计思路。

引用信息

以下是[Openwrt 启动过程]所有用到的引用信息,向这些伟大的家伙致敬:
    1. Jump up ^ https://dev.openwrt.org.cn/browser/backfire/target/linux/x86/base-files/lib/preinit/45_failsafe_x86?rev=1
    2. Jump up ^ http://blog.chinaunix.net/uid-26598889-id-3060545.html
posted @ 2015-01-26 23:13  fastwave2004  阅读(1318)  评论(0编辑  收藏  举报