openwrt启动流程

来源:互联网 发布:在香港用淘宝 编辑:程序博客网 时间:2024/06/06 09:07

了解Openwrt系统的启动流程
1.1:系统介绍
任何系统的启动都是开发人员首要关注的问题,因为只有了解了系统的启动流程和启动机制,才能真正掌握一个系统,如果对系统的启动不熟悉的话,是不可能用好一个系统的。Openwrt系统也不例外,他的启动和一般的嵌入式系统的启动还有所区别,下面记录一下Openwrt的启动流程。
1.2:内核补丁
在openwrt的官网上面下载的源码,其中包括了一些内核补丁 ,这里究竟为什么要给内核做补丁呢?因为openwrt为了支持更多的路由器,更多的操作和openwrt特有的一些内核功能,linux源码是不具备的,这样openwrt为了增加这些功能,就需要在linux官网下载的源代码中做一些修改,在这里体现为给linux打补丁。
openwrt源码中的linux补丁文件放在$<openwrt_dir>/target/linux/generic/文件下面,有对于不同版本的linux内核补丁。根据采用不同的内核,使用不同的补丁。这些不同的内核补丁文件,在编译openwrt的时候,会首先把他们拷贝到内核目录下面,然后在内核上面打上这些补丁,然后在编译内核。首先分析他对于linux启动的补丁,他的名字是:921-use_preinit_as_init.patch(应该与平台有关),下面是一个实例:

--- a/init/main.c+++ b/int/main.c@@ -844,7 +844,8 @@ static int _ref kernel_init(void *unuse pr_err("Failed to execute %s. Attempting default...\n"),execute_command);}- if(!run_init_process("/sbin/init")||+ if(!run_init_process("/etc/preinit")||!run_init_process("/sbin/init")||!run_init_process("/etc/init")||!run_init_process("/bin/preinit")||!run_init_process("/bin/sh"))
可以看到他修改linux中默认的启动项,可以看到它首先启动“/etc/preinit”.他是一个脚本,咱们就从脚本说起.

!/bin/sh# Copyright (C) 2006 OpenWrt.org# Copyright (C) 2010 Vertical Communications[ -z "$PREINIT" ] && exec /sbin/initexport PATH=/usr/sbin:/usr/bin:/sbin:/binpi_ifname=pi_ip=192.168.1.1pi_broadcast=192.168.1.255pi_netmask=255.255.255.0fs_failsafe_ifname=fs_failsafe_ip=192.168.1.1fs_failsafe_broadcast=192.168.1.255fs_failsafe_netmask=255.255.255.0fs_failsafe_wait_timeout=2pi_suppress_stderr="y"pi_init_suppress_stderr="y"pi_init_path="/usr/sbin:/usr/bin:/sbin:/bin"pi_init_cmd="/sbin/init". /lib/functions.sh. /lib/functions/preinit.sh. /lib/functions/system.shboot_hook_init preinit_essentialboot_hook_init preinit_mainboot_hook_init failsafeboot_hook_init initramfsboot_hook_init preinit_mount_rootfor pi_source_file in /lib/preinit/*; do        . $pi_source_filedoneboot_run_hook preinit_essentialpi_mount_skip_next=false
对于这个bash脚本,前半部分定义了一些变量,先记住他们即可,但是有两个函数需要了解,即:boot_hook_init 和 boot_run_hook 他们的定义在/lib/functions/preinit.sh文件当中,boot_hook_init是初始化一个函数队列,boot_run_hook是运行一个函数队列,有一点该文件没有体现,后面文件当中会遇到,这里说明一下,boot_hook_add这个是在一个函数队列中添加一个函数。然后就是执行:

for pi_source_file in/lib/preinit/*

. $pi_source_file

done

 循环执行/lib/preinit 目录下的一个文件,这里分析02_default_set_state,首先看看他的内容。

#!/bin/sh

define_default_set_state(){

. /etc/diag.h

}

boot_hook_add pre_main define_set_state

可以看到他就是在preinit_main 函数队列中增加一个函数,这个函数就是简单的执行一个脚本。当运行preinit_main 的时候,队列中的所有函数就会一次的执行。其他文件可以自行分析,都比较简单。最后在preini脚本中执行preinit_main。(作为初学者的我并不会。。)执行完这个脚本后init进程会根据inittab文件执行其他的启动项。

1.4inittab分析

inittab为linux初始化文件系统时init初始化文件系统用到的配置文件。这个文件负责设置init初始化程序初始化脚本在哪里;每个运行级初始化时命令的运行;开机,关机,重启对应的命令;个运行级登陆时运行的命令。

如果存在/etc/libtab文件,busybox init程序解析他,然后按照他的知识来创建各种子进程,否则使用默认的配置创建子进程。/etc/libtab 文件中每个条目用来定义一个子进程,并且确定他的启动方法,格式如下:

<id>:<runlevels>:<action>:<process>

1:id:表示这个子进程要用的控制台,如果省略,则使用与init进程一样的控制台。

2:runlevel:这个字段没有意义,可以省略。在linux下是具有意义的。

3:action:表示init进程如何控制这个子进程,下面会给出一个表格

4:process:这个就是我们要执行的可执行程序,当然也可以是一个脚本,如果process字段钱有一个“-”字符,这个程序就被称作是交互的。

名称执行条件说明sysinit系统启动后最先执行指定初始化脚本路径,当然只
执行一次,init进程等待他结束、
继续执行其他的动作。wait 系统执行完sysinit进程之后只执行一次,init进程等待它结束
才继续执行其他动作once 系统执行完wait进程之后只执行一次,init进程不会等待他结束respawn启动完once进程后 init进程检测发现子进程退出时,重新启动他,永不
结束,比如shell命令解释器askfirst启动完respawn进程后 与respawn类似,不过init进程先输出“Please
press enter toactive thisconsole”,等待用户输入
回车后才启动子进程。shutdown当系统关机时及重启。关闭系统时执行的程序restart系统重启时init进程重启时执行的程序,通常是init程序本身先重新读取,解析/etc/initlab文件,在执行restart程序ctrl+alt+del按下ctrl+alt+del按键的时候按下ctrl+alt+del按键的时候执行的程序

下面是我自己的openwrt里的initlab内容:

::sysinit:/etc/init.d/rcS S boot::shutdown:/etc/init.d/rcS K shutdown::askconsole:/bin/ash --login


从上面的分析可以看出它在开机的时候执行的是:/etc/init.d/rcS 脚本,以前是有/etc/init.d/rcS脚本的,但是现在的openwrt已经去掉了这个脚本,只要有rcS S boot这几个参数就可以了,但是功能是有的就是按顺序执行/etc/init.d下面的各个脚本,以S开头代表启动的时候执行的脚本,与命令中的S对应,以K 开头的代表关机时候需要执行的脚本,与命令行中的K对应。

1.5总结

这里就不写了


在没有你的世界里,爱你,叶铮。


0 0
原创粉丝点击