OpenWRT 启动流程(三) /sbin/procd 分析

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

在 /sbin/init 执行完后,调用了 spawn_procd 函数 ,启动了 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);
}

procd 代码位于 procd-2018-03-28-dfb68f85\procd.c

跟踪代码:

main
  procd_state_next
    state_enter
      

这里主要来看 state_enter

static void state_enter(void)
{
	char ubus_cmd[] = "/sbin/ubusd";

	switch (state) {
	case STATE_EARLY:
		LOG("- early -\n");
		watchdog_init(0);
		hotplug("/etc/hotplug.json");
		procd_coldplug();
		break;

	case STATE_UBUS:
		// try to reopen incase the wdt was not available before coldplug
		watchdog_init(0);
		set_stdio("console");
		LOG("- ubus -\n");
		procd_connect_ubus();
		service_start_early("ubus", ubus_cmd);
		break;

	case STATE_INIT:
		LOG("- init -\n");
		procd_inittab();
		procd_inittab_run("respawn");
		procd_inittab_run("askconsole");
		procd_inittab_run("askfirst");
		procd_inittab_run("sysinit");

		// switch to syslog log channel
		ulog_open(ULOG_SYSLOG, LOG_DAEMON, "procd");
		break;

	case STATE_RUNNING:
		LOG("- init complete -\n");
		procd_inittab_run("respawnlate");
		procd_inittab_run("askconsolelate");
		break;

	case STATE_SHUTDOWN:
		/* Redirect output to the console for the users' benefit */
		set_console();
		LOG("- shutdown -\n");
		procd_inittab_run("shutdown");
		sync();
		break;

	case STATE_HALT:
		// To prevent killed processes from interrupting the sleep
		signal(SIGCHLD, SIG_IGN);
		LOG("- SIGTERM processes -\n");
		kill(-1, SIGTERM);
		sync();
		sleep(1);
		LOG("- SIGKILL processes -\n");
		kill(-1, SIGKILL);
		sync();
		sleep(1);
#ifndef DISABLE_INIT
		if (reboot_event == RB_POWER_OFF)
			LOG("- power down -\n");
		else
			LOG("- reboot -\n");

		/* Allow time for last message to reach serial console, etc */
		sleep(1);

		/* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS)
		 * in linux/kernel/sys.c, which can cause the machine to panic when
		 * the init process exits... */
		if (!vfork( )) { /* child */
			reboot(reboot_event);
			_exit(EXIT_SUCCESS);
		}
		while (1)
			sleep(1);
#else
		exit(0);
#endif
		break;

	default:
		ERROR("Unhandled state %d\n", state);
		return;
	};
}
  • case STATE_EARLY
    这里主要是 调用 hotplug procd_coldplug ,自动创建设备节点,生成/dev/xxx

  • case STATE_UBUS
    初始化 ubus 连接

  • case STATE_INIT
    读取 /etc/inittab

::sysinit:/etc/init.d/rcS S boot
::shutdown:/etc/init.d/rcS K shutdown
tts/0::askfirst:/usr/libexec/login.sh
ttyS0::askfirst:/usr/libexec/login.sh
tty1::askfirst:/usr/libexec/login.sh

void procd_inittab(void)
  if (add_action(a, tags[TAG_ACTION]))
      for (i = 0; i < ARRAY_SIZE(handlers); i++)   // 见 handlers 定义
        if (!strcmp(handlers[i].name, name)) {
   	    a->handler = &handlers[i];
   	    list_add_tail(&a->list, &actions);
   	    return 0;
       }
// handlers 定义	    
static struct init_handler handlers[] = {
{
   .name = "sysinit",
   .cb = runrc,
}, {
   .name = "shutdown",
   .cb = runrc,
}, {
   .name = "askfirst",
   .cb = askfirst,
   .multi = 1,
}
   //...
}
static void runrc(struct init_action *a)
{
   if (!a->argv[1] || !a->argv[2]) {
   	ERROR("valid format is rcS <S|K> <param>\n");
   	return;
   }

   /* proceed even if no init or shutdown scripts run */
   if (rcS(a->argv[1], a->argv[2], rcdone))
   	rcdone(NULL);
}
int rcS(char *pattern, char *param, void (*q_empty)(struct runqueue *))
{
   runqueue_init(&q);
   q.empty_cb = q_empty;
   q.max_running_tasks = 1;

   return _rc(&q, "/etc/rc.d", pattern, "*", param);
}

最终其实就是 读取 /etc/rc.d/ 下的启动脚本,逐个执行。 /etc/rc.d/ 目录文件实例:

root@172:/etc/rc.d# ls |sort
K10gpio_switch
K10mysqld
K10openvpn
K50dropbear
K50lighttpd
K81redis
K85odhcpd
K89log
K90network
K90sysfixtime
K98boot
K99umount
S00sysfixtime
S10boot
S10system
S11sysctl
S12log
S19dnsmasq
S19firewall
S20network
S35odhcpd
S36asterisk
S50cron
S50dropbear
S50lighttpd
S50odbc
S50php5-fastcgi
S50php5-fpm
S50yate
S90openvpn
S94gpio_switch
S95done
S95mysqld
S96led
S98redis
S98sysntpd
S99urandom_seed
  • case STATE_RUNNING:
    初始化完成

  • case STATE_SHUTDOWN:
    暂时不细究

  • case STATE_HALT:
    暂时不细究

总结:

/sbin/procd 会读取 /etc/inittab ,然后执行 /etc/rc.d/目录下的应用启动脚本。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值