[systemd-devel] [PATCH 06/12] Support cancellation of fsck in progress

Zbigniew Jędrzejewski-Szmek zbyszek at in.waw.pl
Wed Jan 28 06:53:17 PST 2015


On Wed, Jan 28, 2015 at 02:22:54PM +0100, Didier Roche wrote:
> 

> From 104cf82ba28941e907f277a713f834ceb3d909f0 Mon Sep 17 00:00:00 2001
> From: Didier Roche <didrocks at 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.
Could we bind to ^c or if this is not possible, "three c's in three
seconds" instead? I'm worried that before you could press anything to little
effect in plymouth, and now a single key will have significant consequences.

> 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;

Zbyszek


More information about the systemd-devel mailing list