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 <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. 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 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel