[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