Tomato的init启动流程分析(原创)

1.首先,路由器的启动有多种不同的阶段。

通电后,最先执行的CFE启动,CFE完成基本初始化后,把系统交给linux内核。

而linux内核也有一个初始化过程,比如文件系统啊,内存管理啊,系统资源调度啊,等等。

Linux内核初始化完成后,就执行系统的第1个进程init。本文所讲的启动流程是从init进程开始执行,路由器是如何运行的。

 

2.从主函数开始。init进程的主函数是 $(ROUTER)/rc/init.c 文件中的init_main( )函数。

注:为什么是init_main而不是main呢?这是因为init进程实际上链接到rc程序的,运行 ls -l /sbin/init就可以看到的。

从init_main( )开始,基本上就2个过程,先执行一些初始化,比如校验某些关键的nvram参数,加载驱动,设置某些内核参数等。

这些主要是由函数sysinit( )完成的。

然后就是信号集初始化,最后是一个for (;;)死循环,这里面完成各种路由器页面的功能,完成之后等待新的信号到来再次执行不同的服务。

(1)sysinit( )部分

加载驱动,设置内核参数以及某些相关的初始化就不说了,我们主要关注其中校验nvram参数的部分。与之有关的函数有2个,check_bootnv( )和init_nvram( )。

初看起来,这2个函数里貌似都有对nvram参数的操作,那是否可以随便使用呢?

答案是否定的。经过试验就会发现,如果在check_bootnv( )中修正某些nvram变量的默认值,会不起作用,什么原因呢?

而在init_nvram( )修改VLAN参数,在恢复出厂设置后的第1次启动,VLAN并没有生效,什么原因呢?

答案是:

check_bootnv( )是检查启动相关参数的,而init_nvram( )是修改初始化nvram参数的。

check_bootnv( )和底层关系更紧密一些,init_nvram( )和应用层的关系更紧密。

首先理解:系统恢复出厂设置后第1次启动的时候,nvram存储的只有CFE中的那些明文的nvram变量的,$(ROUTER)/nvram/defaults.c中的那个长长的结构体数组中的很多nvram变量都是没有的,所以需要有一个设置默认值的过程。

 

eval("nvram", "defaults", "--initcheck");

上面这一句就是设置出厂默认nvram值。这一句在check_bootnv( )之后并且在init_nvram( )之前执行。

追踪到$(ROUTER)/nvram/nvram.c文件的defaults_main( )函数,可以发现:

如果是恢复出厂设置后第1次启动,必然是force = 1的(原因自己看代码)。

既然force = 1,那很多nvram变量就被恢复成.../router/nvram/defaults.c中的默认值了。

 

至于在init_nvram( )中修改VLAN参数首次启动路由器的时候vlan不生效,那是因为驱动的加载是在init_nvram( )之前。

BCM驱动虽然没有开放源码,但是肯定是会读取某些nvram参数的。

结论:

不要在check_bootnv( )中修改defaults.c中的默认变量,最好是放到init_nvram( )去修改。

但是,如果要在init_nvram( )修改和vlan有关的变量以及系统底层驱动有关的变量,那最好是修改完成后执行nvram_commit( )后多重启1次。

 

(2)for循环部分

前面的代码好理解,搞一个switch检测不同的信号值,执行不同的动作。难理解的是最后3句:

 

1         chld_reap(0);        /* Periodically reap zombies. */
2        check_services();
3         sigwait(&sigset, &state);

 

第1句是回收某些子进程产生的僵尸进程(init进程是整个系统其他进程的祖宗啊)。

第2句是检测下面4个系统服务,如果异常终止,自动重启。现在就不用奇怪dnsmasq进程为啥kill干不掉了^_^。

而第3句sigwait(&sigset, &state)就很费解了^_^。这个可以自己baidu下。baidu上的那些人讲了很多废话^_^。其实在toamto里就是:监测系统信号集的变化(异步监测),如果信号集中的信号发生变化,就执行相应的信号动作,并且进一步执行返回到for循环开头执行,否则就一直休眠在那里等待直到信号集中的信号到来(这个和socket编程的select机制有点类似吧)。

比如dnsmasq异常退出了(比如被你人为干掉了)系统肯定会有SIGCHLD信号产生的,追踪到SIGCHLD信号的处理函数signal(SIGCHLD, handle_reap)--------------raise(SIGALRM),而SIGALRM是在所监视的信号集合中的。

init进程的信号集定义如下:

 

static int initsigs[] = {
    SIGHUP,
    SIGUSR1,
    SIGUSR2,
    SIGINT,
    SIGQUIT,
    SIGALRM,
    SIGTERM
};

 

至此toamto得init启动流程分析完毕,主要分析了其中比较难理解的部分,其它部分代码,基本看函数和变量命名就能猜出干啥的^_^。

 

 

转载于:https://www.cnblogs.com/bank/p/3618312.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值