From ceb4eef697ee6f7cef509911aa071c0cbfd334a0 Mon Sep 17 00:00:00 2001
From: Didier Roche <didrocks@ubuntu.com>
Date: Thu, 9 Apr 2015 15:24:09 +0200
Subject: [PATCH 1/3] Add fsckd patch prepared to get out of upstream trunk

Note that Add-gettext-support.patch is kept separated for now as it may
stay upstream.
---
 debian/changelog                                   |   10 +-
 debian/patches/Add-gettext-support.patch           |    2 +
 ...sckd-daemon-for-inter-fsckd-communication.patch | 1326 +++++++++++++++++---
 debian/patches/series                              |   10 +-
 4 files changed, 1136 insertions(+), 212 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index e16502f..91f3246 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -11,14 +11,18 @@ systemd (219-7) UNRELEASED; urgency=medium
   * display-managers autopkgtest: Reset failed units between tests, to avoid
     running into restart limits and for better test isolation.
   * Enable timesyncd in virtual machines. (Closes: #762343)
-  * fsck, fsckd: Grab various fixes from upstream git. Amongst others, this
-    suppresses "Couldn't connect to plymouth" errors if plymouth is not
-    running. (LP: #1429171)
 
   [ Adam Conrad ]
   * debian/systemd.{triggers,postinst}: Trigger a systemctl daemon-reload
     when init scripts are installed or removed (Closes: #766429)
 
+  [ Didier Roche ]
+  * Squash all fsckd patches in one (as fsckd and such will be removed
+    soon upstream), containing various fixes from upstream git and refactor
+    the connection flow to upstream's suggestion. Modify the man pages to match
+    those modifications as well. Amongst others, this suppresses "Couldn't
+    connect to plymouth" errors if plymouth is not running. (LP: #1429171)
+
  -- Martin Pitt <mpitt@debian.org>  Mon, 06 Apr 2015 13:19:37 +0200
 
 systemd (219-6) experimental; urgency=medium
diff --git a/debian/patches/Add-gettext-support.patch b/debian/patches/Add-gettext-support.patch
index d65c2f3..091efb3 100644
--- a/debian/patches/Add-gettext-support.patch
+++ b/debian/patches/Add-gettext-support.patch
@@ -2,6 +2,8 @@ From: Didier Roche <didrocks@ubuntu.com>
 Date: Thu, 29 Jan 2015 16:12:58 +0100
 Subject: Add gettext support
 
+Note that this patch was part of the fsckd set. Need to track if upstream
+keeps it (as used in our fsckd patch).
 ---
  configure.ac      | 1 +
  src/shared/util.c | 8 ++++++++
diff --git a/debian/patches/fsckd-daemon-for-inter-fsckd-communication.patch b/debian/patches/fsckd-daemon-for-inter-fsckd-communication.patch
index f0d00f9..b5affe1 100644
--- a/debian/patches/fsckd-daemon-for-inter-fsckd-communication.patch
+++ b/debian/patches/fsckd-daemon-for-inter-fsckd-communication.patch
@@ -1,30 +1,123 @@
 From: Didier Roche <didrocks@ubuntu.com>
-Date: Wed, 4 Feb 2015 16:42:47 +0100
+Date: Thu, 9 Apr 2015 11:56:51 +0200
 Subject: fsckd daemon for inter-fsckd communication
 
-Add systemd-fsckd multiplexer which accepts multiple systemd-fsck
-instances to connect to it and sends progress report. systemd-fsckd then
+Global logic:
+Add systemd-fsckd multiplexer which accepts multiple (via systemd-fsck)
+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. This will be used for interactive
-progress report and cancelling in plymouth.
+checked and the minimum fsck progress. Make the necessary changes to
+systemd-fsck to connect to pass fsck to the systemd-fsckd socket.
 
-systemd-fsckd stops on idle when no systemd-fsck is connected.
+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.
 
-Make the necessary changes to systemd-fsck to connect to the systemd-fsckd
-socket.
+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.
+Also, add mock fsck process.
+
+Note that this patch (without fsck direct connexion to systemd-fsckd) lived it
+upstream tree for a while, but was removed. More information at
+http://lists.freedesktop.org/archives/systemd-devel/2015-April/030175.html
 ---
- Makefile.am        |  13 ++
- src/fsck/fsck.c    |  88 ++++--------
- src/fsckd/Makefile |   1 +
- src/fsckd/fsckd.c  | 404 +++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/fsckd/fsckd.h  |  34 +++++
- 5 files changed, 483 insertions(+), 57 deletions(-)
+ Makefile-man.am                    |  12 +
+ Makefile.am                        |  17 +
+ man/systemd-fsck@.service.xml      |  31 +-
+ man/systemd-fsckd.service.xml      | 162 +++++++++
+ src/fsck/fsck.c                    | 195 ++++-------
+ src/fsckd/Makefile                 |   1 +
+ src/fsckd/fsckd.c                  | 680 +++++++++++++++++++++++++++++++++++++
+ src/fsckd/fsckd.h                  |  25 ++
+ test/mocks/fsck                    |  27 ++
+ units/systemd-fsck-root.service.in |   3 +-
+ units/systemd-fsck@.service.in     |   4 +-
+ units/systemd-fsckd.service.in     |  17 +
+ units/systemd-fsckd.socket         |  15 +
+ 13 files changed, 1045 insertions(+), 144 deletions(-)
+ create mode 100644 man/systemd-fsckd.service.xml
  create mode 120000 src/fsckd/Makefile
  create mode 100644 src/fsckd/fsckd.c
  create mode 100644 src/fsckd/fsckd.h
+ create mode 100755 test/mocks/fsck
+ 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 d0fb9aa..7a9612e 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 \
+@@ -209,6 +210,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 \
+@@ -321,6 +324,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
+@@ -601,6 +606,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)
+ 
+@@ -1738,6 +1749,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 aadaad2..7423590 100644
+index 5c9e5cd..7974185 100644
 --- a/Makefile.am
 +++ b/Makefile.am
 @@ -391,6 +391,7 @@ rootlibexec_PROGRAMS = \
@@ -35,12 +128,37 @@ index aadaad2..7423590 100644
  	systemd-machine-id-commit \
  	systemd-ac-power \
  	systemd-sysctl \
-@@ -2357,6 +2358,18 @@ systemd_fsck_LDADD = \
+@@ -495,6 +496,7 @@ dist_systemunit_DATA = \
+ 	units/slices.target \
+ 	units/system.slice \
+ 	units/x-.slice \
++	units/systemd-fsckd.socket \
+ 	units/systemd-initctl.socket \
+ 	units/systemd-shutdownd.socket \
+ 	units/syslog.socket \
+@@ -546,6 +548,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 \
+@@ -604,6 +607,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 \
+@@ -2362,6 +2366,19 @@ systemd_fsck_LDADD = \
  	libsystemd-shared.la
  
  # ------------------------------------------------------------------------------
 +systemd_fsckd_SOURCES = \
 +	src/fsckd/fsckd.c \
++	src/fsckd/fsckd.h \
 +	$(NULL)
 +
 +systemd_fsckd_LDADD = \
@@ -54,20 +172,254 @@ index aadaad2..7423590 100644
  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 32ba062..aff212f 100644
+--- a/man/systemd-fsck@.service.xml
++++ b/man/systemd-fsck@.service.xml
+@@ -50,7 +50,7 @@
+   <refsynopsisdiv>
+     <para><filename>systemd-fsck@.service</filename></para>
+     <para><filename>systemd-fsck-root.service</filename></para>
+-    <para><filename>/lib/systemd/systemd-fsck</filename></para>
++    <para><filename>/usr/lib/systemd/systemd-fsck</filename></para>
+   </refsynopsisdiv>
+ 
+   <refsect1>
+@@ -80,11 +80,11 @@
+     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 the console. 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>
++    <para><filename>systemd-fsck</filename> will forward fsck socket
++    for checking progress to <filename>systemd-fsckd.service</filename>
++    socket. 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>
+ 
+   <refsect1>
+@@ -125,16 +125,17 @@
+     <title>See Also</title>
+     <para>
+       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+-      <citerefentry><refentrytitle>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><refentrytitle>fsck.btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+-      <citerefentry><refentrytitle>fsck.cramfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+-      <citerefentry><refentrytitle>fsck.ext4</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+-      <citerefentry><refentrytitle>fsck.fat</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+-      <citerefentry><refentrytitle>fsck.hfsplus</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+-      <citerefentry><refentrytitle>fsck.minix</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+-      <citerefentry><refentrytitle>fsck.ntfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+-      <citerefentry><refentrytitle>fsck.xfs</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/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:&lt;num_devices&gt;:&lt;progress&gt;:&lt;string&gt;</literal>
++      <variablelist>
++        <varlistentry>
++          <term><literal>&lt;num_devices&gt;</literal></term>
++          <listitem><para>the current number of devices
++          being checked (int)</para></listitem>
++        </varlistentry>
++        <varlistentry>
++          <term><literal>&lt;progress&gt;</literal></term>
++          <listitem><para>the current minimum percentage of
++          all devices being checking (float, from 0 to 100)</para></listitem>
++        </varlistentry>
++        <varlistentry>
++          <term><literal>&lt;string&gt;</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:&lt;string&gt;</literal>
++      <variablelist>
++        <varlistentry>
++          <term><literal>&lt;strings&gt;</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/src/fsck/fsck.c b/src/fsck/fsck.c
-index 78ceeb6..6ccb2e7 100644
+index 78ceeb6..b3dbd29 100644
 --- a/src/fsck/fsck.c
 +++ b/src/fsck/fsck.c
-@@ -27,6 +27,7 @@
+@@ -22,11 +22,12 @@
+ 
+ #include <stdio.h>
+ #include <stdbool.h>
+-#include <string.h>
+ #include <errno.h>
  #include <unistd.h>
  #include <fcntl.h>
  #include <sys/file.h>
 +#include <sys/stat.h>
++#include <sys/socket.h>
  
  #include "sd-bus.h"
  #include "libudev.h"
-@@ -39,6 +40,8 @@
- #include "fileio.h"
+@@ -36,13 +37,13 @@
+ #include "bus-util.h"
+ #include "bus-error.h"
+ #include "bus-common-errors.h"
+-#include "fileio.h"
  #include "udev-util.h"
  #include "path-util.h"
 +#include "socket-util.h"
@@ -75,8 +427,16 @@ index 78ceeb6..6ccb2e7 100644
  
  static bool arg_skip = false;
  static bool arg_force = false;
-@@ -132,58 +135,36 @@ static void test_files(void) {
-                 arg_show_progress = true;
+-static bool arg_show_progress = false;
+ static const char *arg_repair = "-a";
+ 
+ static void start_target(const char *target) {
+@@ -128,88 +129,26 @@ static void test_files(void) {
+         }
+ #endif
+ 
+-        if (access("/run/systemd/show-status", F_OK) >= 0 || plymouth_running())
+-                arg_show_progress = true;
  }
  
 -static double percent(int pass, unsigned long cur, unsigned long max) {
@@ -84,14 +444,12 @@ index 78ceeb6..6ccb2e7 100644
 -
 -        static const int pass_table[] = {
 -                0, 70, 90, 92, 95, 100
-+static int process_progress(int fd, dev_t device_num) {
-+        _cleanup_fclose_ FILE *f = NULL;
-+        usec_t last = 0;
-+        _cleanup_close_ int fsckd_fd = -1;
++static int make_progress_fd(void) {
 +        static const union sockaddr_union sa = {
 +                .un.sun_family = AF_UNIX,
 +                .un.sun_path = FSCKD_SOCKET_PATH,
          };
++        int fsck_fd;
  
 -        if (pass <= 0)
 -                return 0.0;
@@ -109,13 +467,8 @@ index 78ceeb6..6ccb2e7 100644
 -        usec_t last = 0;
 -        bool locked = false;
 -        int clear = 0;
-+        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");
+-
+-        f = fdopen(fd, "r");
 -        if (!f) {
 -                safe_close(fd);
 -                return -errno;
@@ -124,39 +477,37 @@ index 78ceeb6..6ccb2e7 100644
 -        console = fopen("/dev/console", "we");
 -        if (!console)
 -                return -ENOMEM;
-+        if (!f)
-+                return log_warning_errno(errno, "Cannot connect to fsck, we won't report fsck progress: %m");
- 
-         while (!feof(f)) {
+-
+-        while (!feof(f)) {
 -                int pass, m;
 -                unsigned long cur, max;
 -                _cleanup_free_ char *device = NULL;
 -                double p;
-+                int pass;
-+                size_t cur, max;
-+                ssize_t n;
-                 usec_t t;
-+                _cleanup_free_ char *device = NULL;
-+                FsckProgress progress;
- 
-                 if (fscanf(f, "%i %lu %lu %ms", &pass, &cur, &max, &device) != 4)
-                         break;
+-                usec_t t;
+-
+-                if (fscanf(f, "%i %lu %lu %ms", &pass, &cur, &max, &device) != 4)
+-                        break;
++        fsck_fd = socket(AF_UNIX, SOCK_STREAM, 0);
++        if (fsck_fd < 0)
++                return log_warning_errno(errno, "Cannot crate fsck socket, we won't report fsck progress: %m");
  
 -                /* Only show one progress counter at max */
 -                if (!locked) {
 -                        if (flock(fileno(console), LOCK_EX|LOCK_NB) < 0)
 -                                continue;
--
++        if (shutdown(fsck_fd, SHUT_RD) < 0)
++                return log_warning_errno(errno, "Cannot make fsck socket write-only, we won't report fsck progress: %m");
+ 
 -                        locked = true;
 -                }
 -
-                 /* Only update once every 50ms */
-                 t = now(CLOCK_MONOTONIC);
-                 if (last + 50 * USEC_PER_MSEC > t)
-@@ -191,22 +172,15 @@ static int process_progress(int fd) {
- 
-                 last = t;
- 
+-                /* Only update once every 50ms */
+-                t = now(CLOCK_MONOTONIC);
+-                if (last + 50 * USEC_PER_MSEC > t)
+-                        continue;
+-
+-                last = t;
+-
 -                p = percent(pass, cur, max);
 -                fprintf(console, "\r%s: fsck %3.1f%% complete...\r%n", device, p, &m);
 -                fflush(console);
@@ -167,32 +518,225 @@ index 78ceeb6..6ccb2e7 100644
 -
 -        if (clear > 0) {
 -                unsigned j;
-+                /* send progress to fsckd */
-+                progress.devnum = device_num;
-+                progress.cur = cur;
-+                progress.max = max;
-+                progress.pass = pass;
- 
+-
 -                fputc('\r', console);
 -                for (j = 0; j < (unsigned) clear; j++)
 -                        fputc(' ', console);
 -                fputc('\r', console);
 -                fflush(console);
-+                n = send(fsckd_fd, &progress, sizeof(FsckProgress), 0);
-+                if (n < 0 || (size_t) n < sizeof(FsckProgress))
-+                        log_warning_errno(errno, "Cannot communicate fsck progress to fsckd: %m");
+-        }
++        if (connect(fsck_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");
+ 
+-        return 0;
++        return fsck_fd;
+ }
+ 
+ int main(int argc, char *argv[]) {
+@@ -221,8 +160,9 @@ int main(int argc, char *argv[]) {
+         _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL;
+         const char *device, *type;
+         bool root_directory;
+-        int progress_pipe[2] = { -1, -1 };
++        _cleanup_close_ int fsck_fd = -1;
+         char dash_c[sizeof("-C")-1 + DECIMAL_STR_MAX(int) + 1];
++        int fd_arg_index = -1;
+         struct stat st;
+ 
+         if (argc > 2) {
+@@ -242,13 +182,15 @@ int main(int argc, char *argv[]) {
+ 
+         test_files();
+ 
+-        if (!arg_force && arg_skip)
+-                return 0;
++        if (!arg_force && arg_skip) {
++                r = 0;
++                goto finish;
++        }
+ 
+         udev = udev_new();
+         if (!udev) {
+-                log_oom();
+-                return EXIT_FAILURE;
++                r = log_oom();
++                goto finish;
+         }
+ 
+         if (argc > 1) {
+@@ -256,14 +198,14 @@ int main(int argc, char *argv[]) {
+                 root_directory = false;
+ 
+                 if (stat(device, &st) < 0) {
+-                        log_error_errno(errno, "Failed to stat '%s': %m", device);
+-                        return EXIT_FAILURE;
++                        r = log_error_errno(errno, "Failed to stat '%s': %m", device);
++                        goto finish;
+                 }
+ 
+                 udev_device = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
+                 if (!udev_device) {
+-                        log_error("Failed to detect device %s", device);
+-                        return EXIT_FAILURE;
++                        r = log_error_errno(errno, "Failed to detect device %s", device);
++                        goto finish;
+                 }
+         } else {
+                 struct timespec times[2];
+@@ -271,32 +213,37 @@ int main(int argc, char *argv[]) {
+                 /* Find root device */
+ 
+                 if (stat("/", &st) < 0) {
+-                        log_error_errno(errno, "Failed to stat() the root directory: %m");
+-                        return EXIT_FAILURE;
++                        r = log_error_errno(errno, "Failed to stat() the root directory: %m");
++                        goto finish;
+                 }
+ 
+                 /* Virtual root devices don't need an fsck */
+-                if (major(st.st_dev) == 0)
+-                        return EXIT_SUCCESS;
++                if (major(st.st_dev) == 0) {
++                        log_debug("Root directory is virtual, skipping check.");
++                        r = 0;
++                        goto finish;
++                }
+ 
+                 /* check if we are already writable */
+                 times[0] = st.st_atim;
+                 times[1] = st.st_mtim;
+                 if (utimensat(AT_FDCWD, "/", times, 0) == 0) {
+                         log_info("Root directory is writable, skipping check.");
+-                        return EXIT_SUCCESS;
++                        r = 0;
++                        goto finish;
+                 }
+ 
+                 udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev);
+                 if (!udev_device) {
+-                        log_error("Failed to detect root device.");
+-                        return EXIT_FAILURE;
++                        r = log_error_errno(errno, "Failed to detect root device.");
++                        goto finish;
+                 }
+ 
+                 device = udev_device_get_devnode(udev_device);
+                 if (!device) {
+                         log_error("Failed to detect device node of root directory.");
+-                        return EXIT_FAILURE;
++                        r = -ENXIO;
++                        goto finish;
+                 }
+ 
+                 root_directory = true;
+@@ -307,17 +254,12 @@ int main(int argc, char *argv[]) {
+                 r = fsck_exists(type);
+                 if (r == -ENOENT) {
+                         log_info("fsck.%s doesn't exist, not checking file system on %s", type, device);
+-                        return EXIT_SUCCESS;
++                        r = 0;
++                        goto finish;
+                 } else if (r < 0)
+                         log_warning_errno(r, "fsck.%s cannot be used for %s: %m", type, device);
          }
  
-         return 0;
-@@ -358,7 +332,7 @@ int main(int argc, char *argv[]) {
-         progress_pipe[1] = safe_close(progress_pipe[1]);
+-        if (arg_show_progress)
+-                if (pipe(progress_pipe) < 0) {
+-                        log_error_errno(errno, "pipe(): %m");
+-                        return EXIT_FAILURE;
+-                }
+-
+         cmdline[i++] = "/sbin/fsck";
+         cmdline[i++] =  arg_repair;
+         cmdline[i++] = "-T";
+@@ -335,36 +277,37 @@ int main(int argc, char *argv[]) {
+         if (arg_force)
+                 cmdline[i++] = "-f";
  
-         if (progress_pipe[0] >= 0) {
+-        if (progress_pipe[1] >= 0) {
+-                xsprintf(dash_c, "-C%i", progress_pipe[1]);
+-                cmdline[i++] = dash_c;
+-        }
+-
++        /* mark index for -C arg */
++        fd_arg_index = i++;
+         cmdline[i++] = device;
+         cmdline[i++] = NULL;
+ 
+         pid = fork();
+         if (pid < 0) {
+-                log_error_errno(errno, "fork(): %m");
++                r = log_error_errno(errno, "fork(): %m");
+                 goto finish;
+         } else if (pid == 0) {
+                 /* Child */
+-                if (progress_pipe[0] >= 0)
+-                        safe_close(progress_pipe[0]);
+-                execv(cmdline[0], (char**) cmdline);
+-                _exit(8); /* Operational error */
+-        }
+ 
+-        progress_pipe[1] = safe_close(progress_pipe[1]);
++                /* create and connect systemd-fsckd socket to fsck fd.
++                   only log a warning if progress couldn't be reported
++                   but don't stop. */
++                fsck_fd = make_progress_fd();
++                if (fsck_fd >= 0) {
++                        xsprintf(dash_c, "-C%i", fsck_fd);
++                        cmdline[fd_arg_index] = dash_c;
++                } else
++                        /* put in a harmless and redundant option */
++                        cmdline[fd_arg_index] = "-T";
+ 
+-        if (progress_pipe[0] >= 0) {
 -                process_progress(progress_pipe[0]);
-+                process_progress(progress_pipe[0], st.st_rdev);
-                 progress_pipe[0] = -1;
+-                progress_pipe[0] = -1;
++                execv(cmdline[0], (char**) cmdline);
++                _exit(8); /* Operational error */
          }
++        safe_close(fsck_fd);
  
+-        q = wait_for_terminate(pid, &status);
+-        if (q < 0) {
+-                log_error_errno(q, "waitid(): %m");
++        r = wait_for_terminate(pid, &status);
++        if (r < 0) {
++                log_error_errno(r, "waitid(): %m");
+                 goto finish;
+         }
+ 
+@@ -377,25 +320,25 @@ int main(int argc, char *argv[]) {
+                 else
+                         log_error("fsck failed due to unknown reason.");
+ 
++                r = -EINVAL;
++
+                 if (status.si_code == CLD_EXITED && (status.si_status & 2) && root_directory)
+                         /* System should be rebooted. */
+                         start_target(SPECIAL_REBOOT_TARGET);
+                 else if (status.si_code == CLD_EXITED && (status.si_status & 6))
+                         /* Some other problem */
+                         start_target(SPECIAL_EMERGENCY_TARGET);
+-                else {
+-                        r = EXIT_SUCCESS;
++                else if (status.si_status == 15) {
++                        r = 0;
+                         log_warning("Ignoring error.");
+                 }
+ 
+         } else
+-                r = EXIT_SUCCESS;
++                r = 0;
+ 
+         if (status.si_code == CLD_EXITED && (status.si_status & 1))
+                 touch("/run/systemd/quotacheck");
+ 
+ finish:
+-        safe_close_pair(progress_pipe);
+-
+-        return r;
++        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ }
 diff --git a/src/fsckd/Makefile b/src/fsckd/Makefile
 new file mode 120000
 index 0000000..d0b0e8e
@@ -203,10 +747,10 @@ index 0000000..d0b0e8e
 \ No newline at end of file
 diff --git a/src/fsckd/fsckd.c b/src/fsckd/fsckd.c
 new file mode 100644
-index 0000000..39fe899
+index 0000000..31add9b
 --- /dev/null
 +++ b/src/fsckd/fsckd.c
-@@ -0,0 +1,404 @@
+@@ -0,0 +1,680 @@
 +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
 +
 +/***
@@ -233,6 +777,7 @@ index 0000000..39fe899
 +
 +#include <getopt.h>
 +#include <errno.h>
++#include <libintl.h>
 +#include <math.h>
 +#include <stdbool.h>
 +#include <stdlib.h>
@@ -242,46 +787,104 @@ index 0000000..39fe899
 +#include <sys/un.h>
 +#include <unistd.h>
 +
++#include "sd-daemon.h"
 +#include "build.h"
++#include "def.h"
 +#include "event-util.h"
-+#include "fsckd.h"
 +#include "log.h"
 +#include "list.h"
 +#include "macro.h"
-+#include "sd-daemon.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;
++        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;
-+        size_t buflen;
++
++        bool cancelled;
++        bool bad_input;
++
++        sd_event_source *event_source;
 +
 +        LIST_FIELDS(struct Client, clients);
 +} Client;
 +
 +typedef struct Manager {
 +        sd_event *event;
-+        Client *clients;
-+        int clear;
++
++        LIST_HEAD(Client, clients);
++        unsigned n_clients;
++
++        size_t clear;
++
 +        int connection_fd;
-+        FILE *console;
++        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);
-+#define _cleanup_manager_free_ _cleanup_(manager_freep)
++
++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 */
@@ -301,17 +904,177 @@ index 0000000..39fe899
 +                (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);
 +
-+static void remove_client(Client **first, Client *item) {
-+        LIST_REMOVE(clients, *first, item);
-+        safe_close(item->fd);
-+        free(item);
++        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 int update_global_progress(Manager *m) {
++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;
-+        int current_numdevices = 0, l = 0;
++        _cleanup_free_ char *fsck_message = NULL;
++        int current_numdevices = 0, r;
 +        double current_percent = 100;
 +
 +        /* get the overall percentage */
@@ -329,124 +1092,179 @@ index 0000000..39fe899
 +                m->numdevices = current_numdevices;
 +                m->percent = current_percent;
 +
-+                if (asprintf(&console_message, "Checking in progress on %d disks (%3.1f%% complete)",
-+                                                m->numdevices, m->percent) < 0)
++                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;
 +
-+                /* write to console */
-+                if (m->console) {
-+                        fprintf(m->console, "\r%s\r%n", console_message, &l);
-+                        fflush(m->console);
-+                }
++                if (asprintf(&fsck_message, "fsckd:%d:%3.1f:%s", m->numdevices, m->percent, console_message) < 0)
++                        return -ENOMEM;
 +
-+                if (l > m->clear)
-+                        m->clear = l;
++                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 progress_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
++static int client_progress_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
 +        Client *client = userdata;
-+        Manager *m = NULL;
-+        FsckProgress fsck_data;
-+        size_t buflen;
-+        int r;
++        char line[LINE_MAX];
++        Manager *m;
 +
 +        assert(client);
 +        m = client->manager;
 +
-+        /* 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);
-+                        remove_client(&(m->clients), client);
-+                        r = update_global_progress(m);
-+                        if (r < 0)
-+                                log_warning_errno(r, "Couldn't update global progress: %m");
++        /* 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;
 +                }
-+                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);
-+                remove_client(&(m->clients), 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");
-+
-+        r = update_global_progress(m);
-+        if (r < 0)
-+                log_warning_errno(r, "Couldn't update global progress: %m");
++        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 new_connection_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
++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;
-+        Client *client = NULL;
-+        int new_client_fd, r;
++        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) {
-+                log_debug("New fsck client connected to fd: %d", new_client_fd);
-+                client = new0(Client, 1);
-+                if (!client)
-+                        return log_oom();
-+                client->fd = new_client_fd;
-+                client->manager = m;
-+                LIST_PREPEND(clients, m->clients, client);
-+                r = sd_event_add_io(m->event, NULL, client->fd, EPOLLIN, progress_handler, client);
-+                if (r < 0) {
-+                        remove_client(&(m->clients), client);
-+                        return r;
-+                }
-+        } else
-+                return log_error_errno(errno, "Couldn't accept a new connection: %m");
++        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) {
-+        Client *current = NULL, *l = NULL;
 +        if (!m)
 +                return;
 +
 +        /* clear last line */
-+        if (m->console && m->clear > 0) {
-+                unsigned j;
-+
-+                fputc('\r', m->console);
-+                for (j = 0; j < (unsigned) m->clear; j++)
-+                        fputc(' ', m->console);
-+                fputc('\r', m->console);
-+                fflush(m->console);
-+        }
++        manager_write_console(m, NULL);
 +
++        sd_event_source_unref(m->connection_event_source);
 +        safe_close(m->connection_fd);
-+        if (m->console)
-+                fclose(m->console);
 +
-+        LIST_FOREACH_SAFE(clients, current, l, m->clients)
-+                remove_client(&(m->clients), current);
++        while (m->clients)
++                client_free(m->clients);
++
++        manager_disconnect_plymouth(m);
 +
 +        sd_event_unref(m->event);
 +
@@ -454,7 +1272,7 @@ index 0000000..39fe899
 +}
 +
 +static int manager_new(Manager **ret, int fd) {
-+        _cleanup_manager_free_ Manager *m = NULL;
++        _cleanup_(manager_freep) Manager *m = NULL;
 +        int r;
 +
 +        assert(ret);
@@ -463,15 +1281,20 @@ index 0000000..39fe899
 +        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;
 +
-+        m->connection_fd = fd;
-+        m->console = fopen("/dev/console", "we");
-+        if (!m->console)
-+                return log_warning_errno(errno, "Can't connect to /dev/console: %m");
-+        m->percent = 100;
++        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;
@@ -563,60 +1386,57 @@ index 0000000..39fe899
 +}
 +
 +int main(int argc, char *argv[]) {
-+        _cleanup_manager_free_ Manager *m = NULL;
++        _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)
-+                return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
++                goto finish;
 +
 +        n = sd_listen_fds(0);
 +        if (n > 1) {
 +                log_error("Too many file descriptors received.");
-+                return EXIT_FAILURE;
-+        } else if (n == 1) {
++                r = -EINVAL;
++                goto finish;
++        } else if (n == 1)
 +                fd = SD_LISTEN_FDS_START + 0;
-+        } else {
++        else {
 +                fd = make_socket_fd(LOG_DEBUG, FSCKD_SOCKET_PATH, SOCK_STREAM | SOCK_CLOEXEC);
 +                if (fd < 0) {
-+                        log_error_errno(r, "Couldn't create listening socket fd on %s: %m", FSCKD_SOCKET_PATH);
-+                        return EXIT_FAILURE;
++                        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");
-+                return EXIT_FAILURE;
-+        }
-+
-+        r = sd_event_add_io(m->event, NULL, fd, EPOLLIN, new_connection_handler, m);
-+        if (r < 0) {
-+                log_error_errno(r, "Can't listen to connection socket: %m");
-+                return EXIT_FAILURE;
++                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");
-+                return EXIT_FAILURE;
++                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
 new file mode 100644
-index 0000000..6fe37a7
+index 0000000..27a0d6b
 --- /dev/null
 +++ b/src/fsckd/fsckd.h
-@@ -0,0 +1,34 @@
+@@ -0,0 +1,25 @@
 +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
 +
 +/***
@@ -642,12 +1462,118 @@ index 0000000..6fe37a7
 +***/
 +
 +#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;
+diff --git a/test/mocks/fsck b/test/mocks/fsck
+new file mode 100755
+index 0000000..77b50d7
+--- /dev/null
++++ b/test/mocks/fsck
+@@ -0,0 +1,27 @@
++#!/bin/bash
++fd=0
++
++OPTIND=1
++while getopts "C:aTlM" opt; do
++    case "$opt" in
++        C)
++            fd=$OPTARG
++            ;;
++        \?);;
++    esac
++done
++
++shift "$((OPTIND-1))"
++device=$1
++
++echo "Running fake fsck on $device"
++
++declare -a maxpass=(30 5 2 30 60)
++
++for pass in {1..5}; do
++    maxprogress=${maxpass[$((pass-1))]}
++    for (( current=0; current<=${maxprogress}; current++)); do
++        echo "$pass $current $maxprogress $device">&$fd
++        sleep 0.1
++    done
++done
+diff --git a/units/systemd-fsck-root.service.in b/units/systemd-fsck-root.service.in
+index 6d76578..f493445 100644
+--- a/units/systemd-fsck-root.service.in
++++ b/units/systemd-fsck-root.service.in
+@@ -9,12 +9,13 @@
+ 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]
+ Type=oneshot
+ RemainAfterExit=yes
+ ExecStart=@rootlibexecdir@/systemd-fsck
+-StandardOutput=journal+console
+ TimeoutSec=0
+diff --git a/units/systemd-fsck@.service.in b/units/systemd-fsck@.service.in
+index 857e625..e6d98c0 100644
+--- a/units/systemd-fsck@.service.in
++++ b/units/systemd-fsck@.service.in
+@@ -10,12 +10,12 @@ 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]
+ Type=oneshot
+ RemainAfterExit=yes
+ ExecStart=@rootlibexecdir@/systemd-fsck %f
+-StandardOutput=journal+console
+ TimeoutSec=0
+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..92e8eef
+--- /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/fsckd
++SocketMode=0600
diff --git a/debian/patches/series b/debian/patches/series
index 2aa81ef..f192821 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,16 +1,7 @@
 ## Cherry-picked from upstream
 v219-stable.patch
 sysv-generator-fix-wrong-Overwriting-existing-symlin.patch
-fsckd-daemon-for-inter-fsckd-communication.patch
-systemd-fsck-always-connect-to-systemd-fsckd.patch
-Connect-to-plymouth-and-support-cancellation-of-in-p.patch
 Add-gettext-support.patch
-Translate-fsckd-messages-for-plymouth.patch
-fsck-fsckd-various-fixes.patch
-Refresh-po-files.patch
-Add-fsckd-service-and-socket-retarget-systemd-fsck.patch
-Add-man-page-and-references-to-it.patch
-Add-mock-fsck-process.patch
 units-move-After-systemd-hwdb-update.service-depende.patch
 timesyncd-enable-timesyncd-in-virtual-machines.patch
 
@@ -70,3 +61,4 @@ Revert-journald-allow-restarting-journald-without-lo.patch
 PrivateTmp-shouldn-t-require-tmpfs.patch
 path_is_mount_point-handle-false-positive-on-some-fs.patch
 syslog-Increase-max_dgram_qlen-by-pulling-in-systemd.patch
+fsckd-daemon-for-inter-fsckd-communication.patch
-- 
2.1.4

