+++ /dev/null
-From: Didier Roche <didrocks@ubuntu.com>
-Date: Fri, 22 May 2015 13:04:38 +0200
-Subject: fsckd daemon for inter-fsckd communication
-
-Global logic:
-Add systemd-fsckd multiplexer which accepts multiple (via systemd-fsck's
-/run/systemd/fsck.progress socket) fsck instances to connect to it and sends
-progress report. systemd-fsckd then computes and writes to /dev/console the
-number of devices currently being checked and the minimum fsck progress.
-
-Plymouth and user interaction:
-Forward the progress to plymouth and support canellation of in progress fsck.
-Try to connect and send to plymouth (if running) some checked report progress,
-using direct plymouth protocole.
-
-Update message is the following:
-fsckd:<num_devices>:<progress>:<string>
-* num_devices corresponds to the current number of devices being checked (int)
-* progress corresponds to the current minimum percentage of all devices being
- checked (float, from 0 to 100)
-* string is a translated message ready to be displayed by the plymouth theme
- displaying the information above. It can be overriden by plymouth themes
- supporting i18n.
-
-Grab in fsckd plymouth watch key Control+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 Control+C can be used to cancel current checks. It can be
-overriden (matching only fsckd-cancel-msg prefix) for themes supporting i18n.
-
-Misc:
-systemd-fsckd stops on idle when no fsck is connected.
-Add man page explaining the plymouth theme protocol, usage of the daemon
-as well as the socket activation part. Adapt existing fsck man page.
-
-Note that fsckd had lived in the upstream tree for a while, but was removed.
-More information at
-http://lists.freedesktop.org/archives/systemd-devel/2015-April/030175.html
--
----
- Makefile-man.am | 12 +
- Makefile.am | 16 +
- man/systemd-fsckd.service.xml | 162 +++++++++
- po/POTFILES.in | 1 +
- src/fsckd/fsckd.c | 680 +++++++++++++++++++++++++++++++++++++
- units/systemd-fsck-root.service.in | 2 +
- units/systemd-fsck@.service.in | 3 +-
- units/systemd-fsckd.service.in | 17 +
- units/systemd-fsckd.socket | 15 +
- 9 files changed, 907 insertions(+), 1 deletion(-)
- create mode 100644 man/systemd-fsckd.service.xml
- create mode 100644 src/fsckd/fsckd.c
- create mode 100644 units/systemd-fsckd.service.in
- create mode 100644 units/systemd-fsckd.socket
-
-diff --git a/Makefile-man.am b/Makefile-man.am
-index 85579e0..d52f445 100644
---- a/Makefile-man.am
-+++ b/Makefile-man.am
-@@ -66,6 +66,7 @@ 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 \
-@@ -208,6 +209,8 @@ 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 \
-@@ -318,6 +321,8 @@ 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
-@@ -596,6 +601,12 @@ 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)
-
-@@ -1808,6 +1819,7 @@ 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 51b2dd4..6753812 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -400,6 +400,7 @@ rootlibexec_PROGRAMS = \
- systemd-remount-fs \
- systemd-reply-password \
- systemd-fsck \
-+ systemd-fsckd \
- systemd-machine-id-commit \
- systemd-ac-power \
- systemd-sysctl \
-@@ -504,6 +505,7 @@ 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 \
-@@ -554,6 +556,7 @@ 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 \
-@@ -611,6 +614,7 @@ 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 \
-@@ -2398,6 +2402,16 @@ systemd_fsck_LDADD = \
- libsystemd-shared.la
-
- # ------------------------------------------------------------------------------
-+systemd_fsckd_SOURCES = \
-+ src/fsckd/fsckd.c \
-+ $(NULL)
-+
-+systemd_fsckd_LDADD = \
-+ libsystemd-internal.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-fsckd.service.xml b/man/systemd-fsckd.service.xml
-new file mode 100644
-index 0000000..c976062
---- /dev/null
-+++ b/man/systemd-fsckd.service.xml
-@@ -0,0 +1,162 @@
-+<?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>fsck</command> through an
-+ 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>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/po/POTFILES.in b/po/POTFILES.in
-index b4c1121..70e7594 100644
---- a/po/POTFILES.in
-+++ b/po/POTFILES.in
-@@ -5,3 +5,4 @@ src/locale/org.freedesktop.locale1.policy.in
- src/login/org.freedesktop.login1.policy.in
- src/machine/org.freedesktop.machine1.policy.in
- src/timedate/org.freedesktop.timedate1.policy.in
-+src/fsckd/fsckd.c
-diff --git a/src/fsckd/fsckd.c b/src/fsckd/fsckd.c
-new file mode 100644
-index 0000000..e170d7f
---- /dev/null
-+++ b/src/fsckd/fsckd.c
-@@ -0,0 +1,680 @@
-+/*-*- 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"
-+
-+#define FSCKD_SOCKET_PATH "/run/systemd/fsck.progress"
-+#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;
-+ char *device_name;
-+ /* device id refers to "fd <fd>" until it gets a name as "device_name" */
-+ char *device_id;
-+
-+ pid_t fsck_pid;
-+ FILE *fsck_f;
-+
-+ size_t cur;
-+ size_t max;
-+ int pass;
-+
-+ double percent;
-+
-+ bool cancelled;
-+ bool bad_input;
-+
-+ 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) {
-+ assert(c);
-+
-+ if (c->cancelled)
-+ return 0;
-+
-+ log_info("Request to cancel fsck for %s from fsckd", c->device_id);
-+ if (kill(c->fsck_pid, SIGTERM) < 0) {
-+ /* ignore the error and consider that cancel was sent if fsck just exited */
-+ if (errno != ESRCH)
-+ return log_error_errno(errno, "Cannot send cancel to fsck for %s: %m", c->device_id);
-+ }
-+
-+ 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);
-+ fclose(c->fsck_f);
-+ if (c->device_name)
-+ free(c->device_name);
-+ if (c->device_id)
-+ free(c->device_id);
-+ 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;
-+ char line[LINE_MAX];
-+ Manager *m;
-+
-+ assert(client);
-+ m = client->manager;
-+
-+ /* check first if we need to cancel this client */
-+ if (m->cancel_requested)
-+ client_request_cancel(client);
-+
-+ while (fgets(line, sizeof(line), client->fsck_f) != NULL) {
-+ int pass;
-+ size_t cur, max;
-+ _cleanup_free_ char *device = NULL, *old_device_id = NULL;
-+
-+ if (sscanf(line, "%i %lu %lu %ms", &pass, &cur, &max, &device) == 4) {
-+ if (!client->device_name) {
-+ client->device_name = strdup(device);
-+ if (!client->device_name) {
-+ log_oom();
-+ continue;
-+ }
-+ old_device_id = client->device_id;
-+ client->device_id = strdup(device);
-+ if (!client->device_id) {
-+ log_oom();
-+ client->device_id = old_device_id;
-+ old_device_id = NULL;
-+ continue;
-+ }
-+ }
-+ client->pass = pass;
-+ client->cur = cur;
-+ client->max = max;
-+ client->bad_input = false;
-+ client->percent = compute_percent(client->pass, client->cur, client->max);
-+ log_debug("Getting progress for %s (%lu, %lu, %d) : %3.1f%%", client->device_id,
-+ client->cur, client->max, client->pass, client->percent);
-+ } else {
-+ if (errno == ENOMEM) {
-+ log_oom();
-+ continue;
-+ }
-+
-+ /* if previous input was already garbage, kick it off from progress report */
-+ if (client->bad_input) {
-+ log_warning("Closing connection on incorrect input of fsck connection for %s", client->device_id);
-+ client_free(client);
-+ manager_update_global_progress(m);
-+ return 0;
-+ }
-+ client->bad_input = true;
-+ }
-+
-+ }
-+
-+ if (feof(client->fsck_f)) {
-+ log_debug("Fsck client %s disconnected", client->device_id);
-+ client_free(client);
-+ }
-+
-+ 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_fsck_fd = -1;
-+ _cleanup_fclose_ FILE *new_fsck_f = NULL;
-+ struct ucred ucred = {};
-+ Manager *m = userdata;
-+ int r;
-+
-+ assert(m);
-+
-+ /* Initialize and list new clients */
-+ new_fsck_fd = accept4(m->connection_fd, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
-+ if (new_fsck_fd < 0) {
-+ log_error_errno(errno, "Couldn't accept a new connection: %m");
-+ return 0;
-+ }
-+
-+ if (m->n_clients >= CLIENTS_MAX) {
-+ log_error("Too many clients, refusing connection.");
-+ return 0;
-+ }
-+
-+
-+ new_fsck_f = fdopen(new_fsck_fd, "r");
-+ if (!new_fsck_f) {
-+ log_error_errno(errno, "Couldn't fdopen new connection for fd %d: %m", new_fsck_fd);
-+ return 0;
-+ }
-+ new_fsck_fd = -1;
-+
-+ r = getpeercred(fileno(new_fsck_f), &ucred);
-+ if (r < 0) {
-+ log_error_errno(r, "Couldn't get credentials for fsck: %m");
-+ return 0;
-+ }
-+
-+ c = new0(Client, 1);
-+ if (!c) {
-+ log_oom();
-+ return 0;
-+ }
-+
-+ c->fsck_pid = ucred.pid;
-+ c->fsck_f = new_fsck_f;
-+ new_fsck_f = NULL;
-+
-+ if (asprintf(&(c->device_id), "fd %d", fileno(c->fsck_f)) < 0) {
-+ log_oom();
-+ return 0;
-+ }
-+
-+ r = sd_event_add_io(m->event, &c->event_source, fileno(c->fsck_f), EPOLLIN, client_progress_handler, c);
-+ if (r < 0) {
-+ log_oom();
-+ return 0;
-+ }
-+
-+ LIST_PREPEND(clients, m->clients, c);
-+ m->n_clients++;
-+ c->manager = m;
-+
-+ log_debug("New fsck client connected: %s", c->device_id);
-+
-+ /* 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/units/systemd-fsck-root.service.in b/units/systemd-fsck-root.service.in
-index 3617abf..f493445 100644
---- a/units/systemd-fsck-root.service.in
-+++ b/units/systemd-fsck-root.service.in
-@@ -9,7 +9,9 @@
- 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 0468392..e6d98c0 100644
---- a/units/systemd-fsck@.service.in
-+++ b/units/systemd-fsck@.service.in
-@@ -10,7 +10,8 @@ Description=File System Check on %f
- Documentation=man:systemd-fsck@.service(8)
- DefaultDependencies=no
- BindsTo=%i.device
--After=%i.device systemd-fsck-root.service local-fs-pre.target
-+Wants=systemd-fsckd.socket
-+After=%i.device systemd-fsck-root.service local-fs-pre.target systemd-fsckd.socket
- Before=shutdown.target
-
- [Service]
-diff --git a/units/systemd-fsckd.service.in b/units/systemd-fsckd.service.in
-new file mode 100644
-index 0000000..9c7ed51
---- /dev/null
-+++ b/units/systemd-fsckd.service.in
-@@ -0,0 +1,17 @@
-+# 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
-new file mode 100644
-index 0000000..61fec97
---- /dev/null
-+++ b/units/systemd-fsckd.socket
-@@ -0,0 +1,15 @@
-+# 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/fsck.progress
-+SocketMode=0600
+++ /dev/null
-From: Michael Biebl <biebl@debian.org>
-Date: Fri, 28 Jun 2013 17:54:41 +0200
-Subject: insserv.conf generator
-
-Parse /etc/insserv.conf.d content and /etc/insserv.conf and generate
-systemd unit drop-in files to add corresponding dependencies.
-
-This patch is based on work by Frederic Crozat <fcrozat@suse.com>.
-See [0] for the original patch.
-
-It has the following modifications:
-- it removes support for boot. and bool.localfs which is a SuSE specific
- extension
-- it ensures that targets do not start other targets or services
-- maps $x-display-manager to display-manager.service, just like the
- sysv-generator
-
-[0] https://build.opensuse.org/package/view_file/openSUSE:Factory/systemd/insserv-generator.patch
----
- Makefile.am | 9 +
- src/insserv-generator/Makefile | 28 +++
- src/insserv-generator/insserv-generator.c | 329 ++++++++++++++++++++++++++++++
- 3 files changed, 366 insertions(+)
- create mode 100644 src/insserv-generator/Makefile
- create mode 100644 src/insserv-generator/insserv-generator.c
-
-diff --git a/Makefile.am b/Makefile.am
-index 89d94a0..aa1edd3 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -414,6 +414,7 @@ rootlibexec_PROGRAMS += \
- endif
-
- systemgenerator_PROGRAMS = \
-+ systemd-insserv-generator \
- systemd-getty-generator \
- systemd-fstab-generator \
- systemd-system-update-generator \
-@@ -2433,6 +2434,13 @@ systemd_delta_LDADD = \
- libsystemd-shared.la
-
- # ------------------------------------------------------------------------------
-+systemd_insserv_generator_SOURCES = \
-+ src/insserv-generator/insserv-generator.c
-+
-+systemd_insserv_generator_LDADD = \
-+ libsystemd-internal.la
-+
-+# ------------------------------------------------------------------------------
- systemd_getty_generator_SOURCES = \
- src/getty-generator/getty-generator.c
-
-diff --git a/src/insserv-generator/Makefile b/src/insserv-generator/Makefile
-new file mode 100644
-index 0000000..9d07505
---- /dev/null
-+++ b/src/insserv-generator/Makefile
-@@ -0,0 +1,28 @@
-+# This file is part of systemd.
-+#
-+# Copyright 2010 Lennart Poettering
-+#
-+# 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/>.
-+
-+# This file is a dirty trick to simplify compilation from within
-+# emacs. This file is not intended to be distributed. So, don't touch
-+# it, even better ignore it!
-+
-+all:
-+ $(MAKE) -C ..
-+
-+clean:
-+ $(MAKE) -C .. clean
-+
-+.PHONY: all clean
-diff --git a/src/insserv-generator/insserv-generator.c b/src/insserv-generator/insserv-generator.c
-new file mode 100644
-index 0000000..109f731
---- /dev/null
-+++ b/src/insserv-generator/insserv-generator.c
-@@ -0,0 +1,329 @@
-+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-+
-+/***
-+ This file is part of systemd.
-+
-+ Copyright 2012 Lennart Poettering
-+
-+ 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 <stdio.h>
-+#include <errno.h>
-+#include <string.h>
-+#include <sys/stat.h>
-+
-+#include "mkdir.h"
-+#include "log.h"
-+#include "fileio.h"
-+#include "unit-name.h"
-+#include "special.h"
-+#include "path-util.h"
-+#include "util.h"
-+#include "strv.h"
-+
-+static const char *arg_dest = "/tmp";
-+
-+static char *sysv_translate_name(const char *name) {
-+ char *r;
-+
-+ r = new(char, strlen(name) + sizeof(".service"));
-+ if (!r)
-+ return NULL;
-+
-+ if (endswith(name, ".sh"))
-+ /* Drop .sh suffix */
-+ strcpy(stpcpy(r, name) - 3, ".service");
-+ else
-+ /* Normal init script name */
-+ strcpy(stpcpy(r, name), ".service");
-+
-+ return r;
-+}
-+
-+static int sysv_translate_facility(const char *name, const char *filename, char **_r) {
-+
-+ /* We silently ignore the $ prefix here. According to the LSB
-+ * spec it simply indicates whether something is a
-+ * standardized name or a distribution-specific one. Since we
-+ * just follow what already exists and do not introduce new
-+ * uses or names we don't care who introduced a new name. */
-+
-+ static const char * const table[] = {
-+ /* LSB defined facilities */
-+ "local_fs", NULL,
-+ "network", SPECIAL_NETWORK_TARGET,
-+ "named", SPECIAL_NSS_LOOKUP_TARGET,
-+ "portmap", SPECIAL_RPCBIND_TARGET,
-+ "remote_fs", SPECIAL_REMOTE_FS_TARGET,
-+ "syslog", NULL,
-+ "time", SPECIAL_TIME_SYNC_TARGET,
-+ /* Debian defined facilities */
-+ "x-display-manager", "display-manager.service",
-+ };
-+
-+ unsigned i, e;
-+ char *r;
-+ const char *n;
-+
-+ assert(name);
-+ assert(_r);
-+
-+ n = *name == '$' ? name + 1 : name;
-+
-+ for (i = 0; i < ELEMENTSOF(table); i += 2) {
-+
-+ if (!streq(table[i], n))
-+ continue;
-+
-+ if (!table[i+1])
-+ return 0;
-+
-+ r = strdup(table[i+1]);
-+ if (!r)
-+ return log_oom();
-+
-+ goto finish;
-+ }
-+
-+ /* If we don't know this name, fallback heuristics to figure
-+ * out whether something is a target or a service alias. */
-+
-+ if (*name == '$') {
-+ if (!unit_prefix_is_valid(n))
-+ return -EINVAL;
-+
-+ /* Facilities starting with $ are most likely targets */
-+ e = unit_name_build(n, NULL, ".target", &r);
-+ if (e < 0)
-+ return log_error_errno(e, "Failed to generate unit name: %m");
-+
-+ } else if (filename && streq(name, filename))
-+ /* Names equaling the file name of the services are redundant */
-+ return 0;
-+ else
-+ /* Everything else we assume to be normal service names */
-+ r = sysv_translate_name(n);
-+
-+ if (!r)
-+ return -ENOMEM;
-+
-+finish:
-+ *_r = r;
-+
-+ return 1;
-+}
-+
-+
-+
-+static int parse_insserv_conf(const char* filename) {
-+ _cleanup_fclose_ FILE *f = NULL;
-+ int r;
-+
-+ if (!(f = fopen(filename, "re"))) {
-+ log_debug("Failed to open file %s", filename);
-+ r = errno == ENOENT ? 0 : -errno;
-+ return r;
-+ }
-+
-+ while (!feof(f)) {
-+ char l[LINE_MAX], *t;
-+ _cleanup_strv_free_ char **parsed = NULL;
-+
-+ if (!fgets(l, sizeof(l), f)) {
-+ if (feof(f))
-+ break;
-+
-+ r = -errno;
-+ log_error("Failed to read configuration file '%s': %s", filename, strerror(-r));
-+ return -r;
-+ }
-+
-+ t = strstrip(l);
-+ if (*t != '$' && *t != '<')
-+ continue;
-+
-+ parsed = strv_split(t,WHITESPACE);
-+ /* we ignore <interactive>, not used, equivalent to X-Interactive */
-+ if (parsed && !startswith_no_case (parsed[0], "<interactive>")) {
-+ _cleanup_free_ char *facility = NULL;
-+ if (sysv_translate_facility(parsed[0], NULL, &facility) < 0 || !facility)
-+ continue;
-+ if (streq(facility, SPECIAL_REMOTE_FS_TARGET)) {
-+ _cleanup_free_ char *unit = NULL;
-+ /* insert also a Wants dependency from remote-fs-pre on remote-fs */
-+ unit = strjoin(arg_dest, "/remote-fs.target.d/50-",basename(filename),".conf", NULL);
-+ if (!unit)
-+ return log_oom();
-+
-+ mkdir_parents_label(unit, 0755);
-+
-+ r = write_string_file(unit,
-+ "# Automatically generated by systemd-insserv-generator\n\n"
-+ "[Unit]\n"
-+ "Wants=remote-fs-pre.target\n");
-+ if (r)
-+ return r;
-+ free (facility);
-+ facility=strdup(SPECIAL_REMOTE_FS_PRE_TARGET);
-+ }
-+ if (facility && endswith(facility, ".target")) {
-+ char *name, **j;
-+ FILE *file = NULL;
-+
-+ STRV_FOREACH (j, parsed+1) {
-+ _cleanup_free_ char *unit = NULL;
-+ _cleanup_free_ char *dep = NULL;
-+ _cleanup_free_ char *initscript = NULL;
-+
-+ /* targets should not pull in and activate other targets so skip them */
-+ if (*j[0] == '$')
-+ continue;
-+
-+ if (*j[0] == '+')
-+ name = *j+1;
-+ else
-+ name = *j;
-+ if ((sysv_translate_facility(name, NULL, &dep) < 0) || !dep)
-+ continue;
-+
-+ /* don't create any drop-in configs if the
-+ * corresponding SysV init script does not exist */
-+ initscript = strjoin("/etc/init.d/", name, NULL);
-+ if (access(initscript, F_OK) < 0) {
-+ _cleanup_free_ char *initscript_sh = NULL;
-+
-+ /* Try *.sh source'able init scripts */
-+ initscript_sh = strjoin(initscript, ".sh", NULL);
-+ if (access(initscript_sh, F_OK) < 0) {
-+ continue;
-+ }
-+ }
-+
-+ unit = strjoin(arg_dest, "/", dep, ".d/50-",basename(filename),"-",parsed[0],".conf", NULL);
-+ if (!unit)
-+ return log_oom();
-+
-+ mkdir_parents_label(unit, 0755);
-+
-+ file = fopen(unit, "wxe");
-+ if (!file) {
-+ if (errno == EEXIST)
-+ log_error("Failed to create drop-in file %s", unit);
-+ else
-+ log_error("Failed to create drop-in file %s: %m", unit);
-+ return -errno;
-+ }
-+
-+ fprintf(file,
-+ "# Automatically generated by systemd-insserv-generator\n\n"
-+ "[Unit]\n"
-+ "Wants=%s\n"
-+ "Before=%s\n",
-+ facility, facility);
-+
-+ fflush(file);
-+ if (ferror(file)) {
-+ log_error("Failed to write unit file %s: %m", unit);
-+ return -errno;
-+ }
-+ fclose(file);
-+
-+ if (*j[0] != '+') {
-+ free (unit);
-+ unit = strjoin(arg_dest, "/", facility, ".d/50-hard-dependency-",basename(filename),"-",parsed[0],".conf", NULL);
-+ if (!unit)
-+ return log_oom();
-+
-+ mkdir_parents_label(unit, 0755);
-+
-+ file = fopen(unit, "wxe");
-+ if (!file) {
-+ if (errno == EEXIST)
-+ log_error("Failed to create drop-in file %s, as it already exists", unit);
-+ else
-+ log_error("Failed to create drop-in file %s: %m", unit);
-+ return -errno;
-+ }
-+
-+
-+ fprintf(file,
-+ "# Automatically generated by systemd-insserv-generator\n\n"
-+ "[Unit]\n"
-+ "SourcePath=%s\n"
-+ "Requires=%s\n",
-+ filename, dep);
-+ fflush(file);
-+ if (ferror(file)) {
-+ log_error("Failed to write unit file %s: %m", unit);
-+ return -errno;
-+ }
-+ fclose(file);
-+ }
-+ }
-+ }
-+ }
-+ }
-+ return r;
-+}
-+
-+static int parse_insserv(void) {
-+ DIR *d = NULL;
-+ struct dirent *de;
-+ int r = 0;
-+
-+ if (!(d = opendir("/etc/insserv.conf.d/"))) {
-+ if (errno != ENOENT) {
-+ log_debug("opendir() failed on /etc/insserv.conf.d/ %s", strerror(errno));
-+ }
-+ } else {
-+
-+ while ((de = readdir(d))) {
-+ char *path = NULL;
-+ if (hidden_file(de->d_name))
-+ continue;
-+
-+ path = strjoin("/etc/insserv.conf.d/", de->d_name, NULL);
-+ parse_insserv_conf(path);
-+ free(path);
-+ }
-+ closedir (d);
-+ }
-+
-+ r = parse_insserv_conf("/etc/insserv.conf");
-+
-+ return r;
-+}
-+
-+int main(int argc, char *argv[]) {
-+ int r = 0;
-+
-+ if (argc > 1 && argc != 4) {
-+ log_error("This program takes three or no arguments.");
-+ return EXIT_FAILURE;
-+ }
-+
-+ if (argc > 1)
-+ arg_dest = argv[1];
-+
-+ log_set_target(LOG_TARGET_SAFE);
-+ log_parse_environment();
-+ log_open();
-+
-+ umask(0022);
-+
-+ r = parse_insserv();
-+
-+ return (r < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
-+}