mirror of
https://github.com/troglobit/finit.git
synced 2026-10-31 13:00:32 +00:00
Allow skipping bootstrap wait with Ctrl-C
When setting up a new system with Finit it is very common to make small logical mistakes that cause "hangs" at boot. This is when Finit waits for 180 sec. for run/tasks to complete before moving to the configured runlevel. This patch adds console input monitoring during bootstrap wait that allows users to press Ctrl-C to skip waiting and proceed to the configured runlevel. When Ctrl-C is detected, all incomplete run/task/services are logged to syslog for later troubleshooting after login. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
3 files changed
+124
-2
No files matched your search
@@ -3053,6 +3053,42 @@ int service_completed(svc_t **svcp)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* service_log_incomplete - Log all incomplete run/task in current runlevel
|
||||||
|
*
|
||||||
|
* Iterates through all run/task services and logs those that have not
|
||||||
|
* yet completed. Useful for diagnosing bootstrap delays or reporting
|
||||||
|
* what was skipped when user interrupts bootstrap wait.
|
||||||
|
*/
|
||||||
|
void service_log_incomplete(void)
|
||||||
|
{
|
||||||
|
svc_t *svc, *iter = NULL;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
|
if (!svc_is_runtask(svc))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!svc_enabled(svc))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (svc_conflicts(svc))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strstr(svc->cond, plugin_hook_str(HOOK_SVC_UP)) ||
|
||||||
|
strstr(svc->cond, plugin_hook_str(HOOK_SYSTEM_UP)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!svc->once) {
|
||||||
|
logit(LOG_WARNING, "Incomplete: %s", svc_ident(svc, NULL, 0));
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
logit(LOG_WARNING, "No incomplete run/task services found");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called in SM_RELOAD_WAIT_STATE to update unmodified non-native
|
* Called in SM_RELOAD_WAIT_STATE to update unmodified non-native
|
||||||
* services' READY condition to the current generation. Similar
|
* services' READY condition to the current generation. Similar
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ void service_step_all (int types);
|
|||||||
void service_worker (void *unused);
|
void service_worker (void *unused);
|
||||||
|
|
||||||
int service_completed (svc_t **svc);
|
int service_completed (svc_t **svc);
|
||||||
|
void service_log_incomplete (void);
|
||||||
void service_notify_reconf (void);
|
void service_notify_reconf (void);
|
||||||
|
|
||||||
void service_init (uev_ctx_t *ctx);
|
void service_init (uev_ctx_t *ctx);
|
||||||
|
|||||||
@@ -23,8 +23,10 @@
|
|||||||
|
|
||||||
#include "config.h" /* Generated by configure script */
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <termios.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
@@ -56,8 +58,80 @@ static struct {
|
|||||||
int newlevel; /* Set to new runlevel on change, -1 otherwise */
|
int newlevel; /* Set to new runlevel on change, -1 otherwise */
|
||||||
int reload; /* Set on reload event, else 0 */
|
int reload; /* Set on reload event, else 0 */
|
||||||
int in_reload; /* Set when waiting for all processes to be halted */
|
int in_reload; /* Set when waiting for all processes to be halted */
|
||||||
|
int skip_bootstrap; /* Set to skip bootstrap waiting */
|
||||||
} sm;
|
} sm;
|
||||||
|
|
||||||
|
static uev_t console_watcher;
|
||||||
|
static int console_fd = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Console input callback - handles Ctrl-C during bootstrap wait
|
||||||
|
*/
|
||||||
|
static void console_input_cb(uev_t *w, void *arg, int events)
|
||||||
|
{
|
||||||
|
ssize_t len;
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
if (UEV_ERROR == events) {
|
||||||
|
warnx("Error in console watcher");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read and check for Ctrl-C (ASCII 3) */
|
||||||
|
len = read(w->fd, &ch, 1);
|
||||||
|
if (len == 1 && ch == 3) { /* Ctrl-C */
|
||||||
|
sm.skip_bootstrap = 1;
|
||||||
|
print(2, "Bootstrap wait interrupted by Ctrl-C, resuming ...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop and cleanup the console watcher
|
||||||
|
*/
|
||||||
|
static void console_watcher_stop(void)
|
||||||
|
{
|
||||||
|
if (console_fd >= 0) {
|
||||||
|
uev_io_stop(&console_watcher);
|
||||||
|
close(console_fd);
|
||||||
|
console_fd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup console watcher for Ctrl-C during bootstrap
|
||||||
|
*/
|
||||||
|
static void console_watcher_start(uev_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
struct termios tio;
|
||||||
|
|
||||||
|
/* Open console in non-blocking mode */
|
||||||
|
console_fd = open(console(), O_RDONLY | O_NONBLOCK);
|
||||||
|
if (console_fd < 0) {
|
||||||
|
dbg("Failed opening console for input monitoring: %s", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get current terminal settings */
|
||||||
|
if (tcgetattr(console_fd, &tio) == 0) {
|
||||||
|
/* Put terminal in raw mode to catch Ctrl-C */
|
||||||
|
tio.c_lflag &= ~(ICANON | ECHO | ISIG);
|
||||||
|
tio.c_cc[VMIN] = 0;
|
||||||
|
tio.c_cc[VTIME] = 0;
|
||||||
|
tcsetattr(console_fd, TCSANOW, &tio);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register I/O watcher */
|
||||||
|
if (uev_io_init(ctx, &console_watcher, console_input_cb, NULL, console_fd, UEV_READ)) {
|
||||||
|
dbg("Failed setting up console watcher");
|
||||||
|
close(console_fd);
|
||||||
|
console_fd = -1;
|
||||||
|
} else {
|
||||||
|
dbg("Console watcher active, press Ctrl-C to skip bootstrap wait");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
|
* Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be
|
||||||
@@ -76,13 +150,19 @@ static void sm_check_bootstrap(void *work)
|
|||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
bootstrap_done = service_completed(&svc);
|
bootstrap_done = service_completed(&svc);
|
||||||
if (timeout-- > 0 && !bootstrap_done) {
|
if (timeout-- > 0 && !bootstrap_done && !sm.skip_bootstrap) {
|
||||||
dbg("Not all bootstrap run/tasks have completed yet ... %d", timeout);
|
dbg("Not all bootstrap run/tasks have completed yet ... %d", timeout);
|
||||||
schedule_work(work);
|
schedule_work(work);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeout > 0) {
|
/* Stop console watcher before proceeding */
|
||||||
|
console_watcher_stop();
|
||||||
|
|
||||||
|
if (sm.skip_bootstrap) {
|
||||||
|
logit(LOG_WARNING, "Ctrl-C received, skipped waiting for the following:");
|
||||||
|
service_log_incomplete();
|
||||||
|
} else if (timeout > 0) {
|
||||||
dbg("All run/task have completed, resuming bootstrap.");
|
dbg("All run/task have completed, resuming bootstrap.");
|
||||||
} else {
|
} else {
|
||||||
dbg("Timeout, resuming bootstrap.");
|
dbg("Timeout, resuming bootstrap.");
|
||||||
@@ -184,6 +264,7 @@ void sm_init(void)
|
|||||||
sm.newlevel = -1;
|
sm.newlevel = -1;
|
||||||
sm.reload = 0;
|
sm.reload = 0;
|
||||||
sm.in_reload = 0;
|
sm.in_reload = 0;
|
||||||
|
sm.skip_bootstrap = 0;
|
||||||
|
|
||||||
dbg("Starting bootstrap finalize timer ...");
|
dbg("Starting bootstrap finalize timer ...");
|
||||||
schedule_work(&work);
|
schedule_work(&work);
|
||||||
@@ -206,6 +287,7 @@ restart:
|
|||||||
service_step_all(SVC_TYPE_RUNTASK | SVC_TYPE_SERVICE | SVC_TYPE_SYSV);
|
service_step_all(SVC_TYPE_RUNTASK | SVC_TYPE_SERVICE | SVC_TYPE_SYSV);
|
||||||
|
|
||||||
sm.state = SM_BOOTSTRAP_WAIT_STATE;
|
sm.state = SM_BOOTSTRAP_WAIT_STATE;
|
||||||
|
console_watcher_start(ctx);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -229,6 +311,9 @@ restart:
|
|||||||
if (sm.newlevel == -1)
|
if (sm.newlevel == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* Ensure console watcher is stopped before proceeding */
|
||||||
|
console_watcher_stop();
|
||||||
|
|
||||||
/* Hooks that should run at the very end */
|
/* Hooks that should run at the very end */
|
||||||
dbg("Calling all system up hooks ...");
|
dbg("Calling all system up hooks ...");
|
||||||
plugin_run_hooks(HOOK_SYSTEM_UP);
|
plugin_run_hooks(HOOK_SYSTEM_UP);
|
||||||
|
|||||||
Reference in new issue
Block a user