>From 104cf82ba28941e907f277a713f834ceb3d909f0 Mon Sep 17 00:00:00 2001 From: Didier Roche <didro...@ubuntu.com> Date: Mon, 26 Jan 2015 16:40:52 +0100 Subject: [PATCH 06/12] Support cancellation of fsck in progress
Grab in fsckd plymouth watch key for C or c, and propagate this cancel request to systemd-fsck which will terminate fsck. Send a message to signal to user what key we are grabbing for fsck cancel. Message is: fsckd-cancel-msg:<string> Where string is a translated string ready to be displayed by the plymouth theme indicating that c or C can be used to cancel current checks. It can be overriden (matching only fsckd-cancel-msg prefix) for themes supporting i18n. --- src/fsck/fsck.c | 29 +++++++++++++++++++++-------- src/fsckd/fsckd.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/fsckd/fsckd.h | 5 +++++ 3 files changed, 69 insertions(+), 8 deletions(-) diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index f5dd546..0b42e3b 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -47,6 +47,8 @@ static bool arg_skip = false; static bool arg_force = false; static const char *arg_repair = "-a"; +static pid_t fsck_pid; +static bool cancel_requested = false; static void start_target(const char *target) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; @@ -165,6 +167,7 @@ static int process_progress(int fd) { ssize_t n; usec_t t; FsckProgress progress; + FsckdMessage fsckd_message; if (fscanf(f, "%i %lu %lu %ms", &pass, &cur, &max, &device) != 4) break; @@ -185,6 +188,16 @@ static int process_progress(int fd) { n = send(fsckd_fd, &progress, sizeof(FsckProgress), 0); if (n < 0 || (size_t) n < sizeof(FsckProgress)) log_warning_errno(n, "Cannot communicate fsck progress to fsckd: %m"); + + /* get fsckd requests */ + n = recv(fsckd_fd, &fsckd_message, sizeof(FsckdMessage), 0); + if (n > 0) { + if (fsckd_message.cancel) { + log_warning("Request to cancel fsck from fsckd"); + cancel_requested = true; + kill(fsck_pid, SIGTERM); + } + } } return 0; @@ -193,7 +206,6 @@ static int process_progress(int fd) { int main(int argc, char *argv[]) { const char *cmdline[9]; int i = 0, r = EXIT_FAILURE, q; - pid_t pid; siginfo_t status; _cleanup_udev_unref_ struct udev *udev = NULL; _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL; @@ -321,11 +333,11 @@ int main(int argc, char *argv[]) { cmdline[i++] = device; cmdline[i++] = NULL; - pid = fork(); - if (pid < 0) { + fsck_pid = fork(); + if (fsck_pid < 0) { log_error_errno(errno, "fork(): %m"); goto finish; - } else if (pid == 0) { + } else if (fsck_pid == 0) { /* Child */ if (progress_pipe[0] >= 0) safe_close(progress_pipe[0]); @@ -340,7 +352,7 @@ int main(int argc, char *argv[]) { progress_pipe[0] = -1; } - q = wait_for_terminate(pid, &status); + q = wait_for_terminate(fsck_pid, &status); if (q < 0) { log_error_errno(q, "waitid(): %m"); goto finish; @@ -348,11 +360,11 @@ int main(int argc, char *argv[]) { if (status.si_code != CLD_EXITED || (status.si_status & ~1)) { - if (status.si_code == CLD_KILLED || status.si_code == CLD_DUMPED) + if ((!cancel_requested && status.si_code == CLD_KILLED) || status.si_code == CLD_DUMPED) log_error("fsck terminated by signal %s.", signal_to_string(status.si_status)); else if (status.si_code == CLD_EXITED) log_error("fsck failed with error code %i.", status.si_status); - else + else if (!cancel_requested) log_error("fsck failed due to unknown reason."); if (status.si_code == CLD_EXITED && (status.si_status & 2) && root_directory) @@ -363,7 +375,8 @@ int main(int argc, char *argv[]) { start_target(SPECIAL_EMERGENCY_TARGET); else { r = EXIT_SUCCESS; - log_warning("Ignoring error."); + if (!cancel_requested) + log_warning("Ignoring error."); } } else diff --git a/src/fsckd/fsckd.c b/src/fsckd/fsckd.c index b516193..5760916 100644 --- a/src/fsckd/fsckd.c +++ b/src/fsckd/fsckd.c @@ -57,10 +57,15 @@ typedef struct Clients { unsigned long max; int pass; double percent; + bool cancelled; LIST_FIELDS(struct Clients, clients); } Clients; +#ifdef HAVE_PLYMOUTH +static bool cancelled = false; +#endif + static double compute_percent(int pass, unsigned long cur, unsigned long max) { /* Values stolen from e2fsck */ @@ -79,12 +84,25 @@ static double compute_percent(int pass, unsigned long cur, unsigned long max) { (double) cur / (double) max; } +#ifdef HAVE_PLYMOUTH +static void cancel_requested(void) { + log_debug("Request to cancel fsck checking received"); + cancelled = true; +} +#endif + static int handle_requests(int socket_fd) { Clients *first = NULL; usec_t last_activity = 0; int numdevices = 0, clear = 0; double percent = 100; _cleanup_fclose_ FILE *console = NULL; +#ifdef HAVE_PLYMOUTH + const char *plymouth_cancel_message; + bool cancel_message_plymouth_sent = false; + + plymouth_cancel_message = strappenda("fsckd-cancel-msg:", "Press C to cancel all checks in progress"); +#endif console = fopen("/dev/console", "we"); if (!console) { @@ -111,6 +129,7 @@ static int handle_requests(int socket_fd) { log_debug("new fsck client connected to fd: %d", new_client_fd); current = alloca0(sizeof(Clients)); current->fd = new_client_fd; + current->cancelled = false; if (!first) LIST_INIT(clients, current); else @@ -143,6 +162,20 @@ static int handle_requests(int socket_fd) { log_debug("Getting progress for %s: (%lu, %lu, %d) : %3.1f%%", current->device, current->cur, current->max, current->pass, current->percent); + +#ifdef HAVE_PLYMOUTH + /* send cancel message if cancel key was pressed (and the socket wasn't closed) */ + if (cancelled && !current->cancelled) { + FsckdMessage cancel_msg; + ssize_t n; + cancel_msg.cancel = true; + n = send(current->fd, &cancel_msg, sizeof(FsckdMessage), 0); + if (n < 0 || (size_t) n < sizeof(FsckdMessage)) + log_warning_errno(n, "Cannot send cancel to fsck on %s: %m", current->device); + else + current->cancelled = true; + } +#endif } /* update global (eventually cached) values. */ @@ -173,6 +206,10 @@ static int handle_requests(int socket_fd) { #ifdef HAVE_PLYMOUTH /* send to plymouth */ + if (!cancel_message_plymouth_sent) { + cancel_message_plymouth_sent = \ + plymouth_watch_key("Cc", plymouth_cancel_message, cancel_requested); + } plymouth_update(fsck_message); #endif @@ -183,6 +220,12 @@ static int handle_requests(int socket_fd) { /* idle out after IDLE_TIME_MINUTES minutes with no connected device */ t = now(CLOCK_MONOTONIC); if (numdevices == 0) { +#ifdef HAVE_PLYMOUTH + if (cancel_message_plymouth_sent) { + plymouth_delete_message(); + cancel_message_plymouth_sent = false; + } +#endif if (t > last_activity + IDLE_TIME_MINUTES * USEC_PER_MINUTE) { log_debug("No fsck in progress for the last %d minutes, shutting down.", IDLE_TIME_MINUTES); break; diff --git a/src/fsckd/fsckd.h b/src/fsckd/fsckd.h index e8cd014..6a029ec 100644 --- a/src/fsckd/fsckd.h +++ b/src/fsckd/fsckd.h @@ -23,6 +23,7 @@ ***/ #include <linux/limits.h> +#include <stdbool.h> #define FSCKD_SOCKET_PATH "/run/systemd/fsckd" @@ -32,3 +33,7 @@ typedef struct FsckProgress { int pass; char device[PATH_MAX]; } FsckProgress; + +typedef struct FsckdMessage { + bool cancel; +} FsckdMessage; -- 2.1.4
_______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel