/* * Handle bootstrap transition to configured runlevel, start TTYs * * This is the final stage of bootstrap. It changes to the default * (configured) runlevel, calls all external start scripts and final * bootstrap hooks before bringing up TTYs. * * We must ensure that all declared `task [S]` and `run [S]` jobs in * finit.conf, or *.conf in finit.d/, run to completion before we * finalize the bootstrap process by calling this function. */ static void finalize(void) { /* * Run startup scripts in the runparts directory, if any. */ if (runparts && fisdir(runparts) && !rescue) run_parts(runparts, NULL); /* * Start all tasks/services in the configured runlevel */ _d("Change to default runlevel, start all services ..."); service_runlevel(cfglevel); /* Clean up bootstrap-only tasks/services that never started */ _d("Clean up all bootstrap-only tasks/services ..."); svc_prune_bootstrap(); /* All services/tasks/inetd/etc. in configure runlevel have started */ _d("Running svc up hooks ..."); plugin_run_hooks(HOOK_SVC_UP); service_step_all(SVC_TYPE_ANY); /* Convenient SysV compat for when you just don't care ... */ if (!access(FINIT_RC_LOCAL, X_OK) && !rescue) run_interactive(FINIT_RC_LOCAL, "Calling %s", FINIT_RC_LOCAL); /* Hooks that should run at the very end */ _d("Calling all system up hooks ..."); plugin_run_hooks(HOOK_SYSTEM_UP); service_step_all(SVC_TYPE_ANY); /* Enable silent mode before starting TTYs */ _d("Going silent ..."); log_silent(); /* Delayed start of TTYs at bootstrap */ _d("Launching all getty services ..."); tty_runlevel(); }
/** * service_runlevel - Change to a new runlevel * @newlevel: New runlevel to activate * * Stops all services not in @newlevel and starts, or lets continue to run, * those in @newlevel. Also updates @prevlevel and active @runlevel. */ void service_runlevel(int newlevel) { svc_t *svc; if (runlevel == newlevel) return; if (newlevel < 0 || newlevel > 9) return; prevlevel = runlevel; runlevel = newlevel; _d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel); runlevel_set(prevlevel, newlevel); /* Make sure to (re)load all *.conf in /etc/finit.d/ */ conf_reload_dynamic(); _d("Stopping services services not allowed in new runlevel ..."); for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { if (!svc_in_runlevel(svc, runlevel)) { #ifndef INETD_DISABLED if (svc_is_inetd(svc)) inetd_stop(&svc->inetd); else #endif service_stop(svc); } /* ... or disabled/removed services from /etc/finit.d/ */ if (svc_is_dynamic(svc) && svc_is_changed(svc)) service_stop(svc); } /* Prev runlevel services stopped, call hooks before starting new runlevel ... */ _d("All services have been stoppped, calling runlevel change hooks ..."); plugin_run_hooks(HOOK_RUNLEVEL_CHANGE); /* Reconfigure HW/VLANs/etc here */ _d("Starting services services new to this runlevel ..."); for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { #ifndef INETD_DISABLED /* Inetd services have slightly different semantics */ if (svc_is_inetd(svc)) { if (svc_in_runlevel(svc, runlevel)) inetd_start(&svc->inetd); continue; } #endif /* All other services consult their callback here */ svc_dance(svc); } /* Cleanup stale services */ svc_clean_dynamic(service_unregister); if (0 == runlevel) { do_shutdown(SIGUSR2); return; } if (6 == runlevel) { do_shutdown(SIGUSR1); return; } if (runlevel == 1) touch("/etc/nologin"); /* Disable login in single-user mode */ else erase("/etc/nologin"); if (0 != prevlevel) tty_runlevel(runlevel); }
static int client(int argc, char *argv[]) { int fd; int c; struct option long_options[] = { {"debug", 0, NULL, 'd'}, {"help", 0, NULL, 'h'}, {NULL, 0, NULL, 0} }; struct init_request rq = { .magic = INIT_MAGIC, .cmd = 0 }; while ((c = getopt_long (argc, argv, "h?d", long_options, NULL)) != EOF) { switch(c) { case 'd': rq.cmd = INIT_CMD_DEBUG; break; case 'h': case '?': return usage(0); default: return usage(1); } } if (!rq.cmd) { if (argc < 2) { fprintf(stderr, "Missing runlevel.\n"); return 1; } rq.cmd = INIT_CMD_RUNLVL; rq.runlevel = (int)argv[1][0]; } if (!fexist(FINIT_FIFO)) { fprintf(stderr, "/sbin/init does not support %s!\n", FINIT_FIFO); return 1; } fd = open(FINIT_FIFO, O_WRONLY); if (-1 == fd) { perror("Failed opening " FINIT_FIFO); return 1; } write(fd, &rq, sizeof(rq)); close(fd); return 0; } static int run_loop(void) { int delay = DELAY_TTY ?: 1; _d("Entering main loop ..."); while (1) { svc_monitor(); plugin_monitor(); /* Delayed start of TTYs to let the system stabilize * after switching runlevels. */ if (delay) { if (--delay == 0) tty_runlevel(runlevel); continue; } } return 0; }
/** * svc_runlevel - Change to a new runlevel * @newlevel: New runlevel to activate * * Stops all services not in @newlevel and starts, or lets continue to run, * those in @newlevel. Also updates @prevlevel and active @runlevel. */ void svc_runlevel(int newlevel) { svc_t *svc; if (runlevel == newlevel) return; if (newlevel < 0 || newlevel > 9) return; prevlevel = runlevel; runlevel = newlevel; utmp_save(prevlevel, newlevel); _d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel); for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { svc_cmd_t cmd; /* Inetd services have slightly different semantics */ #ifndef INETD_DISABLED if (svc->type == SVC_CMD_INETD) { if (!ISSET(svc->runlevels, runlevel)) inetd_stop(&svc->inetd); else inetd_start(&svc->inetd); continue; } #endif /* All other services consult their callback here */ cmd = svc_enabled(svc, 0, NULL); if (svc->pid) { if (cmd == SVC_STOP) svc_stop(svc); else if (cmd == SVC_RELOAD) svc_reload(svc); } else { if (cmd == SVC_START) svc_start(svc); } } if (0 == runlevel) { do_shutdown(SIGUSR2); return; } if (6 == runlevel) { do_shutdown(SIGUSR1); return; } if (runlevel == 1) touch("/etc/nologin"); /* Disable login in single-user mode */ else erase("/etc/nologin"); if (0 != prevlevel) tty_runlevel(runlevel); }