本文以mtk7628n openwrt为软件环境进行分析
在linux的发展过程中,linux的启动程序也在发展,从sysv init到现在的upstart、systemd,通常该程序是进程号为1的进程,该程序在linux系统有着举足轻重的地方。在openwrt中,使 用了另外一种启动程序叫做procd,本文的重点并不在于介绍procd,本文主要介绍并解析procd、preinit及各种脚本如何完成整个系统的初始化。
位于linux-3.3.8/init/main.c
汇编语言 b star_kernel----->start_kernel()--->rest_init()–→kernel_init()--→init_post()
重点分析init_post()函数
在openwrt系统中一般都会通过patch方式对源码进行修改,而对于init_post()函数,
但是在QCA9531平台启动内核启动的代码中会作出如下修改,target/linux/generic/patches-3.4/921-use_preinit_as_init.patch
删除了默认的启动方式,直接启动/etc/preinit。
我们只分析mtk7628n平台的,从代码中可以看到init_post函数要启动init进程
./build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/procd-2014-09-15/initd/init.c
./build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/procd-2014-09-15/initd/early.c
/proc
/sys
/tmp
/dev
/dev/pts
目录(early_mount)./build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/procd-2014-09-15/initd/preinit.c
/sbin/init进程是来自procd这个package里面的,不再使用busybox了,而且它是从内核调用过来的,所以它的pid是1,pid 0是内核本身。fork创建父子进程,子进程做一些procd的配置后退出,注意这时procd并不算真正起来,它的pid不是1;父进程继续创建父子进程,
子进程调用/etc/preinit后退出。在这过程中/sbin/init的pid为1,始终没有让位。
创建子进程执行/etc/preinit脚本时,此时PREINIT环境变量被设置为1,主进程(pid=1)同时使用uloop_process_add()把/etc/preinit子进程加入uloop进行监控,当/etc/preinit执行结束时回调plugd_proc_cb()函数把监控/etc/preinit进程对应对象中pid属性设置为0,表示/etc/preinit已执行完成
创建子进程执行/sbin/procd -h/etc/hotplug-preinit.json,主进程同时使用uloop_process_add()把/sbin/procd子进程加入uloop进行监控,当/sbin/procd进程结束时回调spawn_procd()函数,spawn_procd()函数繁衍后继真正使用的/sbin/procd进程,这时procd的进程号将是1。
下面这个函数会用procd将/sbin/init进程替换,从而procd的进程号为1:
最终大家在openwrt环境中看到的进程运行结果是
build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/procd-2014-09-15/state.c
procd有5个状态,分别为STATE_EARLY
、STATE_INIT
、STATE_RUNNING
、STATE_SHUTDOWN
、STATE_HALT
,这5个状态将按顺序变化,当前状态保存在全局变量state
中,可通过procd_state_next()
函数使用状态发生变化
STATE_EARLY
转变为STATE_INIT
main_object
对象,system_object
对象、watch_event
对象(procd_connect_ubus()函数),respawn
、askconsole
、askfirst
、sysinit
命令STATE_INITl
转变为STATE_RUNNING
STATE_RUNNING
状态后procd运行uloop_run()
主循环
https://wiki.openwrt.org/doc/techref/process.boot
S开头的表示要启动的
K开头表示要杀掉的
根据数字顺序表示启动顺序
https://wiki.openwrt.org/doc/techref/start