zoukankan      html  css  js  c++  java
  • 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

    内容:

    #!/bin/sh /etc/rc.common
    # /init.d/startCamera
    START=50
    start()
    {
    ./opt/ipnc/system_server &
    }
    stop()
    {
    killallsystem_server
    }

    之后还需要在rc.d目录下做一个链接,启动时系统会按顺序启动rc.d目录下的脚本链接,对应执行init.d目录下的启动脚本。脚本的命名要符合系统规范,init.d下telnet脚本在rc.d目录下的链接文件名为S50telnet。所以链接文件要在脚本名前加S+启动顺序数字,启动顺序要等系统进行完必要的初始化。所以我们命名为S95+脚本名。

    命令:ln -s /etc/init.d/startCamera /etc/rc.d/S95startCamera

    重启,即可

    现在实现了应用程序的开机自启动。

  • 相关阅读:
    Mayan游戏 (codevs 1136)题解
    虫食算 (codevs 1064)题解
    靶形数独 (codevs 1174)题解
    黑白棋游戏 (codevs 2743)题解
    神经网络 (codevs 1088) 题解
    The Rotation Game (POJ 2286) 题解
    倒水问题 (codevs 1226) 题解
    银河英雄传说 (codevs 1540) 题解
    生日蛋糕 (codevs 1710) 题解
    第一章 1.11 高阶函数
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/4515759.html
Copyright © 2011-2022 走看看