int main(int argc, char **argv)//内核发生热插拔时会执行一次/proc/sys/kernel/hotplug。 {///sbin/mdev > /proc/sys/kernel/hotplug,本质上内核发生一次热插拔时执行一次/sbin/mdev int ch; char *dbglvl = getenv("DBGLVL"); if (dbglvl) { debug = atoi(dbglvl); unsetenv("DBGLVL"); } while ((ch = getopt(argc, argv, "d:s:h:")) != -1) { switch (ch) { case 'h': return hotplug_run(optarg);//执行hotplug_run(/etc/hotplug-preinit.json): case 's': ubus_socket = optarg; break; case 'd': debug = atoi(optarg); break; default: return usage(argv[0]); } } uloop_init(); procd_signal(); trigger_init(); if (getpid() != 1) procd_connect_ubus(); else procd_state_next();//进程pid=1才执行procd_state_next,这才是开机启动流程中的procd,负责解析/etc/inittab文件并据此依次启动系统。 uloop_run(); return 0; }
static void rcdone(struct runqueue *q) { procd_state_next(); }
static void coldplug_complete(struct uloop_timeout *t) { DEBUG(4, "Coldplug complete\n"); hotplug_last_event(NULL); procd_state_next(); }
static void set_console(void) { const char* tty; char* split; char line[ 20 ]; const char* try[] = { "tty0", "console", NULL }; /* Try the most common outputs */ int f, i = 0; tty = get_cmdline_val("console",line,sizeof(line)); if (tty != NULL) { split = strchr(tty, ','); if ( split != NULL ) *split = '\0'; } else { // Try a default tty=try[i]; i++; } if (chdir("/dev")) { ERROR("failed to change dir to /dev\n"); return; } while (tty!=NULL) { f = open(tty, O_RDONLY); if (f >= 0) { close(f); break; } tty=try[i]; i++; } if (chdir("/")) ERROR("failed to change dir to /\n"); if (tty != NULL) set_stdio(tty); } 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"); 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; }; } void procd_state_next(void) { DEBUG(4, "Change state %d -> %d\n", state, state + 1); state++; state_enter(); } void procd_state_ubus_connect(void) { if (state == STATE_UBUS) procd_state_next(); } void procd_shutdown(int event) { if (state >= STATE_SHUTDOWN) return; DEBUG(2, "Shutting down system with event %x\n", event); reboot_event = event; state = STATE_SHUTDOWN; state_enter(); }