本系列导航:
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