diff options
author | Lennart Poettering <lennart@poettering.net> | 2015-04-28 17:13:23 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2015-04-28 17:30:00 +0200 |
commit | 96d9117ad2db7d8c13f7898127eee8939e88daf1 (patch) | |
tree | 182c7c733b81452f4099fe4c33a2e3bf060b2051 | |
parent | e7a3aa3df640993ce9aace39b946543305f3af53 (diff) |
fsck: remove fsckd again, but keep the door open for external replacement
For a longer discussion see this:
http://lists.freedesktop.org/archives/systemd-devel/2015-April/030175.html
This introduces /run/systemd/fsck.progress as a simply
AF_UNIX/SOCK_STREAM socket. If it exists and is connectable we'll
connect fsck's -c switch with it. If external programs want to get
progress data they should hence listen on this socket and will get
all they need via that socket. To get information about the connecting
fsck client they should use SO_PEERCRED.
Unless /run/systemd/fsck.progress is around and connectable this change
reverts back to v219 behaviour where we'd forward fsck output to
/dev/console on our own.
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile-man.am | 12 | ||||
-rw-r--r-- | Makefile.am | 17 | ||||
-rw-r--r-- | man/systemd-fsck@.service.xml | 4 | ||||
-rw-r--r-- | man/systemd-fsckd.service.xml | 162 | ||||
-rw-r--r-- | src/fsck/fsck.c | 254 | ||||
l--------- | src/fsckd/Makefile | 1 | ||||
-rw-r--r-- | src/fsckd/fsckd.c | 642 | ||||
-rw-r--r-- | src/fsckd/fsckd.h | 38 | ||||
-rw-r--r-- | units/.gitignore | 1 | ||||
-rw-r--r-- | units/systemd-fsck-root.service.in | 2 | ||||
-rw-r--r-- | units/systemd-fsck@.service.in | 3 | ||||
-rw-r--r-- | units/systemd-fsckd.service.in | 17 | ||||
-rw-r--r-- | units/systemd-fsckd.socket | 15 |
14 files changed, 167 insertions, 1002 deletions
diff --git a/.gitignore b/.gitignore index d4edf990a4..0376e00a3d 100644 --- a/.gitignore +++ b/.gitignore @@ -78,7 +78,6 @@ /systemd-export /systemd-firstboot /systemd-fsck -/systemd-fsckd /systemd-fstab-generator /systemd-getty-generator /systemd-gnome-ask-password-agent diff --git a/Makefile-man.am b/Makefile-man.am index e902e5ed43..4344ffbb4d 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -66,7 +66,6 @@ MANPAGES += \ man/systemd-efi-boot-generator.8 \ man/systemd-escape.1 \ man/systemd-fsck@.service.8 \ - man/systemd-fsckd.service.8 \ man/systemd-fstab-generator.8 \ man/systemd-getty-generator.8 \ man/systemd-gpt-auto-generator.8 \ @@ -209,8 +208,6 @@ MANPAGES_ALIAS += \ man/systemd-ask-password-wall.service.8 \ man/systemd-fsck-root.service.8 \ man/systemd-fsck.8 \ - man/systemd-fsckd.8 \ - man/systemd-fsckd.socket.8 \ man/systemd-hibernate-resume.8 \ man/systemd-hibernate.service.8 \ man/systemd-hybrid-sleep.service.8 \ @@ -321,8 +318,6 @@ man/systemd-ask-password-wall.path.8: man/systemd-ask-password-console.service.8 man/systemd-ask-password-wall.service.8: man/systemd-ask-password-console.service.8 man/systemd-fsck-root.service.8: man/systemd-fsck@.service.8 man/systemd-fsck.8: man/systemd-fsck@.service.8 -man/systemd-fsckd.8: man/systemd-fsckd.service.8 -man/systemd-fsckd.socket.8: man/systemd-fsckd.service.8 man/systemd-hibernate-resume.8: man/systemd-hibernate-resume@.service.8 man/systemd-hibernate.service.8: man/systemd-suspend.service.8 man/systemd-hybrid-sleep.service.8: man/systemd-suspend.service.8 @@ -601,12 +596,6 @@ man/systemd-fsck-root.service.html: man/systemd-fsck@.service.html man/systemd-fsck.html: man/systemd-fsck@.service.html $(html-alias) -man/systemd-fsckd.html: man/systemd-fsckd.service.html - $(html-alias) - -man/systemd-fsckd.socket.html: man/systemd-fsckd.service.html - $(html-alias) - man/systemd-hibernate-resume.html: man/systemd-hibernate-resume@.service.html $(html-alias) @@ -1764,7 +1753,6 @@ EXTRA_DIST += \ man/systemd-escape.xml \ man/systemd-firstboot.xml \ man/systemd-fsck@.service.xml \ - man/systemd-fsckd.service.xml \ man/systemd-fstab-generator.xml \ man/systemd-getty-generator.xml \ man/systemd-gpt-auto-generator.xml \ diff --git a/Makefile.am b/Makefile.am index 292cf917f6..29ffcbb8f9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -398,7 +398,6 @@ rootlibexec_PROGRAMS = \ systemd-remount-fs \ systemd-reply-password \ systemd-fsck \ - systemd-fsckd \ systemd-machine-id-commit \ systemd-ac-power \ systemd-sysctl \ @@ -501,7 +500,6 @@ dist_systemunit_DATA = \ units/slices.target \ units/system.slice \ units/x-.slice \ - units/systemd-fsckd.socket \ units/systemd-initctl.socket \ units/syslog.socket \ units/dev-hugepages.mount \ @@ -552,7 +550,6 @@ nodist_systemunit_DATA = \ units/systemd-kexec.service \ units/systemd-fsck@.service \ units/systemd-fsck-root.service \ - units/systemd-fsckd.service \ units/systemd-machine-id-commit.service \ units/systemd-udevd.service \ units/systemd-udev-trigger.service \ @@ -605,7 +602,6 @@ EXTRA_DIST += \ units/user/systemd-exit.service.in \ units/systemd-fsck@.service.in \ units/systemd-fsck-root.service.in \ - units/systemd-fsckd.service.in \ units/systemd-machine-id-commit.service.in \ units/user@.service.m4.in \ units/debug-shell.service.in \ @@ -2378,19 +2374,6 @@ systemd_fsck_LDADD = \ libsystemd-shared.la # ------------------------------------------------------------------------------ -systemd_fsckd_SOURCES = \ - src/fsckd/fsckd.c \ - src/fsckd/fsckd.h \ - $(NULL) - -systemd_fsckd_LDADD = \ - libsystemd-internal.la \ - libsystemd-label.la \ - libsystemd-shared.la \ - libudev-internal.la \ - $(NULL) - -# ------------------------------------------------------------------------------ systemd_machine_id_commit_SOURCES = \ src/machine-id-commit/machine-id-commit.c \ src/core/machine-id-setup.c \ diff --git a/man/systemd-fsck@.service.xml b/man/systemd-fsck@.service.xml index 69b8fdde2c..e4ffcba168 100644 --- a/man/systemd-fsck@.service.xml +++ b/man/systemd-fsck@.service.xml @@ -80,9 +80,7 @@ the filesystem should actually be checked based on the time since last check, number of mounts, unclean unmount, etc.</para> - <para><filename>systemd-fsck</filename> will forward file system - checking progress to <filename>systemd-fsckd.service</filename> - socket. If a file system check fails for a service without + <para>If a file system check fails for a service without <option>nofail</option>, emergency mode is activated, by isolating to <filename>emergency.target</filename>.</para> </refsect1> diff --git a/man/systemd-fsckd.service.xml b/man/systemd-fsckd.service.xml deleted file mode 100644 index 2ad78448f8..0000000000 --- a/man/systemd-fsckd.service.xml +++ /dev/null @@ -1,162 +0,0 @@ -<?xml version="1.0"?> -<!--*-nxml-*--> -<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> -<!-- - This file is part of systemd. - - Copyright 2015 Canonical - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ---> -<refentry id="systemd-fsckd.service" xmlns:xi="http://www.w3.org/2001/XInclude"> - - <refentryinfo> - <title>systemd-fsckd.service</title> - <productname>systemd</productname> - - <authorgroup> - <author> - <contrib>Developer</contrib> - <firstname>Didier</firstname> - <surname>Roche</surname> - <email>didrocks@ubuntu.com</email> - </author> - </authorgroup> - </refentryinfo> - - <refmeta> - <refentrytitle>systemd-fsckd.service</refentrytitle> - <manvolnum>8</manvolnum> - </refmeta> - - <refnamediv> - <refname>systemd-fsckd.service</refname> - <refname>systemd-fsckd.socket</refname> - <refname>systemd-fsckd</refname> - <refpurpose>File system check progress reporting</refpurpose> - </refnamediv> - - <refsynopsisdiv> - <para><filename>systemd-fsckd.service</filename></para> - <para><filename>systemd-fsckd.socket</filename></para> - <para><filename>/usr/lib/systemd/systemd-fsckd</filename></para> - </refsynopsisdiv> - - <refsect1> - <title>Description</title> - - <para><filename>systemd-fsckd.service</filename> is a service responsible - for receiving file system check progress, and communicating some - consolidated data to console and plymouth (if running). It also handles - possible check cancellations.</para> - - <para><command>systemd-fsckd</command> receives messages about file - system check progress from <command>systemd-fsck</command> through a - UNIX domain socket. It can display the progress of the least advanced - fsck as well as the total number of devices being checked in parallel - to the console. It will also send progress messages to plymouth. - Both the raw data and translated messages are sent, so compiled - plymouth themes can use the raw data to display custom messages, and - scripted themes, not supporting i18n, can display the translated - versions.</para> - - <para><command>systemd-fsckd</command> will instruct plymouth to grab - Control+C keypresses. When the key is pressed, running checks will be - terminated. It will also cancel any newly connected fsck instances for - the lifetime of <filename>systemd-fsckd</filename>.</para> - </refsect1> - - <refsect1> - <title>Protocol for communication with plymouth</title> - - <para><filename>systemd-fsckd</filename> passes the - following messages to the theme:</para> - - <para>Progress update, sent as a plymouth update message: - <literal>fsckd:<num_devices>:<progress>:<string></literal> - <variablelist> - <varlistentry> - <term><literal><num_devices></literal></term> - <listitem><para>the current number of devices - being checked (int)</para></listitem> - </varlistentry> - <varlistentry> - <term><literal><progress></literal></term> - <listitem><para>the current minimum percentage of - all devices being checking (float, from 0 to 100)</para></listitem> - </varlistentry> - <varlistentry> - <term><literal><string></literal></term> - <listitem><para>a translated message ready to be displayed - by the plymouth theme displaying the data above. It can be overriden - by themes supporting i18n.</para></listitem> - </varlistentry> - </variablelist> - </para> - - <para>Cancel message, sent as a traditional plymouth message: - <literal>fsckd-cancel-msg:<string></literal> - <variablelist> - <varlistentry> - <term><literal><strings></literal></term> - <listitem><para>a translated string ready to be displayed - by the plymouth theme indicating that Control+C can be used to cancel - current checks. It can be overriden (matching only - <literal>fsckd-cancel-msg</literal> prefix) - by themes supporting i18n.</para></listitem> - </varlistentry> - </variablelist> - </para> - </refsect1> - - <refsect1> - <title>Options</title> - - <para>The following options are understood:</para> - - <variablelist> - <xi:include href="standard-options.xml" xpointer="help" /> - <xi:include href="standard-options.xml" xpointer="version" /> - </variablelist> - - </refsect1> - - <refsect1> - <title>Exit status</title> - - <para>On success, 0 is returned, a non-zero failure - code otherwise. Note that the daemon stays idle for - a while to accept new <filename>systemd-fsck</filename> - connections before exiting.</para> - </refsect1> - - <refsect1> - <title>See Also</title> - <para> - <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd-fsck</refentrytitle><manvolnum>8</manvolnum></citerefentry>, - <citerefentry project='man-pages'><refentrytitle>fsck</refentrytitle><manvolnum>8</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd-quotacheck.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, - <citerefentry project='man-pages'><refentrytitle>fsck.btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>, - <citerefentry project='man-pages'><refentrytitle>fsck.cramfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>, - <citerefentry project='man-pages'><refentrytitle>fsck.ext4</refentrytitle><manvolnum>8</manvolnum></citerefentry>, - <citerefentry project='man-pages'><refentrytitle>fsck.fat</refentrytitle><manvolnum>8</manvolnum></citerefentry>, - <citerefentry project='man-pages'><refentrytitle>fsck.hfsplus</refentrytitle><manvolnum>8</manvolnum></citerefentry>, - <citerefentry project='man-pages'><refentrytitle>fsck.minix</refentrytitle><manvolnum>8</manvolnum></citerefentry>, - <citerefentry project='man-pages'><refentrytitle>fsck.ntfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>, - <citerefentry project='man-pages'><refentrytitle>fsck.xfs</refentrytitle><manvolnum>8</manvolnum></citerefentry> - </para> - </refsect1> - -</refentry> diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index f030dd3d2f..56d880ac81 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -27,6 +27,7 @@ #include <fcntl.h> #include <sys/file.h> #include <sys/stat.h> +#include <sys/prctl.h> #include "sd-bus.h" #include "sd-device.h" @@ -40,10 +41,10 @@ #include "device-util.h" #include "path-util.h" #include "socket-util.h" -#include "fsckd/fsckd.h" static bool arg_skip = false; static bool arg_force = false; +static bool arg_show_progress = false; static const char *arg_repair = "-a"; static void start_target(const char *target) { @@ -135,39 +136,74 @@ static void test_files(void) { } #endif + arg_show_progress = access("/run/systemd/show-status", F_OK) >= 0; } -static int process_progress(int fd, pid_t fsck_pid, dev_t device_num) { - _cleanup_fclose_ FILE *f = NULL; - usec_t last = 0; - _cleanup_close_ int fsckd_fd = -1; - static const union sockaddr_union sa = { - .un.sun_family = AF_UNIX, - .un.sun_path = FSCKD_SOCKET_PATH, +static double percent(int pass, unsigned long cur, unsigned long max) { + /* Values stolen from e2fsck */ + + static const int pass_table[] = { + 0, 70, 90, 92, 95, 100 }; - fsckd_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (fsckd_fd < 0) - return log_warning_errno(errno, "Cannot open fsckd socket, we won't report fsck progress: %m"); - if (connect(fsckd_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) - return log_warning_errno(errno, "Cannot connect to fsckd socket, we won't report fsck progress: %m"); - - f = fdopen(fd, "r"); - if (!f) - return log_warning_errno(errno, "Cannot connect to fsck, we won't report fsck progress: %m"); - - while (!feof(f)) { - int pass; - size_t buflen; - size_t cur, max; - ssize_t r; - usec_t t; + if (pass <= 0) + return 0.0; + + if ((unsigned) pass >= ELEMENTSOF(pass_table) || max == 0) + return 100.0; + + return (double) pass_table[pass-1] + + ((double) pass_table[pass] - (double) pass_table[pass-1]) * + (double) cur / (double) max; +} + +static int process_progress(int fd) { + _cleanup_fclose_ FILE *console = NULL, *f = NULL; + usec_t last = 0; + bool locked = false; + int clear = 0, r; + + /* No progress pipe to process? Then we are a NOP. */ + if (fd < 0) + return 0; + + f = fdopen(fd, "re"); + if (!f) { + safe_close(fd); + return -errno; + } + + console = fopen("/dev/console", "we"); + if (!console) + return -ENOMEM; + + for (;;) { + int pass, m; + unsigned long cur, max; _cleanup_free_ char *device = NULL; - FsckProgress progress; - FsckdMessage fsckd_message; + double p; + usec_t t; - if (fscanf(f, "%i %zu %zu %ms", &pass, &cur, &max, &device) != 4) + if (fscanf(f, "%i %lu %lu %ms", &pass, &cur, &max, &device) != 4) { + + if (ferror(f)) + r = log_warning_errno(errno, "Failed to read from progress pipe: %m"); + else if (feof(f)) + r = 0; + else { + log_warning("Failed to parse progress pipe data"); + r = -EBADMSG; + } break; + } + + /* Only show one progress counter at max */ + if (!locked) { + if (flock(fileno(console), LOCK_EX|LOCK_NB) < 0) + continue; + + locked = true; + } /* Only update once every 50ms */ t = now(CLOCK_MONOTONIC); @@ -176,42 +212,58 @@ static int process_progress(int fd, pid_t fsck_pid, dev_t device_num) { last = t; - /* send progress to fsckd */ - progress.devnum = device_num; - progress.cur = cur; - progress.max = max; - progress.pass = pass; - - r = send(fsckd_fd, &progress, sizeof(FsckProgress), 0); - if (r < 0 || (size_t) r < sizeof(FsckProgress)) - log_warning_errno(errno, "Cannot communicate fsck progress to fsckd: %m"); - - /* get fsckd requests, only read when we have coherent size data */ - r = ioctl(fsckd_fd, FIONREAD, &buflen); - if (r == 0 && (size_t) buflen >= sizeof(FsckdMessage)) { - r = recv(fsckd_fd, &fsckd_message, sizeof(FsckdMessage), 0); - if (r > 0 && fsckd_message.cancel == 1) { - log_info("Request to cancel fsck from fsckd"); - kill(fsck_pid, SIGTERM); - } - } + p = percent(pass, cur, max); + fprintf(console, "\r%s: fsck %3.1f%% complete...\r%n", device, p, &m); + fflush(console); + + if (m > clear) + clear = m; } - return 0; + if (clear > 0) { + unsigned j; + + fputc('\r', console); + for (j = 0; j < (unsigned) clear; j++) + fputc(' ', console); + fputc('\r', console); + fflush(console); + } + + return r; +} + +static int fsck_progress_socket(void) { + static const union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/fsck.progress", + }; + + int fd, r; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + return log_warning_errno(errno, "socket(): %m"); + + if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { + r = log_full_errno(errno == ECONNREFUSED || errno == ENOENT ? LOG_DEBUG : LOG_WARNING, + errno, "Failed to connect to progress socket %s, ignoring: %m", sa.un.sun_path); + safe_close(fd); + return r; + } + + return fd; } int main(int argc, char *argv[]) { - const char *cmdline[9]; - int i = 0, r = EXIT_FAILURE, q; - pid_t pid; - int progress_rc; - siginfo_t status; + _cleanup_close_pair_ int progress_pipe[2] = { -1, -1 }; _cleanup_device_unref_ sd_device *dev = NULL; const char *device, *type; bool root_directory; - _cleanup_close_pair_ int progress_pipe[2] = { -1, -1 }; - char dash_c[sizeof("-C")-1 + DECIMAL_STR_MAX(int) + 1]; + siginfo_t status; struct stat st; + int r; + pid_t pid; if (argc > 2) { log_error("This program expects one or no arguments."); @@ -309,48 +361,74 @@ int main(int argc, char *argv[]) { log_warning_errno(r, "Couldn't detect if fsck.%s may be used for %s: %m", type, device); } - if (pipe(progress_pipe) < 0) { - r = log_error_errno(errno, "pipe(): %m"); - goto finish; + if (arg_show_progress) { + if (pipe(progress_pipe) < 0) { + r = log_error_errno(errno, "pipe(): %m"); + goto finish; + } } - cmdline[i++] = "/sbin/fsck"; - cmdline[i++] = arg_repair; - cmdline[i++] = "-T"; - - /* - * Since util-linux v2.25 fsck uses /run/fsck/<diskname>.lock files. - * The previous versions use flock for the device and conflict with - * udevd, see https://bugs.freedesktop.org/show_bug.cgi?id=79576#c5 - */ - cmdline[i++] = "-l"; - - if (!root_directory) - cmdline[i++] = "-M"; - - if (arg_force) - cmdline[i++] = "-f"; - - xsprintf(dash_c, "-C%i", progress_pipe[1]); - cmdline[i++] = dash_c; - - cmdline[i++] = device; - cmdline[i++] = NULL; - pid = fork(); if (pid < 0) { r = log_error_errno(errno, "fork(): %m"); goto finish; - } else if (pid == 0) { + } + if (pid == 0) { + char dash_c[sizeof("-C")-1 + DECIMAL_STR_MAX(int) + 1]; + int progress_socket = -1; + const char *cmdline[9]; + int i = 0; + /* Child */ + + reset_all_signal_handlers(); + reset_signal_mask(); + assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0); + + /* Close the reading side of the progress pipe */ progress_pipe[0] = safe_close(progress_pipe[0]); + + /* Try to connect to a progress management daemon, if there is one */ + progress_socket = fsck_progress_socket(); + if (progress_socket >= 0) { + /* If this worked we close the progress pipe early, and just use the socket */ + progress_pipe[1] = safe_close(progress_pipe[1]); + xsprintf(dash_c, "-C%i", progress_socket); + } else if (progress_pipe[1] >= 0) { + /* Otherwise if we have the progress pipe to our own local handle, we use it */ + xsprintf(dash_c, "-C%i", progress_pipe[1]); + } else + dash_c[0] = 0; + + cmdline[i++] = "/sbin/fsck"; + cmdline[i++] = arg_repair; + cmdline[i++] = "-T"; + + /* + * Since util-linux v2.25 fsck uses /run/fsck/<diskname>.lock files. + * The previous versions use flock for the device and conflict with + * udevd, see https://bugs.freedesktop.org/show_bug.cgi?id=79576#c5 + */ + cmdline[i++] = "-l"; + + if (!root_directory) + cmdline[i++] = "-M"; + + if (arg_force) + cmdline[i++] = "-f"; + + if (!isempty(dash_c)) + cmdline[i++] = dash_c; + + cmdline[i++] = device; + cmdline[i++] = NULL; + execv(cmdline[0], (char**) cmdline); _exit(8); /* Operational error */ } progress_pipe[1] = safe_close(progress_pipe[1]); - - progress_rc = process_progress(progress_pipe[0], pid, st.st_rdev); + (void) process_progress(progress_pipe[0]); progress_pipe[0] = -1; r = wait_for_terminate(pid, &status); @@ -359,14 +437,13 @@ int main(int argc, char *argv[]) { goto finish; } - if (status.si_code != CLD_EXITED || (status.si_status & ~1) || progress_rc != 0) { + if (status.si_code != CLD_EXITED || (status.si_status & ~1)) { - /* cancel will kill fsck (but process_progress returns 0) */ - if ((progress_rc != 0 && status.si_code == CLD_KILLED) || status.si_code == CLD_DUMPED) + if (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 if (progress_rc != 0) + else log_error("fsck failed due to unknown reason."); r = -EINVAL; @@ -378,9 +455,8 @@ int main(int argc, char *argv[]) { /* Some other problem */ start_target(SPECIAL_EMERGENCY_TARGET); else { + log_warning("Ignoring error."); r = 0; - if (progress_rc != 0) - log_warning("Ignoring error."); } } else diff --git a/src/fsckd/Makefile b/src/fsckd/Makefile deleted file mode 120000 index d0b0e8e008..0000000000 --- a/src/fsckd/Makefile +++ /dev/null @@ -1 +0,0 @@ -../Makefile
\ No newline at end of file diff --git a/src/fsckd/fsckd.c b/src/fsckd/fsckd.c deleted file mode 100644 index 6b35fc26a2..0000000000 --- a/src/fsckd/fsckd.c +++ /dev/null @@ -1,642 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2015 Canonical - - Author: - Didier Roche <didrocks@ubuntu.com> - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <getopt.h> -#include <errno.h> -#include <libintl.h> -#include <math.h> -#include <stdbool.h> -#include <stdlib.h> -#include <stdio.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/un.h> -#include <unistd.h> - -#include "sd-daemon.h" -#include "build.h" -#include "def.h" -#include "event-util.h" -#include "log.h" -#include "list.h" -#include "macro.h" -#include "socket-util.h" -#include "util.h" -#include "fsckd.h" - -#define IDLE_TIME_SECONDS 30 -#define PLYMOUTH_REQUEST_KEY "K\2\2\3" -#define CLIENTS_MAX 128 - -struct Manager; - -typedef struct Client { - struct Manager *manager; - int fd; - dev_t devnum; - - size_t cur; - size_t max; - int pass; - - double percent; - - size_t buflen; - bool cancelled; - - sd_event_source *event_source; - - LIST_FIELDS(struct Client, clients); -} Client; - -typedef struct Manager { - sd_event *event; - - LIST_HEAD(Client, clients); - unsigned n_clients; - - size_t clear; - - int connection_fd; - sd_event_source *connection_event_source; - - bool show_status_console; - - double percent; - int numdevices; - - int plymouth_fd; - sd_event_source *plymouth_event_source; - bool plymouth_cancel_sent; - - bool cancel_requested; -} Manager; - -static void client_free(Client *c); -static void manager_free(Manager *m); - -DEFINE_TRIVIAL_CLEANUP_FUNC(Client*, client_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); - -static int manager_write_console(Manager *m, const char *message) { - _cleanup_fclose_ FILE *console = NULL; - int l; - size_t j; - - assert(m); - - if (!m->show_status_console) - return 0; - - /* Reduce the SAK window by opening and closing console on every request */ - console = fopen("/dev/console", "we"); - if (!console) - return -errno; - - if (message) { - fprintf(console, "\r%s\r%n", message, &l); - if (m->clear < (size_t)l) - m->clear = (size_t)l; - } else { - fputc('\r', console); - for (j = 0; j < m->clear; j++) - fputc(' ', console); - fputc('\r', console); - } - fflush(console); - - return 0; -} - -static double compute_percent(int pass, size_t cur, size_t max) { - /* Values stolen from e2fsck */ - - static const double pass_table[] = { - 0, 70, 90, 92, 95, 100 - }; - - if (pass <= 0) - return 0.0; - - if ((unsigned) pass >= ELEMENTSOF(pass_table) || max == 0) - return 100.0; - - return pass_table[pass-1] + - (pass_table[pass] - pass_table[pass-1]) * - (double) cur / max; -} - -static int client_request_cancel(Client *c) { - FsckdMessage cancel_msg = { - .cancel = 1, - }; - - ssize_t n; - - assert(c); - - if (c->cancelled) - return 0; - - n = send(c->fd, &cancel_msg, sizeof(FsckdMessage), 0); - if (n < 0) - return log_warning_errno(errno, "Cannot send cancel to fsck on (%u:%u): %m", major(c->devnum), minor(c->devnum)); - if ((size_t) n < sizeof(FsckdMessage)) { - log_warning("Short send when sending cancel to fsck on (%u:%u).", major(c->devnum), minor(c->devnum)); - return -EIO; - } - - c->cancelled = true; - return 1; -} - -static void client_free(Client *c) { - assert(c); - - if (c->manager) { - LIST_REMOVE(clients, c->manager->clients, c); - c->manager->n_clients--; - } - - sd_event_source_unref(c->event_source); - - safe_close(c->fd); - free(c); -} - -static void manager_disconnect_plymouth(Manager *m) { - assert(m); - - m->plymouth_event_source = sd_event_source_unref(m->plymouth_event_source); - m->plymouth_fd = safe_close(m->plymouth_fd); - m->plymouth_cancel_sent = false; -} - -static int manager_plymouth_feedback_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - Manager *m = userdata; - Client *current; - char buffer[6]; - ssize_t l; - - assert(m); - - l = read(m->plymouth_fd, buffer, sizeof(buffer)); - if (l < 0) { - log_warning_errno(errno, "Got error while reading from plymouth: %m"); - manager_disconnect_plymouth(m); - return -errno; - } - if (l == 0) { - manager_disconnect_plymouth(m); - return 0; - } - - if (l > 1 && buffer[0] == '\15') - log_error("Message update to plymouth wasn't delivered successfully"); - - /* the only answer support type we requested is a key interruption */ - if (l > 2 && buffer[0] == '\2' && buffer[5] == '\3') { - m->cancel_requested = true; - - /* cancel all connected clients */ - LIST_FOREACH(clients, current, m->clients) - client_request_cancel(current); - } - - return 0; -} - -static int manager_connect_plymouth(Manager *m) { - union sockaddr_union sa = PLYMOUTH_SOCKET; - int r; - - if (!plymouth_running()) - return 0; - - /* try to connect or reconnect if sending a message */ - if (m->plymouth_fd >= 0) - return 1; - - m->plymouth_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); - if (m->plymouth_fd < 0) - return log_warning_errno(errno, "Connection to plymouth socket failed: %m"); - - if (connect(m->plymouth_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) { - r = log_warning_errno(errno, "Couldn't connect to plymouth: %m"); - goto fail; - } - - r = sd_event_add_io(m->event, &m->plymouth_event_source, m->plymouth_fd, EPOLLIN, manager_plymouth_feedback_handler, m); - if (r < 0) { - log_warning_errno(r, "Can't listen to plymouth socket: %m"); - goto fail; - } - - return 1; - -fail: - manager_disconnect_plymouth(m); - return r; -} - -static int plymouth_send_message(int plymouth_fd, const char *message, bool update) { - _cleanup_free_ char *packet = NULL; - int n; - char mode = 'M'; - - if (update) - mode = 'U'; - - if (asprintf(&packet, "%c\002%c%s%n", mode, (int) (strlen(message) + 1), message, &n) < 0) - return log_oom(); - - return loop_write(plymouth_fd, packet, n + 1, true); -} - -static int manager_send_plymouth_message(Manager *m, const char *message) { - const char *plymouth_cancel_message = NULL, *l10n_cancel_message = NULL; - int r; - - r = manager_connect_plymouth(m); - if (r < 0) - return r; - /* 0 means that plymouth isn't running, do not send any message yet */ - else if (r == 0) - return 0; - - if (!m->plymouth_cancel_sent) { - - /* Indicate to plymouth that we listen to Ctrl+C */ - r = loop_write(m->plymouth_fd, PLYMOUTH_REQUEST_KEY, sizeof(PLYMOUTH_REQUEST_KEY), true); - if (r < 0) - return log_warning_errno(r, "Can't send to plymouth cancel key: %m"); - - m->plymouth_cancel_sent = true; - - l10n_cancel_message = _("Press Ctrl+C to cancel all filesystem checks in progress"); - plymouth_cancel_message = strjoina("fsckd-cancel-msg:", l10n_cancel_message); - - r = plymouth_send_message(m->plymouth_fd, plymouth_cancel_message, false); - if (r < 0) - log_warning_errno(r, "Can't send filesystem cancel message to plymouth: %m"); - - } else if (m->numdevices == 0) { - - m->plymouth_cancel_sent = false; - - r = plymouth_send_message(m->plymouth_fd, "", false); - if (r < 0) - log_warning_errno(r, "Can't clear plymouth filesystem cancel message: %m"); - } - - r = plymouth_send_message(m->plymouth_fd, message, true); - if (r < 0) - return log_warning_errno(r, "Couldn't send \"%s\" to plymouth: %m", message); - - return 0; -} - -static int manager_update_global_progress(Manager *m) { - Client *current = NULL; - _cleanup_free_ char *console_message = NULL; - _cleanup_free_ char *fsck_message = NULL; - int current_numdevices = 0, r; - double current_percent = 100; - - /* get the overall percentage */ - LIST_FOREACH(clients, current, m->clients) { - current_numdevices++; - - /* right now, we only keep the minimum % of all fsckd processes. We could in the future trying to be - linear, but max changes and corresponds to the pass. We have all the informations into fsckd - already if we can treat that in a smarter way. */ - current_percent = MIN(current_percent, current->percent); - } - - /* update if there is anything user-visible to update */ - if (fabs(current_percent - m->percent) > 0.001 || current_numdevices != m->numdevices) { - m->numdevices = current_numdevices; - m->percent = current_percent; - - if (asprintf(&console_message, - ngettext("Checking in progress on %d disk (%3.1f%% complete)", - "Checking in progress on %d disks (%3.1f%% complete)", m->numdevices), - m->numdevices, m->percent) < 0) - return -ENOMEM; - - if (asprintf(&fsck_message, "fsckd:%d:%3.1f:%s", m->numdevices, m->percent, console_message) < 0) - return -ENOMEM; - - r = manager_write_console(m, console_message); - if (r < 0) - return r; - - /* try to connect to plymouth and send message */ - r = manager_send_plymouth_message(m, fsck_message); - if (r < 0) - return r; - } - return 0; -} - -static int client_progress_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - Client *client = userdata; - FsckProgress fsck_data; - size_t buflen; - Manager *m; - int r; - - assert(client); - - m = client->manager; - - /* check first if we need to cancel this client */ - if (m->cancel_requested) - client_request_cancel(client); - - /* ensure we have enough data to read */ - r = ioctl(fd, FIONREAD, &buflen); - if (r == 0 && buflen != 0 && (size_t) buflen < sizeof(FsckProgress)) { - if (client->buflen != buflen) - client->buflen = buflen; - /* we got twice the same size from a bad behaving client, kick it off the list */ - else { - log_warning("Closing bad behaving fsck client connection at fd %d", client->fd); - client_free(client); - manager_update_global_progress(m); - } - return 0; - } - - /* read actual data */ - r = recv(fd, &fsck_data, sizeof(FsckProgress), 0); - if (r == 0) { - log_debug("Fsck client connected to fd %d disconnected", client->fd); - client_free(client); - } else if (r > 0 && r != sizeof(FsckProgress)) - log_warning("Unexpected data structure sent to fsckd socket from fd: %d. Ignoring", client->fd); - else if (r > 0 && r == sizeof(FsckProgress)) { - client->devnum = fsck_data.devnum; - client->cur = fsck_data.cur; - client->max = fsck_data.max; - client->pass = fsck_data.pass; - client->percent = compute_percent(client->pass, client->cur, client->max); - log_debug("Getting progress for %u:%u (%lu, %lu, %d) : %3.1f%%", - major(client->devnum), minor(client->devnum), - client->cur, client->max, client->pass, client->percent); - } else - log_error_errno(r, "Unknown error while trying to read fsck data: %m"); - - manager_update_global_progress(m); - - return 0; -} - -static int manager_new_connection_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(client_freep) Client *c = NULL; - _cleanup_close_ int new_client_fd = -1; - Manager *m = userdata; - int r; - - assert(m); - - /* Initialize and list new clients */ - new_client_fd = accept4(m->connection_fd, NULL, NULL, SOCK_CLOEXEC); - if (new_client_fd < 0) - return log_error_errno(errno, "Couldn't accept a new connection: %m"); - - if (m->n_clients >= CLIENTS_MAX) { - log_error("Too many clients, refusing connection."); - return 0; - } - - log_debug("New fsck client connected to fd: %d", new_client_fd); - - c = new0(Client, 1); - if (!c) { - log_oom(); - return 0; - } - - c->fd = new_client_fd; - new_client_fd = -1; - - r = sd_event_add_io(m->event, &c->event_source, c->fd, EPOLLIN, client_progress_handler, c); - if (r < 0) { - log_oom(); - return 0; - } - - LIST_PREPEND(clients, m->clients, c); - m->n_clients++; - c->manager = m; - - /* only request the client to cancel now in case the request is dropped by the client (chance to recancel) */ - if (m->cancel_requested) - client_request_cancel(c); - - c = NULL; - return 0; -} - -static void manager_free(Manager *m) { - if (!m) - return; - - /* clear last line */ - manager_write_console(m, NULL); - - sd_event_source_unref(m->connection_event_source); - safe_close(m->connection_fd); - - while (m->clients) - client_free(m->clients); - - manager_disconnect_plymouth(m); - - sd_event_unref(m->event); - - free(m); -} - -static int manager_new(Manager **ret, int fd) { - _cleanup_(manager_freep) Manager *m = NULL; - int r; - - assert(ret); - - m = new0(Manager, 1); - if (!m) - return -ENOMEM; - - m->plymouth_fd = -1; - m->connection_fd = fd; - m->percent = 100; - - r = sd_event_default(&m->event); - if (r < 0) - return r; - - if (access("/run/systemd/show-status", F_OK) >= 0) - m->show_status_console = true; - - r = sd_event_add_io(m->event, &m->connection_event_source, fd, EPOLLIN, manager_new_connection_handler, m); - if (r < 0) - return r; - - *ret = m; - m = NULL; - - return 0; -} - -static int run_event_loop_with_timeout(sd_event *e, usec_t timeout) { - int r, code; - - assert(e); - - for (;;) { - r = sd_event_get_state(e); - if (r < 0) - return r; - if (r == SD_EVENT_FINISHED) - break; - - r = sd_event_run(e, timeout); - if (r < 0) - return r; - - /* timeout reached */ - if (r == 0) { - sd_event_exit(e, 0); - break; - } - } - - r = sd_event_get_exit_code(e, &code); - if (r < 0) - return r; - - return code; -} - -static void help(void) { - printf("%s [OPTIONS...]\n\n" - "Capture fsck progress and forward one stream to plymouth\n\n" - " -h --help Show this help\n" - " --version Show package version\n", - program_invocation_short_name); -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_VERSION = 0x100, - ARG_ROOT, - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - {} - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "hv", options, NULL)) >= 0) - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; - - case '?': - return -EINVAL; - - default: - assert_not_reached("Unhandled option"); - } - - if (optind < argc) { - log_error("Extraneous arguments"); - return -EINVAL; - } - - return 1; -} - -int main(int argc, char *argv[]) { - _cleanup_(manager_freep) Manager *m = NULL; - int fd = -1; - int r, n; - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - init_gettext(); - - r = parse_argv(argc, argv); - if (r <= 0) - goto finish; - - n = sd_listen_fds(0); - if (n > 1) { - log_error("Too many file descriptors received."); - r = -EINVAL; - goto finish; - } else if (n == 1) - fd = SD_LISTEN_FDS_START + 0; - else { - fd = make_socket_fd(LOG_DEBUG, FSCKD_SOCKET_PATH, SOCK_STREAM | SOCK_CLOEXEC); - if (fd < 0) { - r = log_error_errno(fd, "Couldn't create listening socket fd on %s: %m", FSCKD_SOCKET_PATH); - goto finish; - } - } - - r = manager_new(&m, fd); - if (r < 0) { - log_error_errno(r, "Failed to allocate manager: %m"); - goto finish; - } - - r = run_event_loop_with_timeout(m->event, IDLE_TIME_SECONDS * USEC_PER_SEC); - if (r < 0) { - log_error_errno(r, "Failed to run event loop: %m"); - goto finish; - } - - sd_event_get_exit_code(m->event, &r); - -finish: - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/fsckd/fsckd.h b/src/fsckd/fsckd.h deleted file mode 100644 index 8239273dae..0000000000 --- a/src/fsckd/fsckd.h +++ /dev/null @@ -1,38 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2015 Canonical - - Author: - Didier Roche <didrocks@ubuntu.com> - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#define FSCKD_SOCKET_PATH "/run/systemd/fsckd" - -#include "libudev.h" - -typedef struct FsckProgress { - dev_t devnum; - size_t cur; - size_t max; - int pass; -} FsckProgress; - -typedef struct FsckdMessage { - uint8_t cancel; -} FsckdMessage; diff --git a/units/.gitignore b/units/.gitignore index d81d0c587a..b8f0a0b723 100644 --- a/units/.gitignore +++ b/units/.gitignore @@ -28,7 +28,6 @@ /systemd-firstboot.service /systemd-fsck-root.service /systemd-fsck@.service -/systemd-fsckd.service /systemd-machine-id-commit.service /systemd-halt.service /systemd-hibernate.service diff --git a/units/systemd-fsck-root.service.in b/units/systemd-fsck-root.service.in index f493445b86..3617abf04a 100644 --- a/units/systemd-fsck-root.service.in +++ b/units/systemd-fsck-root.service.in @@ -9,9 +9,7 @@ Description=File System Check on Root Device Documentation=man:systemd-fsck-root.service(8) DefaultDependencies=no -Wants=systemd-fsckd.socket Before=local-fs.target shutdown.target -After=systemd-fsckd.socket ConditionPathIsReadWrite=!/ [Service] diff --git a/units/systemd-fsck@.service.in b/units/systemd-fsck@.service.in index e6d98c031b..0468392dc4 100644 --- a/units/systemd-fsck@.service.in +++ b/units/systemd-fsck@.service.in @@ -10,8 +10,7 @@ Description=File System Check on %f Documentation=man:systemd-fsck@.service(8) DefaultDependencies=no BindsTo=%i.device -Wants=systemd-fsckd.socket -After=%i.device systemd-fsck-root.service local-fs-pre.target systemd-fsckd.socket +After=%i.device systemd-fsck-root.service local-fs-pre.target Before=shutdown.target [Service] diff --git a/units/systemd-fsckd.service.in b/units/systemd-fsckd.service.in deleted file mode 100644 index 9c7ed5146d..0000000000 --- a/units/systemd-fsckd.service.in +++ /dev/null @@ -1,17 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. - -[Unit] -Description=File System Check Daemon to report status -Documentation=man:systemd-fsckd.service(8) -DefaultDependencies=no -Requires=systemd-fsckd.socket -Before=shutdown.target - -[Service] -ExecStart=@rootlibexecdir@/systemd-fsckd -StandardOutput=journal+console diff --git a/units/systemd-fsckd.socket b/units/systemd-fsckd.socket deleted file mode 100644 index 92e8eefea6..0000000000 --- a/units/systemd-fsckd.socket +++ /dev/null @@ -1,15 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. - -[Unit] -Description=fsck to fsckd communication Socket -Documentation=man:systemd-fsckd.service(8) man:systemd-fsck@.service(8) man:systemd-fsck-root.service(8) -DefaultDependencies=no - -[Socket] -ListenStream=/run/systemd/fsckd -SocketMode=0600 |