>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

Reply via email to