OpenWrt启动过程分析+添加自启动脚本【转】
一、OpenWrt启动过程分析
转自: http://www.eehello.com/?post=107
总结一下OpenWrt的启动流程:1.CFE->2.linux->3./etc/preinit->4./sbin/init ->5./etc/inittab ->6./etc/init.d/rcS->7./etc/rc.d/S* ->8.
OpenWrt是一个开放的linux平台,主要用于带wifi的无线路由上。
类似于Ubuntu、Red Hat、之类的linux发行版本,它也有一套自己的启动流程。下面,我就以我的Linksys 的WRT54G为平台介绍一下,OpenWrt的启动流程。
1.首先,CFE(common firmware environment)--它就是一个bootloader,类似u-boot,redboot之类,有点broadcom公司御用之嫌--
最先启动。它的任务只是创造一个简单的环境,让系统先运行起来。除了能够跳转到特定地址上启动操作系统(如Linux)外,
它还能让你download东西到上面,比如download一个linux,然后启动它。
另外,值得一提的是,CFE在启动之后会有1,2秒的时间等待由tftp上传的内核并烧写到flash上,
这就给一些操作系统损坏但CFE还能工作的"砖头"板一个起死回生的机会。请注意一旦linux启动之后,将由linux全部接管系统,
2.这时候就没CFE什么事情了。唯一的瓜葛是CFE传递给内核一个命令行的参数,这个可以在linux启动起来之后用下面的命令查看:
root@OpenWrt:/# cat /proc/cmdline
console=ttyS0,115200 mtdparts=spi_flash:1m(u-boot)ro,3m(kernel),-(rootfs)
之后,linux系统启动起来了。它使用类似如下的脚本命令来解析cmdline:
for x in $(cat /proc/cmdline); do
case $x in
init=*)
init=${x#init=}
;;
root=*)
ROOT=${x#root=}
case $ROOT in
LABEL=*)
ROOT="/dev/disk/by-label/${ROOT#LABEL=}"
;;
UUID=*)
ROOT="/dev/disk/by-uuid/${ROOT#UUID=}"
;;
esac
;;
rootflags=*)
ROOTFLAGS="-o ${x#rootflags=}"
;;
cryptopts=*)
cryptopts="${x#cryptopts=}"
;;
nfsroot=*)
NFSROOT="${x#nfsroot=}"
;;
nfsopts=*)
NFSOPTS="-o ${x#nfsopts=}"
;;
boot=*)
BOOT=${x#boot=}
;;
resume=*)
RESUME=${x#resume=}
;;
noresume)
NORESUME=y
;;
quiet)
quiet=y
;;
ro)
readonly=y
;;
rw)
readonly=n
;;
debug)
debug=y
exec >/tmp/initramfs.debug 2>&1
set -x
;;
break=*)
break=${x#break=}
;;
break)
break=premount
;;
esac
done
对于OpenWrt这个cmdline的意思就是:root=/dev/mtdblock2 文件系统在第三个flash分区上(mtdblock0,1,2);
rootfstype=squashfs,jffs2 文件系统类型是squashfs和jffs2(为什么两种类型,目前还不清楚,
不过可以确定OpenWrt使用了较为复杂的文件系统,实现了squashfs的压缩和jffs2的可写 );
init=/etc/preinit 执行该初始化,noinitrd console=ttyS0,115200
没有initrd和console口设定。
3.
init=/etc/preinit 是linux会执行的初始化,具体内容如下:
root@OpenWrt:/# cat /etc/preinit
#!/bin/sh
# Copyright (C) 2006 OpenWrt.org
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
. /etc/diag.sh
failsafe_ip() {
ifconfig $ifname 192.168.1.1 netmask 255.255.255.0 broadcast 192.168.1.2 55 up
}
failsafe() {
[ -n "$ifname" ] && grep "$ifname" /proc/net/dev >/dev/null && {
failsafe_ip
netmsg 192.168.1.255 "Entering Failsafe!"
telnetd -l /bin/login <> /dev/null 2>&1
}
lock /tmp/.failsafe
ash --login
}
mount proc /proc -t proc
mount sysfs /sys -t sysfs
size=$(awk '/MemTotal:/ {l=5242880;mt=($2*1024);print((s=mt/2)<l)&&(mt>l)?mt-l:s }' /proc/meminfo)
mount tmpfs /tmp -t tmpfs -o size=$size,nosuid,nodev,mode=1777
if grep devfs /proc/filesystems > /dev/null; then
mount devfs /dev -t devfs
M0=/dev/pty/m0
M1=/dev/pty/m1
HOTPLUG=/sbin/hotplug-call
elif [ -x /sbin/hotplug2 ]; then
mount -t tmpfs tmpfs /dev -o size=512K
mknod /dev/console c 5 1
/sbin/hotplug2 --coldplug --set-rules-file /etc/hotplug2-init.rules
/sbin/hotplug2 --no-coldplug --persistent --set-rules-file /etc/hotplug2 -init.rules &
M0=/dev/ptmx
M1=/dev/ptmx
HOTPLUG=
elif [ -x /sbin/udevd ]; then
mount -n -t tmpfs -o mode=0755 udev /dev
/sbin/udevd --daemon
/sbin/udevtrigger
/sbin/udevsettle
M0=/dev/pty/ptmx
M1=/dev/pty/ptmx
HOTPLUG=
fi
mkdir -p /dev/pts /dev/shm
mount devpts /dev/pts -t devpts
# the shell really doesn't like having stdin/out closed
# that's why we use /dev/pty/m0 and m1 as replacement
# for /dev/console if there's no serial console available
dd if=/dev/console of=/dev/null bs=1 count=0 >/dev/null 2>/dev/null && {
M0=/dev/console
M1=/dev/console
}
exec <$M0 >$M1 2>&0
echo "- preinit -"
echo "Press CTRL-C for failsafe"
trap 'FAILSAFE=true' INT
trap 'FAILSAFE=true' USR1
[ -e /etc/preinit.arch ] && . /etc/preinit.arch
set_state preinit
echo "$HOTPLUG" > /proc/sys/kernel/hotplug
eval ${FAILSAFE:+failsafe}
lock -w /tmp/.failsafe
if [ -z "$INITRAMFS" ]; then
mount_root
[ -f /sysupgrade.tgz ] && {
echo "- config restore -"
cd /
mv sysupgrade.tgz /tmp
tar xzf /tmp/sysupgrade.tgz
rm -f /tmp/sysupgrade.tgz
sync
}
echo "- init -"
exec /sbin/init
fi
可见,它主要是挂载一些系统需要的文件系统,例如tmpfs,proc和sysfs(是否真正挂载取决于内核是否2.6的)。
并且会准备设备节点和故障恢复(failsafe)的准备。(这里还没看懂 )
4.
最后,exec /sbin/init启动文件系统,在OpenWrt上也就是busybox的init程序。
它会自动分析/etc/inittab这个文件,其内容解释详见busybox网站的cmd help。
5.
/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
6.
运行/etc/init.d/rcS:
#!/bin/sh
# Copyright (C) 2006 OpenWrt.org
run_scripts() {
for i in /etc/rc.d/$1*; do
[ -x $i ] && $i $2 2>&1
done | $LOGGER
}
LOGGER="cat"
[ -x /usr/bin/logger ] && LOGGER="logger -s -p 6 -t sysinit"
if [ "$1" = "S" ]; then
run_scripts "$1" "$2" &
else
run_scripts "$1" "$2"
fi
7.
将执行/etc/rc.d/S*这些脚本:
root@OpenWrt:/# ls /etc/rc.d/S*
/etc/rc.d/S10boot
/etc/rc.d/S50cron
/etc/rc.d/S60led
/etc/rc.d/S20fstab
/etc/rc.d/S50dropbear
/etc/rc.d/S95done
/etc/rc.d/S39usb
/etc/rc.d/S50uhttpd
/etc/rc.d/S97watchdog
/etc/rc.d/S40network
/etc/rc.d/S50telnet
/etc/rc.d/S99sysctl
/etc/rc.d/S45firewall /
etc/rc.d/S60dnsmasq
按照数字从小到大的顺序执行。
二、实现自启动脚本
OpenWRT的启动脚本放在 /etc/init.d 目录下,而系统开机时自动运行/etc/rc.d目录下的脚本。所以在rc.d目录下、有init.d下脚本的链接文件。
整理一下
05 defconfig //加载默认参数
10 boot //启动
39 usb // 加载usbfs
40 network // 设置网卡参数
45 firewall // 防火墙
50 dropbear // sshd server
50 cron // .....
50 telnet // 如果没有修改root密码,则启动telnet server
60 dnsmasq // DHCP 和 DNS 服务端
95 done // ...
96 led // 指示灯
97 watchdog // ...
99 sysctl // 最后,进行必要的内核参数调整
然后,我们加入自己的脚本,实现模块驱动的加载、应用程序的开机自启动等。
首先在/etc/init.d里添加需要启动的shell脚本
例如:
vim startCamera
内容:
之后还需要在rc.d目录下做一个链接,启动时系统会按顺序启动rc.d目录下的脚本链接,对应执行init.d目录下的启动脚本。脚本的命名要符合系统规范,init.d下telnet脚本在rc.d目录下的链接文件名为S50telnet。所以链接文件要在脚本名前加S+启动顺序数字,启动顺序要等系统进行完必要的初始化。所以我们命名为S95+脚本名。
命令:ln -s /etc/init.d/startCamera /etc/rc.d/S95startCamera
重启,即可
现在实现了应用程序的开机自启动。
OpenWrt启动过程分析+添加自启动脚本【转】的更多相关文章
- OpenWrt启动过程分析
openwrt是通过一系列shell脚本进行启动流程的组织,下面是启动流程的提纲.如 果想详细了解启动的过程,则需要仔细走读脚本文件. 1. 在make menuconfig 选择target平台 B ...
- linux 开机自启动脚本
在/etc/rc.local文件中添加自启动命令(其中一种方法) 1.案例,就用博主本人之前发的博文 “nginx + flask + uwsgi + centos + python3 搭建web项目 ...
- linux添加开机自启动脚本示例详解
linux下(以RedHat为范本)添加开机自启动脚本有两种方法,先来简单的; 一.在/etc/rc.local中添加如果不想将脚本粘来粘去,或创建链接什么的,则:step1. 先修改好脚本,使其所有 ...
- 转载:ubuntu 下添加简单的开机自启动脚本
转自:https://www.cnblogs.com/downey-blog/p/10473939.html linux下添加简单的开机自启动脚本 在linux的使用过程中,我们经常会碰到需要将某个自 ...
- openwrt启动过程(脚本)
来源: http://wiki.openwrt.org/doc/techref/preinit_mount#first.boot 基本的openwrt启动顺序为: 1.boot loader loa ...
- openwrt 为软件包添加服务
手动修改 rc.local 加入也可以实现自启动,缺点手动修改太麻烦,停止只能用 kill . 配置成服务最方便了,可以启用或禁用,启动,停止,重启非常方便. 在openwrt 中使用服务 servi ...
- 【转】linux 编译安装nginx,配置自启动脚本
linux 编译安装nginx,配置自启动脚本 本文章来给各位同学介绍一篇关于linux 编译安装nginx,配置自启动脚本教程,希望有需要了解的朋友可一起来学习学习哦. 在公司的suse服务器装ng ...
- linux 编译安装nginx,配置自启动脚本
本文章来给各位同学介绍一篇关于linux 编译安装nginx,配置自启动脚本教程,希望有需要了解的朋友可一起来学习学习哦. 在公司的suse服务器装nginx,记录下安装过程: 参照这篇文章:Linu ...
- Ubuntu14.04设置开机自启动脚本
方法一.编辑rc.loacl脚本 Ubuntu开机之后会执行/etc/rc.local文件中的脚本,所以我们可以直接在/etc/rc.local中添加启动脚本.在 exit 0 前面添加好脚本代码, ...
随机推荐
- 【BZOJ4712】洪水(动态dp)
[BZOJ4712]洪水(动态dp) 题面 BZOJ 然而是权限题QwQ,所以粘过来算了. Description 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开 ...
- 洛谷 CF55D Beautiful numbers 解题报告
CF55D Beautiful numbers 题意 \(t(\le 10)\)次询问区间\([l,r](1\le l\le r\le 9\times 10^{18})\)中能被每一位上数整除的数的个 ...
- 用selenium获取cookies
前言:由于登录反爬措施的越来越麻烦,甚至出现了12306这种看图识物的无敌验证码,我只能说,我选择死亡.这就衍生出了使用selenium来获取获取cookies. 实例:获取qq空间cookies,亲 ...
- 隐藏技能go:linkname
来源:https://blog.csdn.net/lastsweetop/article/details/78830772 什么是go:linkname 指令的格式如下: //go:linkname ...
- GNOME Shell Extension常用扩展
这篇博文的,主要目的是为了方便我和大家安装GNOME扩展.我将我安装过的所有扩展列在此处. 常用扩展 Clipboard Indicator https://extensions.gnome.org/ ...
- [NOI2009]二叉查找树
题目大意: 给定一棵严格的treap,父亲节点的优先级必然小于儿子节点的.权值按照二叉树的定义,左儿子小于父亲小于右儿子. 深度从1开始定义,每个点除优先级.数值之外,还有一个访问频度. 访问频度所产 ...
- Vagrant工具的安装
Vagrant工具的安装 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 这篇博客源于我的北京一位好友:崔佳.在此,为了感激崔佳的帮助,特意写下这篇博客.希望对一些开发的小伙伴有些帮 ...
- nginx: [warn] duplicate MIME type "text/html"错误
检查配置文件时提示:nginx: [warn] duplicate MIME type "text/html" in /home/web/nginx/inc/gzip.conf:9 ...
- MYSQL增加tmp_table_size 的操作
最近有张表经常损坏,修复后还是会出现损坏. dba分析有可能是临时表空间太小导致的.以下是设置临时表空间大小的操作. 设置 tmp_table_size的大小 mysql> set global ...
- synchronized实现原理
线程安全是并发编程中的重要关注点,应该注意到的是,造成线程安全问题的主要诱因有两点,一是存在共享数据(也称临界资源),二是存在多条线程共同操作共享数据.因此为了解决这个问题,我们可能需要这样一个方案, ...