From 58aec56d8442438ddbc1e54c132c3eda52c3cc75 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Wed, 12 Jun 2024 15:48:06 +0200 Subject: [PATCH 1/4] core/manager: correct alignment in manager_handle_ctrl_alt_del --- src/core/manager.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/core/manager.c b/src/core/manager.c index 21918a9f226..62a2da96c6d 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2967,15 +2967,16 @@ static void manager_start_special(Manager *m, const char *name, JobMode mode) { } static void manager_handle_ctrl_alt_del(Manager *m) { - /* If the user presses C-A-D more than - * 7 times within 2s, we reboot/shutdown immediately, - * unless it was disabled in system.conf */ + assert(m); + + /* If the user presses C-A-D more than 7 times within 2s, we reboot/shutdown immediately, + * unless it was disabled in system.conf. */ if (ratelimit_below(&m->ctrl_alt_del_ratelimit) || m->cad_burst_action == EMERGENCY_ACTION_NONE) manager_start_special(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY); else emergency_action(m, m->cad_burst_action, EMERGENCY_ACTION_WARN, NULL, -1, - "Ctrl-Alt-Del was pressed more than 7 times within 2s"); + "Ctrl-Alt-Del was pressed more than 7 times within 2s"); } static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { From c1bf0571c0f94bbc530f99ae2d6044bd6fca4366 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Wed, 5 Jun 2024 16:54:29 +0200 Subject: [PATCH 2/4] string-util: modernize first_word a bit --- src/basic/string-util.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/src/basic/string-util.c b/src/basic/string-util.c index d0d33a407a6..274a3f3a048 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -24,37 +24,26 @@ #include "utf8.h" char* first_word(const char *s, const char *word) { - size_t sl, wl; - const char *p; - assert(s); assert(word); - /* Checks if the string starts with the specified word, either - * followed by NUL or by whitespace. Returns a pointer to the - * NUL or the first character after the whitespace. */ + /* Checks if the string starts with the specified word, either followed by NUL or by whitespace. + * Returns a pointer to the NUL or the first character after the whitespace. */ - sl = strlen(s); - wl = strlen(word); - - if (sl < wl) - return NULL; - - if (wl == 0) + if (isempty(word)) return (char*) s; - if (memcmp(s, word, wl) != 0) + const char *p = startswith(s, word); + if (!p) return NULL; - - p = s + wl; - if (*p == 0) + if (*p == '\0') return (char*) p; - if (!strchr(WHITESPACE, *p)) + const char *nw = skip_leading_chars(p, WHITESPACE); + if (p == nw) return NULL; - p += strspn(p, WHITESPACE); - return (char*) p; + return (char*) nw; } char *strnappend(const char *s, const char *suffix, size_t b) { From 758760a3610e3c6674de8a1d51b12b991eafef7c Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Wed, 5 Jun 2024 17:53:27 +0200 Subject: [PATCH 3/4] shutdown: clean up sync_with_progress a bit Also, ignore the error on caller's side. --- src/shutdown/shutdown.c | 67 ++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c index 46f22cfc69d..8e11e3533a3 100644 --- a/src/shutdown/shutdown.c +++ b/src/shutdown/shutdown.c @@ -188,7 +188,9 @@ static int switch_root_initramfs(void) { static int sync_making_progress(unsigned long long *prev_dirty) { _cleanup_fclose_ FILE *f = NULL; unsigned long long val = 0; - int ret; + int r; + + assert(prev_dirty); f = fopen("/proc/meminfo", "re"); if (!f) @@ -196,13 +198,12 @@ static int sync_making_progress(unsigned long long *prev_dirty) { for (;;) { _cleanup_free_ char *line = NULL; - unsigned long long ull = 0; - int q; + unsigned long long ull; - q = read_line(f, LONG_LINE_MAX, &line); - if (q < 0) - return log_warning_errno(q, "Failed to parse /proc/meminfo: %m"); - if (q == 0) + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return log_warning_errno(r, "Failed to parse /proc/meminfo: %m"); + if (r == 0) break; if (!first_word(line, "NFS_Unstable:") && !first_word(line, "Writeback:") && !first_word(line, "Dirty:")) @@ -210,25 +211,20 @@ static int sync_making_progress(unsigned long long *prev_dirty) { errno = 0; if (sscanf(line, "%*s %llu %*s", &ull) != 1) { - if (errno != 0) - log_warning_errno(errno, "Failed to parse /proc/meminfo: %m"); - else - log_warning("Failed to parse /proc/meminfo"); - + log_warning_errno(errno_or_else(EIO), "Failed to parse /proc/meminfo field, ignoring: %m"); return false; } val += ull; } - ret = *prev_dirty > val; + r = *prev_dirty > val; *prev_dirty = val; - return ret; + return r; } -static void sync_with_progress(void) { +static int sync_with_progress(void) { unsigned long long dirty = ULLONG_MAX; - unsigned checks; pid_t pid; int r; @@ -238,37 +234,32 @@ static void sync_with_progress(void) { * the progress. If the timeout lapses, the assumption is that the particular sync stalled. */ r = asynchronous_sync(&pid); - if (r < 0) { - log_error_errno(r, "Failed to fork sync(): %m"); - return; - } + if (r < 0) + return log_error_errno(r, "Failed to fork sync(): %m"); log_info("Syncing filesystems and block devices."); /* Start monitoring the sync operation. If more than * SYNC_PROGRESS_ATTEMPTS lapse without progress being made, * we assume that the sync is stalled */ - for (checks = 0; checks < SYNC_PROGRESS_ATTEMPTS; checks++) { + for (unsigned checks = 0; checks < SYNC_PROGRESS_ATTEMPTS; checks++) { r = wait_for_terminate_with_timeout(pid, SYNC_TIMEOUT_USEC); if (r == 0) - /* Sync finished without error. - * (The sync itself does not return an error code) */ - return; - else if (r == -ETIMEDOUT) { - /* Reset the check counter if the "Dirty" value is - * decreasing */ - if (sync_making_progress(&dirty) > 0) - checks = 0; - } else { - log_error_errno(r, "Failed to sync filesystems and block devices: %m"); - return; - } + /* Sync finished without error (sync() call itself does not return an error code) */ + return 0; + if (r != -ETIMEDOUT) + return log_error_errno(r, "Failed to sync filesystems and block devices: %m"); + + /* Reset the check counter if we made some progress */ + if (sync_making_progress(&dirty) > 0) + checks = 0; } - /* Only reached in the event of a timeout. We should issue a kill - * to the stray process. */ - log_error("Syncing filesystems and block devices - timed out, issuing SIGKILL to PID "PID_FMT".", pid); + /* Only reached in the event of a timeout. We should issue a kill to the stray process. */ (void) kill(pid, SIGKILL); + return log_error_errno(SYNTHETIC_ERRNO(ETIMEDOUT), + "Syncing filesystems and block devices - timed out, issuing SIGKILL to PID "PID_FMT".", + pid); } static int read_current_sysctl_printk_log_level(void) { @@ -436,7 +427,7 @@ int main(int argc, char *argv[]) { * desperately trying to sync IO to disk within their timeout. Do not remove this sync, data corruption will * result. */ if (!in_container) - sync_with_progress(); + (void) sync_with_progress(); disable_coredumps(); disable_binfmt(); @@ -604,7 +595,7 @@ int main(int argc, char *argv[]) { * which might have caused IO, hence let's do it once more. Do not remove this sync, data corruption * will result. */ if (!in_container) - sync_with_progress(); + (void) sync_with_progress(); notify_supervisor(); From 0dd4a3345458ac73259326cf857636f28fa9e129 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Wed, 5 Jun 2024 17:57:07 +0200 Subject: [PATCH 4/4] shutdown: re-enable CAD handling in kernel at start --- src/shutdown/shutdown.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c index 8e11e3533a3..03e6e70fd85 100644 --- a/src/shutdown/shutdown.c +++ b/src/shutdown/shutdown.c @@ -374,6 +374,11 @@ int main(int argc, char *argv[]) { log_set_always_reopen_console(true); + /* Re-enable reboot on Ctrl-Alt-Delete, so that if close/broadcast_signal/umount/... stalls, + * or an error is encountered and we freeze(), the user can still initiate a force reboot + * through kernel. */ + (void) reboot(RB_ENABLE_CAD); + r = parse_argv(argc, argv); if (r < 0) goto error;