OpenWRT 启动流程(一) /sbin/init 进程分析

本系列导航:
OpenWRT 启动流程(一) /sbin/init 进程分析
OpenWRT 启动流程(二) /etc/preinit 脚本分析
OpenWRT 启动流程(三) /sbin/procd 分析

OpenWRT /sbin/init 进程分析

之前分析内核启动流程,知道了内核加载完根文件系统后启动的第一个进程是/sbin/init

if (!try_to_run_init_process("/sbin/init") ||
	    !try_to_run_init_process("/etc/init") ||
	    !try_to_run_init_process("/bin/init") ||
	    !try_to_run_init_process("/bin/sh"))

接下来分析一下/sbin/init 进程。
围绕以下两个问题:
1./sbin/init 怎么来的?
2./sbin/init 做了些什么?

1./sbin/init 怎么来的?
一般是来自busybox,但是这里面的不是(因为一般busybox来的会是指向/bin/busybox的软连接)。那它到底从哪里来的呢?
openwrt /sbin/init
找到一个可能的地方,procd

root@localhost:/home2/lql/openwrt/build_dir# find . -name init
...省略...
./target-arm_cortex-a7+neon-vfpv4_musl_eabi/procd-2018-03-28-dfb68f85/ipkg-install/usr/sbin/init
./target-arm_cortex-a7+neon-vfpv4_musl_eabi/procd-2018-03-28-dfb68f85/.pkgdir/procd/sbin/init
./target-arm_cortex-a7+neon-vfpv4_musl_eabi/procd-2018-03-28-dfb68f85/ipkg-arm_cortex-a7_neon-vfpv4/procd/sbin/init
./target-arm_cortex-a7+neon-vfpv4_musl_eabi/procd-2018-03-28-dfb68f85/init
./target-arm_cortex-a7+neon-vfpv4_musl_eabi/root.orig-sunxi/sbin/init
root@localhost:/home2/lql/openwrt/build_dir# 

2./sbin/init 做了些什么?
那么来看一下procd 的源码。

initd/init.c

int
main(int argc, char **argv)
{
	pid_t pid;

	ulog_open(ULOG_KMSG, LOG_DAEMON, "init");

	sigaction(SIGTERM, &sa_shutdown, NULL);
	sigaction(SIGUSR1, &sa_shutdown, NULL);
	sigaction(SIGUSR2, &sa_shutdown, NULL);

	early();
	cmdline();
	watchdog_init(1);

	pid = fork();
	if (!pid) {
		char *kmod[] = { "/sbin/kmodloader", "/etc/modules-boot.d/", NULL };

		if (debug < 3)
			patch_stdio("/dev/null");

		execvp(kmod[0], kmod);
		ERROR("Failed to start kmodloader: %m\n");
		exit(-1);
	}
	if (pid <= 0) {
		ERROR("Failed to start kmodloader instance: %m\n");
	} else {
		int i;

		for (i = 0; i < 1200; i++) {
			if (waitpid(pid, NULL, WNOHANG) > 0)
				break;
			usleep(10 * 1000);
			watchdog_ping();
		}
	}
	uloop_init();
	preinit();
	uloop_run();

	return 0;
}

1.early() 主要是挂载了 /proc 、/sys 、/dev 、/tmp …等目录,并设置 PATH 环境变量

early()
	early_mounts();
	early_env();

2.cmdline() 是设置了 debug 全局变量

cmdline() 
	debug = (int) r;

3.watchdog_init(1) 开启看门狗

4./sbin/kmodloader /etc/modules-boot.d/ 加载模块

5.preinit() 启动/sbin/procd进程 ,执行/etc/preinit 脚本

void
preinit(void)
{
	char *init[] = { "/bin/sh", "/etc/preinit", NULL };
	char *plug[] = { "/sbin/procd", "-h", "/etc/hotplug-preinit.json", NULL };
	int fd;
	
	LOG("- preinit -\n");
	
	plugd_proc.cb = plugd_proc_cb;
	plugd_proc.pid = fork();
	if (!plugd_proc.pid) {
		execvp(plug[0], plug);
		ERROR("Failed to start plugd: %m\n");
		exit(-1);
	}
	if (plugd_proc.pid <= 0) {
		ERROR("Failed to start new plugd instance: %m\n");
		return;
	}
	uloop_process_add(&plugd_proc);
	
	setenv("PREINIT", "1", 1);
	
	fd = creat("/tmp/.preinit", 0600);
	
	if (fd < 0)
		ERROR("Failed to create sentinel file: %m\n");
	else
		close(fd);
		
	preinit_proc.cb = spawn_procd;
	preinit_proc.pid = fork();
	if (!preinit_proc.pid) {
		execvp(init[0], init);
		ERROR("Failed to start preinit: %m\n");
		exit(-1);
	}
	if (preinit_proc.pid <= 0) {
		ERROR("Failed to start new preinit instance: %m\n");
		return;
	}
	uloop_process_add(&preinit_proc);
	
	DEBUG(4, "Launched preinit instance, pid=%d\n", (int) preinit_proc.pid);
}

6.执行完 /etc/preinit 脚本 之后,启动 procd

static void
spawn_procd(struct uloop_process *proc, int ret)
{
	char *wdt_fd = watchdog_fd();
	char *argv[] = { "/sbin/procd", NULL};
	char dbg[2];
	//......
	execvp(argv[0], argv);
}

小结:

1./sbin/init 怎么来的?来自procd
2. /sbin/init 做了些什么?/sbin/init 进程最终是启动了/sbin/procd 进程,并执行/etc/preinit 脚本
3. 执行完 /etc/preinit 脚本 之后,启动 procd

todo:
后续分析/etc/preinit 脚本 ,procd 进程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值