Blame SOURCES/0001-src-die-during-shutdown-with-everything-else.patch

adeacd
From f55051678452647e035853ee94a89cb54ea2aa4a Mon Sep 17 00:00:00 2001
647dcb
From: Ray Strode <rstrode@redhat.com>
647dcb
Date: Fri, 17 Jul 2020 16:06:44 -0400
647dcb
Subject: [PATCH] src: die during shutdown with everything else
647dcb
647dcb
plymouthd currently avoids getting killed at shutdown.  This causes
647dcb
filesystems to fail to remount read-only in some cases.
647dcb
647dcb
This commit changes things up so that plymouthd dies with everyone else,
647dcb
but spawns a process to hold open the drm device that can keep the splash
647dcb
up until the very end.
adeacd
adeacd
In order to keep this process alive until the very end, it gets run
adeacd
from within the initramfs (if available).  This requires adding service
adeacd
files to jump back into the initramfs at shutdown
647dcb
---
adeacd
 configure.ac                                  |  1 +
adeacd
 scripts/plymouth-populate-initrd.in           |  2 +
adeacd
 src/Makefile.am                               |  7 +++
adeacd
 src/main.c                                    | 11 +++-
adeacd
 src/plugins/renderers/drm/Makefile.am         |  3 +-
adeacd
 src/plugins/renderers/drm/plugin.c            | 62 +++++++++++++++++++
adeacd
 src/plymouthd-drm-escrow.c                    | 18 ++++++
adeacd
 systemd-units/Makefile.am                     | 28 ++++++---
adeacd
 systemd-units/plymouth-halt.service.in        |  1 +
adeacd
 systemd-units/plymouth-poweroff.service.in    |  1 +
adeacd
 systemd-units/plymouth-reboot.service.in      |  1 +
adeacd
 .../plymouth-switch-root-initramfs.service.in | 12 ++++
adeacd
 12 files changed, 134 insertions(+), 13 deletions(-)
647dcb
 create mode 100644 src/plymouthd-drm-escrow.c
adeacd
 create mode 100644 systemd-units/plymouth-switch-root-initramfs.service.in
647dcb
adeacd
diff --git a/configure.ac b/configure.ac
adeacd
index 970e19f..1dc8cdb 100644
adeacd
--- a/configure.ac
adeacd
+++ b/configure.ac
adeacd
@@ -319,36 +319,37 @@ AC_CONFIG_FILES([Makefile po/Makefile.in
adeacd
            src/plugins/controls/label/Makefile
adeacd
            src/Makefile
adeacd
            src/client/ply-boot-client.pc
adeacd
            src/client/Makefile
adeacd
            src/upstart-bridge/Makefile
adeacd
            themes/Makefile
adeacd
            themes/spinfinity/Makefile
adeacd
            themes/fade-in/Makefile
adeacd
            themes/tribar/Makefile
adeacd
            themes/text/Makefile
adeacd
            themes/details/Makefile
adeacd
            themes/solar/Makefile
adeacd
            themes/glow/Makefile
adeacd
            themes/spinner/Makefile
adeacd
            themes/script/Makefile
adeacd
            themes/bgrt/Makefile
adeacd
            images/Makefile
adeacd
 	   scripts/plymouth-generate-initrd
adeacd
 	   scripts/plymouth-populate-initrd
adeacd
 	   scripts/plymouth-set-default-theme
adeacd
            scripts/Makefile
adeacd
            systemd-units/plymouth-halt.service
adeacd
            systemd-units/plymouth-kexec.service
adeacd
            systemd-units/plymouth-poweroff.service
adeacd
            systemd-units/plymouth-quit.service
adeacd
            systemd-units/plymouth-quit-wait.service
adeacd
            systemd-units/plymouth-read-write.service
adeacd
            systemd-units/plymouth-reboot.service
adeacd
            systemd-units/plymouth-start.service
adeacd
            systemd-units/plymouth-switch-root.service
adeacd
+           systemd-units/plymouth-switch-root-initramfs.service
adeacd
            systemd-units/systemd-ask-password-plymouth.path
adeacd
            systemd-units/systemd-ask-password-plymouth.service
adeacd
            systemd-units/Makefile
adeacd
            docs/Makefile
adeacd
 ])
adeacd
 AC_OUTPUT
adeacd
diff --git a/scripts/plymouth-populate-initrd.in b/scripts/plymouth-populate-initrd.in
adeacd
index 60fd063..535a896 100755
adeacd
--- a/scripts/plymouth-populate-initrd.in
adeacd
+++ b/scripts/plymouth-populate-initrd.in
adeacd
@@ -1,54 +1,55 @@
adeacd
 #!/bin/bash
adeacd
 #
adeacd
 # inst bits ruthlessly and viciously stolen from dracut
adeacd
 
adeacd
 [ -z "$DESTDIR" ] || exit 0
adeacd
 
adeacd
 # For running on a (cross-compiled) sysroot, the following
adeacd
 # settings are needed:
adeacd
 # PLYMOUTH_SYSROOT - the sysroot directory
adeacd
 # PLYMOUTH_LDD - an optional ldd command that works on foreign binaries
adeacd
 # PLYMOUTH_LDD_PATH - optional PATH ldd is run with
adeacd
 
adeacd
 [ -z "$PLYMOUTH_LDD" ] && PLYMOUTH_LDD="ldd"
adeacd
 [ -z "$PLYMOUTH_LDD_PATH" ] && PLYMOUTH_LDD_PATH="$PATH"
adeacd
 [ -z "$PLYMOUTH_LIBEXECDIR" ] && PLYMOUTH_LIBEXECDIR="@PLYMOUTH_LIBEXECDIR@"
adeacd
 [ -z "$PLYMOUTH_DATADIR" ] && PLYMOUTH_DATADIR="@PLYMOUTH_DATADIR@"
adeacd
 [ -z "$PLYMOUTH_PLUGIN_PATH" ] && PLYMOUTH_PLUGIN_PATH="$(plymouth --get-splash-plugin-path)"
adeacd
 [ -z "$PLYMOUTH_LOGO_FILE" ] && PLYMOUTH_LOGO_FILE="@PLYMOUTH_LOGO_FILE@"
adeacd
 [ -n "$PLYMOUTH_THEME_NAME" ] && THEME_OVERRIDE=1
adeacd
 [ -z "$PLYMOUTH_THEME_NAME" ] && PLYMOUTH_THEME_NAME=$(plymouth-set-default-theme)
adeacd
 [ -z "$PLYMOUTH_CONFDIR" ] && PLYMOUTH_CONFDIR="@PLYMOUTH_CONF_DIR@"
adeacd
 [ -z "$PLYMOUTH_POLICYDIR" ] && PLYMOUTH_POLICYDIR="@PLYMOUTH_POLICY_DIR@"
adeacd
 [ -z "$PLYMOUTH_DAEMON_PATH" ] && PLYMOUTH_DAEMON_PATH="@PLYMOUTH_DAEMON_DIR@/plymouthd"
adeacd
 [ -z "$PLYMOUTH_CLIENT_PATH" ] && PLYMOUTH_CLIENT_PATH="@PLYMOUTH_CLIENT_DIR@/plymouth"
adeacd
+[ -z "$PLYMOUTH_DRM_ESCROW_PATH" ] && PLYMOUTH_DRM_ESCROW_PATH="@PLYMOUTH_LIBEXECDIR@/plymouth/plymouth-drm-escrow"
adeacd
 [ -z "$SYSTEMD_UNIT_DIR" ] && SYSTEMD_UNIT_DIR="@SYSTEMD_UNIT_DIR@"
adeacd
 [ -z "$SUPPORTED_LANGUAGES" ] && SUPPORTED_LANGUAGES="pt fr de it ru es en zh ja ko zh as bn gu hi kn ml mr or pa ta te"
adeacd
 
adeacd
 # Generic substring function.  If $2 is in $1, return 0.
adeacd
 strstr() { [ "${1#*$2*}" != "$1" ]; }
adeacd
 
adeacd
 ddebug() {
adeacd
     [ "$verbose" = "true" ] && echo "$@"
adeacd
 }
adeacd
 
adeacd
 # normalize_path <path>
adeacd
 # Prints the normalized path, where it removes any duplicated
adeacd
 # and trailing slashes.
adeacd
 # Example:
adeacd
 # $ normalize_path ///test/test//
adeacd
 # /test/test
adeacd
 normalize_path() {
adeacd
     shopt -q -s extglob
adeacd
     set -- "${1//+(\/)//}"
adeacd
     shopt -q -u extglob
adeacd
     echo "${1%/}"
adeacd
 }
adeacd
 
adeacd
 # convert_abs_rel <from> <to>
adeacd
 # Prints the relative path, when creating a symlink to <to> from <from>.
adeacd
 # Example:
adeacd
 # $ convert_abs_rel /usr/bin/test /bin/test-2
adeacd
 # ../../bin/test-2
adeacd
 # $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test
adeacd
 convert_abs_rel() {
adeacd
@@ -390,60 +391,61 @@ verbose=false
adeacd
 INITRDDIR=""
adeacd
 while [ $# -gt 0 ]; do
adeacd
     case $1 in
adeacd
         --verbose|-v)
adeacd
             verbose=true
adeacd
             ;;
adeacd
         --targetdir|-t)
adeacd
             shift
adeacd
             INITRDDIR="$1"
adeacd
             ;;
adeacd
         --help|-h)
adeacd
             usage normal
adeacd
             ;;
adeacd
         *)
adeacd
             usage error
adeacd
             break
adeacd
             ;;
adeacd
     esac
adeacd
     shift
adeacd
 done
adeacd
 
adeacd
 [ -z "$INITRDDIR" ] && usage error
adeacd
 
adeacd
 ddebug "Running with PLYMOUTH_SYSROOT=$PLYMOUTH_SYSROOT"
adeacd
 ddebug "Running with PLYMOUTH_LDD=$PLYMOUTH_LDD"
adeacd
 ddebug "Running with PLYMOUTH_LDD_PATH=$PLYMOUTH_LDD_PATH"
adeacd
 
adeacd
 mkdir -p ${INITRDDIR}${PLYMOUTH_DATADIR}/plymouth/themes
adeacd
 inst ${PLYMOUTH_DAEMON_PATH} $INITRDDIR
adeacd
 inst ${PLYMOUTH_CLIENT_PATH} $INITRDDIR
adeacd
+inst ${PLYMOUTH_DRM_ESCROW_PATH} $INITRDDIR
adeacd
 inst ${PLYMOUTH_DATADIR}/plymouth/themes/text/text.plymouth $INITRDDIR
adeacd
 inst ${PLYMOUTH_PLUGIN_PATH}/text.so $INITRDDIR
adeacd
 inst ${PLYMOUTH_DATADIR}/plymouth/themes/details/details.plymouth $INITRDDIR
adeacd
 inst ${PLYMOUTH_PLUGIN_PATH}/details.so $INITRDDIR
adeacd
 inst ${PLYMOUTH_LOGO_FILE} $INITRDDIR
adeacd
 inst @RELEASE_FILE@ $INITRDDIR
adeacd
 inst ${PLYMOUTH_POLICYDIR}/plymouthd.defaults $INITRDDIR
adeacd
 inst ${PLYMOUTH_CONFDIR}/plymouthd.conf $INITRDDIR
adeacd
 
adeacd
 if [ -z "$PLYMOUTH_THEME_NAME" ]; then
adeacd
     echo "No default plymouth plugin is set" >&2
adeacd
     exit 1
adeacd
 fi
adeacd
 
adeacd
 if [ $THEME_OVERRIDE ]; then
adeacd
     conf=$INITRDDIR/${PLYMOUTH_CONFDIR}/plymouthd.conf
adeacd
     echo "modifying plymouthd.conf: Theme=$PLYMOUTH_THEME_NAME" >&2
adeacd
     # make sure the section and key exist so we can modify them
adeacd
     grep -q "^ *\[Daemon\]" $conf || echo "[Daemon]" >> $conf
adeacd
     grep -q "^ *Theme *=" $conf || echo "Theme=fade-in" >> $conf
adeacd
     sed -i "s/^ *Theme *=.*/# theme modified by plymouth-populate-initrd\nTheme=$PLYMOUTH_THEME_NAME/" $conf
adeacd
 fi
adeacd
 
adeacd
 PLYMOUTH_MODULE_NAME=$(grep "ModuleName *= *" ${PLYMOUTH_SYSROOT}${PLYMOUTH_DATADIR}/plymouth/themes/${PLYMOUTH_THEME_NAME}/${PLYMOUTH_THEME_NAME}.plymouth | sed 's/ModuleName *= *//')
adeacd
 PLYMOUTH_THEME_DIR="${PLYMOUTH_DATADIR}/plymouth/themes/${PLYMOUTH_THEME_NAME}"
adeacd
 PLYMOUTH_IMAGE_DIR=$(grep "ImageDir *= *" ${PLYMOUTH_SYSROOT}${PLYMOUTH_THEME_DIR}/${PLYMOUTH_THEME_NAME}.plymouth | sed 's/ImageDir *= *//')
adeacd
 
adeacd
 if [ ! -f ${PLYMOUTH_SYSROOT}${PLYMOUTH_PLUGIN_PATH}/${PLYMOUTH_MODULE_NAME}.so ]; then
adeacd
     echo "The default plymouth plugin (${PLYMOUTH_MODULE_NAME}) doesn't exist" >&2
adeacd
     exit 1
647dcb
diff --git a/src/Makefile.am b/src/Makefile.am
647dcb
index 95ed019..78f3f78 100644
647dcb
--- a/src/Makefile.am
647dcb
+++ b/src/Makefile.am
647dcb
@@ -1,52 +1,59 @@
647dcb
 SUBDIRS = libply libply-splash-core libply-splash-graphics . plugins client
647dcb
 if ENABLE_UPSTART_MONITORING
647dcb
 SUBDIRS += upstart-bridge
647dcb
 endif
647dcb
 AM_CPPFLAGS = -I$(top_srcdir)                                                 \
647dcb
            -I$(srcdir)/libply                                                 \
647dcb
            -I$(srcdir)/libply-splash-core                                     \
647dcb
            -I$(srcdir)                                                        \
647dcb
+           -DPLYMOUTH_DRM_ESCROW_DIRECTORY=\"$(libexecdir)/plymouth\"         \
647dcb
            -DPLYMOUTH_LOG_DIRECTORY=\"$(localstatedir)/log\"                  \
647dcb
            -DPLYMOUTH_SPOOL_DIRECTORY=\"$(localstatedir)/spool/plymouth\"     \
647dcb
            -DPLYMOUTH_TIME_DIRECTORY=\"$(localstatedir)/lib/plymouth/\"       \
647dcb
            -DPLYMOUTH_LOGO_FILE=\"$(logofile)\"
647dcb
 
647dcb
 plymouthdbindir = $(plymouthdaemondir)
647dcb
 plymouthdbin_PROGRAMS = plymouthd
647dcb
 
647dcb
 plymouthd_CFLAGS = $(PLYMOUTH_CFLAGS)                                         \
647dcb
 		   -rdynamic                                                  \
647dcb
 		   -DPLYMOUTH_PLUGIN_PATH=\"$(PLYMOUTH_PLUGIN_PATH)\"         \
647dcb
 		   -DPLYMOUTH_THEME_PATH=\"$(PLYMOUTH_THEME_PATH)/\"          \
647dcb
 		   -DPLYMOUTH_POLICY_DIR=\"$(PLYMOUTH_POLICY_DIR)/\"          \
647dcb
 		   -DPLYMOUTH_RUNTIME_DIR=\"$(PLYMOUTH_RUNTIME_DIR)\"         \
647dcb
 		   -DPLYMOUTH_CONF_DIR=\"$(PLYMOUTH_CONF_DIR)/\"              \
647dcb
 		   -DPLYMOUTH_RUNTIME_THEME_PATH=\"$(PLYMOUTH_RUNTIME_THEME_PATH)/\"
647dcb
 plymouthd_LDADD = $(PLYMOUTH_LIBS) libply/libply.la libply-splash-core/libply-splash-core.la
647dcb
 plymouthd_SOURCES =                                                            \
647dcb
                    ply-boot-protocol.h                                        \
647dcb
                    ply-boot-server.h                                          \
647dcb
                    ply-boot-server.c                                          \
647dcb
                    plugins/splash/details/plugin.c                  \
647dcb
                    main.c
647dcb
 
647dcb
+escrowdir = $(libexecdir)/plymouth
647dcb
+escrow_PROGRAMS = plymouthd-drm-escrow
647dcb
+
647dcb
+plymouthd_drm_escrow_LDFLAGS = -all-static
647dcb
+plymouthd_drm_escrow_SOURCES = plymouthd-drm-escrow.c
647dcb
+
647dcb
 plymouthdrundir = $(localstatedir)/run/plymouth
647dcb
 plymouthdspooldir = $(localstatedir)/spool/plymouth
647dcb
 plymouthdtimedir = $(localstatedir)/lib/plymouth
647dcb
 
647dcb
 pkgconfigdir = $(libdir)/pkgconfig
647dcb
 pkgconfig_DATA = ply-splash-core.pc ply-splash-graphics.pc
647dcb
 
647dcb
 plymouthd_defaultsdir = $(PLYMOUTH_POLICY_DIR)
647dcb
 dist_plymouthd_defaults_DATA = plymouthd.defaults
647dcb
 
647dcb
 plymouthd_confdir = $(PLYMOUTH_CONF_DIR)
647dcb
 dist_plymouthd_conf_DATA = plymouthd.conf
647dcb
 
647dcb
 install-data-hook:
647dcb
 	-mkdir -p $(DESTDIR)$(plymouthdrundir)
647dcb
 	-mkdir -p $(DESTDIR)$(plymouthdspooldir)
647dcb
 	-mkdir -p $(DESTDIR)$(plymouthdtimedir)
647dcb
 
647dcb
 EXTRA_DIST = ply-splash-core.pc.in ply-splash-graphics.pc.in
647dcb
 MAINTAINERCLEANFILES = Makefile.in
647dcb
diff --git a/src/main.c b/src/main.c
647dcb
index 8848ad0..8372f2f 100644
647dcb
--- a/src/main.c
647dcb
+++ b/src/main.c
647dcb
@@ -2181,65 +2181,70 @@ main (int    argc,
647dcb
 
647dcb
                 if (daemon_handle == NULL) {
647dcb
                         ply_error ("plymouthd: cannot daemonize: %m");
647dcb
                         return EX_UNAVAILABLE;
647dcb
                 }
647dcb
         }
647dcb
 
647dcb
         if (debug)
647dcb
                 debug_buffer = ply_buffer_new ();
647dcb
 
647dcb
         signal (SIGABRT, on_crash);
647dcb
         signal (SIGSEGV, on_crash);
647dcb
 
647dcb
         /* before do anything we need to make sure we have a working
647dcb
          * environment.
647dcb
          */
647dcb
         if (!initialize_environment (&state)) {
647dcb
                 if (errno == 0) {
647dcb
                         if (daemon_handle != NULL)
647dcb
                                 ply_detach_daemon (daemon_handle, 0);
647dcb
                         return 0;
647dcb
                 }
647dcb
 
647dcb
                 ply_error ("plymouthd: could not setup basic operating environment: %m");
647dcb
                 if (daemon_handle != NULL)
647dcb
                         ply_detach_daemon (daemon_handle, EX_OSERR);
647dcb
                 return EX_OSERR;
647dcb
         }
647dcb
 
647dcb
         /* Make the first byte in argv be '@' so that we can survive systemd's killing
647dcb
-         * spree when going from initrd to /, and so we stay alive all the way until
647dcb
-         * the power is killed at shutdown.
647dcb
+         * spree when going from initrd to /
647dcb
          * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons
647dcb
+         *
647dcb
+         * If the system is shutting down, we let systemd slay us because otherwise we
647dcb
+         * may prevent the root fs from getting remounted read-only.
647dcb
          */
647dcb
-        argv[0][0] = '@';
647dcb
+        if (state.mode != PLY_BOOT_SPLASH_MODE_SHUTDOWN &&
647dcb
+	    state.mode != PLY_BOOT_SPLASH_MODE_REBOOT) {
647dcb
+                argv[0][0] = '@';
647dcb
+        }
647dcb
 
647dcb
         state.boot_server = start_boot_server (&state);
647dcb
 
647dcb
         if (state.boot_server == NULL) {
647dcb
                 ply_trace ("plymouthd is already running");
647dcb
 
647dcb
                 if (daemon_handle != NULL)
647dcb
                         ply_detach_daemon (daemon_handle, EX_OK);
647dcb
                 return EX_OK;
647dcb
         }
647dcb
 
647dcb
         state.boot_buffer = ply_buffer_new ();
647dcb
 
647dcb
         if (attach_to_session) {
647dcb
                 state.should_be_attached = attach_to_session;
647dcb
                 if (!attach_to_running_session (&state)) {
647dcb
                         ply_trace ("could not redirect console session: %m");
647dcb
                         if (!no_daemon)
647dcb
                                 ply_detach_daemon (daemon_handle, EX_UNAVAILABLE);
647dcb
                         return EX_UNAVAILABLE;
647dcb
                 }
647dcb
         }
647dcb
 
647dcb
         state.progress = ply_progress_new ();
647dcb
         state.splash_delay = NAN;
647dcb
         state.device_timeout = NAN;
647dcb
 
647dcb
         ply_progress_load_cache (state.progress,
647dcb
                                  get_cache_file_for_mode (state.mode));
647dcb
 
647dcb
diff --git a/src/plugins/renderers/drm/Makefile.am b/src/plugins/renderers/drm/Makefile.am
647dcb
index 271b17f..22a819b 100644
647dcb
--- a/src/plugins/renderers/drm/Makefile.am
647dcb
+++ b/src/plugins/renderers/drm/Makefile.am
647dcb
@@ -1,23 +1,24 @@
647dcb
 if ENABLE_DRM_RENDERER
647dcb
 AM_CPPFLAGS = -I$(top_srcdir)                                                 \
647dcb
            -I$(srcdir)/../../../libply                                        \
647dcb
            -I$(srcdir)/../../../libply-splash-core                            \
647dcb
            -I$(srcdir)/../../..                                               \
647dcb
            -I$(srcdir)/../..                                                  \
647dcb
            -I$(srcdir)/..                                                     \
647dcb
-           -I$(srcdir)
647dcb
+           -I$(srcdir)                                                        \
647dcb
+           -DPLYMOUTH_DRM_ESCROW_DIRECTORY=\"$(libexecdir)/plymouth\"
647dcb
 
647dcb
 plugindir = $(libdir)/plymouth/renderers
647dcb
 plugin_LTLIBRARIES = drm.la
647dcb
 
647dcb
 drm_la_CFLAGS = $(PLYMOUTH_CFLAGS) $(DRM_CFLAGS)
647dcb
 
647dcb
 drm_la_LDFLAGS = -module -avoid-version -export-dynamic
647dcb
 drm_la_LIBADD = $(PLYMOUTH_LIBS) $(DRM_LIBS)                                  \
647dcb
                          ../../../libply/libply.la                            \
647dcb
                          ../../../libply-splash-core/libply-splash-core.la
647dcb
 drm_la_SOURCES = $(srcdir)/plugin.c
647dcb
 
647dcb
 endif
647dcb
 
647dcb
 MAINTAINERCLEANFILES = Makefile.in
647dcb
diff --git a/src/plugins/renderers/drm/plugin.c b/src/plugins/renderers/drm/plugin.c
647dcb
index 4dbf8da..38bae36 100644
647dcb
--- a/src/plugins/renderers/drm/plugin.c
647dcb
+++ b/src/plugins/renderers/drm/plugin.c
647dcb
@@ -131,73 +131,79 @@ typedef struct
647dcb
         bool connected;
647dcb
         bool uses_hw_rotation;
647dcb
 } ply_output_t;
647dcb
 
647dcb
 struct _ply_renderer_backend
647dcb
 {
647dcb
         ply_event_loop_t                *loop;
647dcb
         ply_terminal_t                  *terminal;
647dcb
 
647dcb
         int                              device_fd;
647dcb
         char                            *device_name;
647dcb
         drmModeRes                      *resources;
647dcb
 
647dcb
         ply_renderer_input_source_t      input_source;
647dcb
         ply_list_t                      *heads;
647dcb
         ply_hashtable_t                 *heads_by_controller_id;
647dcb
 
647dcb
         ply_hashtable_t                 *output_buffers;
647dcb
 
647dcb
         ply_output_t                    *outputs;
647dcb
         int                              outputs_len;
647dcb
         int                              connected_count;
647dcb
 
647dcb
         int32_t                          dither_red;
647dcb
         int32_t                          dither_green;
647dcb
         int32_t                          dither_blue;
647dcb
 
647dcb
         uint32_t                         is_active : 1;
647dcb
         uint32_t        requires_explicit_flushing : 1;
647dcb
         uint32_t                use_preferred_mode : 1;
647dcb
+        uint32_t          watching_for_termination : 1;
647dcb
 
647dcb
         int                              panel_width;
647dcb
         int                              panel_height;
647dcb
         ply_pixel_buffer_rotation_t      panel_rotation;
647dcb
         int                              panel_scale;
647dcb
 };
647dcb
 
647dcb
 ply_renderer_plugin_interface_t *ply_renderer_backend_get_interface (void);
647dcb
 static bool open_input_source (ply_renderer_backend_t      *backend,
647dcb
                                ply_renderer_input_source_t *input_source);
647dcb
 static void flush_head (ply_renderer_backend_t *backend,
647dcb
                         ply_renderer_head_t    *head);
647dcb
 
647dcb
+static void close_device (ply_renderer_backend_t *backend);
647dcb
+
647dcb
+static void watch_for_termination (ply_renderer_backend_t *backend);
647dcb
+static void stop_watching_for_termination (ply_renderer_backend_t *backend);
647dcb
+
647dcb
 /* A small helper to determine if we should try to keep the current mode
647dcb
  * or pick the best mode ourselves, we keep the current mode only if the
647dcb
  * user specified a specific mode using video= on the commandline.
647dcb
  */
647dcb
 static bool
647dcb
 should_use_preferred_mode (void)
647dcb
 {
647dcb
         bool use_preferred_mode = true;
647dcb
 
647dcb
         if (ply_kernel_command_line_get_string_after_prefix ("video="))
647dcb
                 use_preferred_mode = false;
647dcb
 
647dcb
         ply_trace ("should_use_preferred_mode: %d", use_preferred_mode);
647dcb
 
647dcb
         return use_preferred_mode;
647dcb
 }
647dcb
 
647dcb
 static bool
647dcb
 ply_renderer_buffer_map (ply_renderer_backend_t *backend,
647dcb
                          ply_renderer_buffer_t  *buffer)
647dcb
 {
647dcb
         struct drm_mode_map_dumb map_dumb_buffer_request;
647dcb
         void *map_address;
647dcb
 
647dcb
         if (buffer->map_address != MAP_FAILED) {
647dcb
                 buffer->map_count++;
647dcb
                 return true;
647dcb
         }
647dcb
 
647dcb
         memset (&map_dumb_buffer_request, 0, sizeof(struct drm_mode_map_dumb));
647dcb
@@ -918,158 +924,214 @@ static void
647dcb
 destroy_backend (ply_renderer_backend_t *backend)
647dcb
 {
647dcb
         ply_trace ("destroying renderer backend for device %s", backend->device_name);
647dcb
         free_heads (backend);
647dcb
 
647dcb
         free (backend->device_name);
647dcb
         ply_hashtable_free (backend->output_buffers);
647dcb
         ply_hashtable_free (backend->heads_by_controller_id);
647dcb
 
647dcb
         free (backend->outputs);
647dcb
         free (backend);
647dcb
 }
647dcb
 
647dcb
 static void
647dcb
 activate (ply_renderer_backend_t *backend)
647dcb
 {
647dcb
         ply_renderer_head_t *head;
647dcb
         ply_list_node_t *node;
647dcb
 
647dcb
         ply_trace ("taking master and scanning out");
647dcb
         backend->is_active = true;
647dcb
 
647dcb
         drmSetMaster (backend->device_fd);
647dcb
         node = ply_list_get_first_node (backend->heads);
647dcb
         while (node != NULL) {
647dcb
                 head = (ply_renderer_head_t *) ply_list_node_get_data (node);
647dcb
                 /* Flush out any pending drawing to the buffer */
647dcb
                 flush_head (backend, head);
647dcb
                 node = ply_list_get_next_node (backend->heads, node);
647dcb
         }
647dcb
+
647dcb
+        watch_for_termination (backend);
647dcb
 }
647dcb
 
647dcb
 static void
647dcb
 deactivate (ply_renderer_backend_t *backend)
647dcb
 {
647dcb
         ply_trace ("dropping master");
647dcb
         drmDropMaster (backend->device_fd);
647dcb
         backend->is_active = false;
647dcb
+
647dcb
+        stop_watching_for_termination (backend);
647dcb
 }
647dcb
 
647dcb
 static void
647dcb
 on_active_vt_changed (ply_renderer_backend_t *backend)
647dcb
 {
647dcb
         if (ply_terminal_is_active (backend->terminal)) {
647dcb
                 ply_trace ("activating on vt change");
647dcb
                 activate (backend);
647dcb
         } else {
647dcb
                 ply_trace ("deactivating on vt change");
647dcb
                 deactivate (backend);
647dcb
         }
647dcb
 }
647dcb
 
647dcb
 static bool
647dcb
 load_driver (ply_renderer_backend_t *backend)
647dcb
 {
647dcb
         int device_fd;
647dcb
 
647dcb
         ply_trace ("Opening '%s'", backend->device_name);
647dcb
         device_fd = open (backend->device_name, O_RDWR);
647dcb
 
647dcb
         if (device_fd < 0) {
647dcb
                 ply_trace ("open failed: %m");
647dcb
                 return false;
647dcb
         }
647dcb
 
647dcb
         backend->device_fd = device_fd;
647dcb
 
647dcb
         drmDropMaster (device_fd);
647dcb
 
647dcb
         return true;
647dcb
 }
647dcb
 
647dcb
 static void
647dcb
 unload_backend (ply_renderer_backend_t *backend)
647dcb
 {
647dcb
         if (backend == NULL)
647dcb
                 return;
647dcb
 
647dcb
         ply_trace ("unloading backend");
647dcb
 
647dcb
         if (backend->device_fd >= 0) {
647dcb
                 drmClose (backend->device_fd);
647dcb
                 backend->device_fd = -1;
647dcb
         }
647dcb
 
647dcb
         destroy_backend (backend);
647dcb
         backend = NULL;
647dcb
 
647dcb
 }
647dcb
 
647dcb
+static void
647dcb
+on_term_signal (ply_renderer_backend_t *backend)
647dcb
+{
647dcb
+        pid_t pid;
647dcb
+
647dcb
+        ply_trace ("got SIGTERM, launching drm escrow to protect splash, and dying");
647dcb
+
647dcb
+        pid = fork();
647dcb
+
647dcb
+        if (pid == 0) {
647dcb
+                const char *argv[] = { PLYMOUTH_DRM_ESCROW_DIRECTORY "/plymouthd-drm-escrow", NULL };
647dcb
+
647dcb
+                dup (backend->device_fd);
647dcb
+                execve (argv[0], (char * const *) argv, NULL);
647dcb
+
647dcb
+		ply_trace ("could not launch drm escrow process: %m");
647dcb
+
647dcb
+                _exit (1);
647dcb
+        }
647dcb
+
647dcb
+
647dcb
+	close_device (backend);
647dcb
+
647dcb
+        exit (0);
647dcb
+}
647dcb
+
647dcb
+static void
647dcb
+watch_for_termination (ply_renderer_backend_t *backend)
647dcb
+{
647dcb
+        if (backend->watching_for_termination)
647dcb
+                return;
647dcb
+
647dcb
+	ply_trace ("watching for termination signal");
647dcb
+        ply_event_loop_watch_signal (backend->loop, SIGTERM, (ply_event_handler_t) on_term_signal, backend);
647dcb
+        backend->watching_for_termination = true;
647dcb
+}
647dcb
+
647dcb
+static void
647dcb
+stop_watching_for_termination (ply_renderer_backend_t *backend)
647dcb
+{
647dcb
+        if (!backend->watching_for_termination)
647dcb
+                return;
647dcb
+
647dcb
+	ply_trace ("stopping watching for termination signal");
647dcb
+        ply_event_loop_stop_watching_signal (backend->loop, SIGTERM);
647dcb
+        backend->watching_for_termination = false;
647dcb
+}
647dcb
+
647dcb
 static bool
647dcb
 open_device (ply_renderer_backend_t *backend)
647dcb
 {
647dcb
         assert (backend != NULL);
647dcb
         assert (backend->device_name != NULL);
647dcb
 
647dcb
         if (!load_driver (backend))
647dcb
                 return false;
647dcb
 
647dcb
         if (backend->terminal == NULL)
647dcb
                 return true;
647dcb
 
647dcb
         if (!ply_terminal_open (backend->terminal)) {
647dcb
                 ply_trace ("could not open terminal: %m");
647dcb
                 return false;
647dcb
         }
647dcb
 
647dcb
         if (!ply_terminal_is_vt (backend->terminal)) {
647dcb
                 ply_trace ("terminal is not a VT");
647dcb
                 ply_terminal_close (backend->terminal);
647dcb
                 return false;
647dcb
         }
647dcb
 
647dcb
         ply_terminal_watch_for_active_vt_change (backend->terminal,
647dcb
                                                  (ply_terminal_active_vt_changed_handler_t)
647dcb
                                                  on_active_vt_changed,
647dcb
                                                  backend);
647dcb
 
647dcb
+        watch_for_termination (backend);
647dcb
+
647dcb
         return true;
647dcb
 }
647dcb
 
647dcb
 static void
647dcb
 close_device (ply_renderer_backend_t *backend)
647dcb
 {
647dcb
         ply_trace ("closing device");
647dcb
 
647dcb
         free_heads (backend);
647dcb
 
647dcb
+        stop_watching_for_termination (backend);
647dcb
+
647dcb
         if (backend->terminal != NULL) {
647dcb
                 ply_terminal_stop_watching_for_active_vt_change (backend->terminal,
647dcb
                                                                  (ply_terminal_active_vt_changed_handler_t)
647dcb
                                                                  on_active_vt_changed,
647dcb
                                                                  backend);
647dcb
         }
647dcb
 
647dcb
         unload_backend (backend);
647dcb
 }
647dcb
 
647dcb
 static void
647dcb
 output_get_controller_info (ply_renderer_backend_t *backend,
647dcb
                             drmModeConnector       *connector,
647dcb
                             ply_output_t           *output)
647dcb
 {
647dcb
         int i;
647dcb
         drmModeEncoder *encoder;
647dcb
 
647dcb
         assert (backend != NULL);
647dcb
 
647dcb
         output->possible_controllers = 0xffffffff;
647dcb
 
647dcb
         for (i = 0; i < connector->count_encoders; i++) {
647dcb
                 encoder = drmModeGetEncoder (backend->device_fd,
647dcb
                                              connector->encoders[i]);
647dcb
 
647dcb
                 if (encoder == NULL)
647dcb
                         continue;
647dcb
 
647dcb
                 if (encoder->encoder_id == connector->encoder_id && encoder->crtc_id) {
647dcb
diff --git a/src/plymouthd-drm-escrow.c b/src/plymouthd-drm-escrow.c
647dcb
new file mode 100644
647dcb
index 0000000..9097db9
647dcb
--- /dev/null
647dcb
+++ b/src/plymouthd-drm-escrow.c
647dcb
@@ -0,0 +1,18 @@
647dcb
+#include <signal.h>
647dcb
+#include <unistd.h>
647dcb
+
647dcb
+int
647dcb
+main(int argc, char **argv)
647dcb
+{
647dcb
+	signal (SIGTERM, SIG_IGN);
647dcb
+
647dcb
+        /* Make the first byte in argv be '@' so that we can survive systemd's killing
647dcb
+         * spree until the power is killed at shutdown.
647dcb
+         * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons
647dcb
+         */
647dcb
+        argv[0][0] = '@';
647dcb
+
647dcb
+        while (pause());
647dcb
+
647dcb
+        return 0;
647dcb
+}
adeacd
diff --git a/systemd-units/Makefile.am b/systemd-units/Makefile.am
adeacd
index b1d843b..bfede17 100644
adeacd
--- a/systemd-units/Makefile.am
adeacd
+++ b/systemd-units/Makefile.am
adeacd
@@ -1,78 +1,88 @@
adeacd
 systemd_unit_templates =                                                     \
adeacd
         plymouth-switch-root.service.in                                      \
adeacd
+        plymouth-switch-root-initramfs.service.in                            \
adeacd
         plymouth-start.service.in                                            \
adeacd
         plymouth-read-write.service.in                                       \
adeacd
         plymouth-quit.service.in                                             \
adeacd
         plymouth-quit-wait.service.in                                        \
adeacd
         plymouth-reboot.service.in                                           \
adeacd
         plymouth-kexec.service.in                                            \
adeacd
         plymouth-poweroff.service.in                                         \
adeacd
         plymouth-halt.service.in                                             \
adeacd
         systemd-ask-password-plymouth.path.in                                \
adeacd
         systemd-ask-password-plymouth.service.in
adeacd
 
adeacd
 if ENABLE_SYSTEMD_INTEGRATION
adeacd
 systemdunitdir=$(SYSTEMD_UNIT_DIR)
adeacd
 systemdunit_DATA = $(systemd_unit_templates:.in=)
adeacd
 
adeacd
 install-data-hook:
adeacd
 	$(MKDIR_P) -m 0755                                                   \
adeacd
 		$(DESTDIR)$(SYSTEMD_UNIT_DIR)/initrd-switch-root.target.wants\
adeacd
 		$(DESTDIR)$(SYSTEMD_UNIT_DIR)/sysinit.target.wants           \
adeacd
 		$(DESTDIR)$(SYSTEMD_UNIT_DIR)/multi-user.target.wants        \
adeacd
 		$(DESTDIR)$(SYSTEMD_UNIT_DIR)/reboot.target.wants            \
adeacd
 		$(DESTDIR)$(SYSTEMD_UNIT_DIR)/kexec.target.wants             \
adeacd
 		$(DESTDIR)$(SYSTEMD_UNIT_DIR)/poweroff.target.wants          \
adeacd
 		$(DESTDIR)$(SYSTEMD_UNIT_DIR)/halt.target.wants
adeacd
 	(cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/initrd-switch-root.target.wants && \
adeacd
 		rm -f plymouth-start.service plymouth-switch-root.service && \
adeacd
 		$(LN_S) ../plymouth-start.service &&                         \
adeacd
 		$(LN_S) ../plymouth-switch-root.service)
adeacd
 	(cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/sysinit.target.wants &&            \
adeacd
 		rm -f plymouth-start.service plymouth-read-write.service &&  \
adeacd
 		$(LN_S) ../plymouth-start.service &&                         \
adeacd
 		$(LN_S) ../plymouth-read-write.service)
adeacd
 	(cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/multi-user.target.wants &&         \
adeacd
 		rm -f plymouth-quit.service plymouth-quit-wait.service &&    \
adeacd
 		$(LN_S) ../plymouth-quit.service &&                          \
adeacd
 		$(LN_S) ../plymouth-quit-wait.service)
adeacd
 	(cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/reboot.target.wants &&             \
adeacd
-		rm -f plymouth-reboot.service &&                             \
adeacd
-		$(LN_S) ../plymouth-reboot.service)
adeacd
+		rm -f plymouth-reboot.service                                \
adeacd
+		      plymouth-switch-root-initramfs.service &&              \
adeacd
+		$(LN_S) ../plymouth-reboot.service &&                        \
adeacd
+		$(LN_S) ../plymouth-switch-root-initramfs.service)
adeacd
 	(cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/kexec.target.wants &&              \
adeacd
 		rm -f plymouth-kexec.service &&                              \
adeacd
 		$(LN_S) ../plymouth-kexec.service)
adeacd
 	(cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/poweroff.target.wants &&           \
adeacd
-		rm -f plymouth-poweroff.service &&                           \
adeacd
-		$(LN_S) ../plymouth-poweroff.service)
adeacd
+		rm -f plymouth-poweroff.service                              \
adeacd
+		      plymouth-switch-root-initramfs.service &&              \
adeacd
+		$(LN_S) ../plymouth-poweroff.service &&                      \
adeacd
+		$(LN_S) ../plymouth-switch-root-initramf.services)
adeacd
 	(cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/halt.target.wants &&               \
adeacd
-		rm -f plymouth-halt.service &&                               \
adeacd
-		$(LN_S) ../plymouth-halt.service)
adeacd
+		rm -f plymouth-halt.service                                  \
adeacd
+		      plymouth-switch-root-initramfs.service &&              \
adeacd
+		$(LN_S) ../plymouth-halt.service &&                          \
adeacd
+		$(LN_S) ../plymouth-switch-root-initramfs.service)
adeacd
 
adeacd
 uninstall-hook:
adeacd
 	(cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/initrd-switch-root.target.wants && \
adeacd
 		rm -f plymouth-start.service plymouth-switch-root.service)
adeacd
 	(cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/sysinit.target.wants &&            \
adeacd
 		rm -f plymouth-start.service plymouth-read-write.service)
adeacd
 	(cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/multi-user.target.wants &&         \
adeacd
 		rm -f plymouth-quit.service plymouth-quit-wait.service)
adeacd
 	(cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/reboot.target.wants &&             \
adeacd
-		rm -f plymouth-reboot.service)
adeacd
+		rm -f plymouth-reboot.service                                \
adeacd
+		      plymouth-switch-root-initramfs.service)
adeacd
 	(cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/kexec.target.wants &&              \
adeacd
 		rm -f plymouth-kexec.service)
adeacd
 	(cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/poweroff.target.wants &&           \
adeacd
-		rm -f plymouth-poweroff.service)
adeacd
+		rm -f plymouth-poweroff.service                              \
adeacd
+		      plymouth-switch-root-initramfs.service)
adeacd
 	(cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/halt.target.wants &&               \
adeacd
-		rm -f plymouth-halt.service)
adeacd
+		rm -f plymouth-halt.service                                  \
adeacd
+		      plymouth-switch-root-initramfs.service)
adeacd
 	rmdir --ignore-fail-on-non-empty                                     \
adeacd
 		$(DESTDIR)$(SYSTEMD_UNIT_DIR)/sysinit.target.wants           \
adeacd
 		$(DESTDIR)$(SYSTEMD_UNIT_DIR)/multi-user.target.wants        \
adeacd
 		$(DESTDIR)$(SYSTEMD_UNIT_DIR)/reboot.target.wants            \
adeacd
 		$(DESTDIR)$(SYSTEMD_UNIT_DIR)/kexec.target.wants             \
adeacd
 		$(DESTDIR)$(SYSTEMD_UNIT_DIR)/poweroff.target.wants          \
adeacd
 		$(DESTDIR)$(SYSTEMD_UNIT_DIR)/halt.target.wants
adeacd
 
adeacd
 endif
adeacd
 
adeacd
 EXTRA_DIST = $(systemd_unit_templates) $(systemdunit_DATA)
adeacd
 DISTCLEANFILES=$(systemdunit_DATA)
647dcb
diff --git a/systemd-units/plymouth-halt.service.in b/systemd-units/plymouth-halt.service.in
647dcb
index cb87c1f..00f7eed 100644
647dcb
--- a/systemd-units/plymouth-halt.service.in
647dcb
+++ b/systemd-units/plymouth-halt.service.in
647dcb
@@ -1,13 +1,14 @@
647dcb
 [Unit]
647dcb
 Description=Show Plymouth Halt Screen
647dcb
 After=getty@tty1.service display-manager.service plymouth-start.service
647dcb
 Before=systemd-halt.service
647dcb
 DefaultDependencies=no
647dcb
 ConditionKernelCommandLine=!plymouth.enable=0
647dcb
 ConditionVirtualization=!container
647dcb
 
647dcb
 [Service]
647dcb
 ExecStart=@PLYMOUTH_DAEMON_DIR@/plymouthd --mode=shutdown --attach-to-session
647dcb
 ExecStartPost=-@PLYMOUTH_CLIENT_DIR@/plymouth show-splash
647dcb
+KillMode=none
647dcb
 Type=forking
647dcb
 RemainAfterExit=yes
647dcb
diff --git a/systemd-units/plymouth-poweroff.service.in b/systemd-units/plymouth-poweroff.service.in
647dcb
index cf05e47..a1f78eb 100644
647dcb
--- a/systemd-units/plymouth-poweroff.service.in
647dcb
+++ b/systemd-units/plymouth-poweroff.service.in
647dcb
@@ -1,13 +1,14 @@
647dcb
 [Unit]
647dcb
 Description=Show Plymouth Power Off Screen
647dcb
 After=getty@tty1.service display-manager.service plymouth-start.service
647dcb
 Before=systemd-poweroff.service
647dcb
 DefaultDependencies=no
647dcb
 ConditionKernelCommandLine=!plymouth.enable=0
647dcb
 ConditionVirtualization=!container
647dcb
 
647dcb
 [Service]
647dcb
 ExecStart=@PLYMOUTH_DAEMON_DIR@/plymouthd --mode=shutdown --attach-to-session
647dcb
 ExecStartPost=-@PLYMOUTH_CLIENT_DIR@/plymouth show-splash
647dcb
+KillMode=none
647dcb
 Type=forking
647dcb
 RemainAfterExit=yes
647dcb
diff --git a/systemd-units/plymouth-reboot.service.in b/systemd-units/plymouth-reboot.service.in
647dcb
index 3624550..8fff576 100644
647dcb
--- a/systemd-units/plymouth-reboot.service.in
647dcb
+++ b/systemd-units/plymouth-reboot.service.in
647dcb
@@ -1,13 +1,14 @@
647dcb
 [Unit]
647dcb
 Description=Show Plymouth Reboot Screen
647dcb
 After=getty@tty1.service display-manager.service plymouth-start.service
647dcb
 Before=systemd-reboot.service
647dcb
 DefaultDependencies=no
647dcb
 ConditionKernelCommandLine=!plymouth.enable=0
647dcb
 ConditionVirtualization=!container
647dcb
 
647dcb
 [Service]
647dcb
 ExecStart=@PLYMOUTH_DAEMON_DIR@/plymouthd --mode=reboot --attach-to-session
647dcb
 ExecStartPost=-@PLYMOUTH_CLIENT_DIR@/plymouth show-splash
647dcb
+KillMode=none
647dcb
 Type=forking
647dcb
 RemainAfterExit=yes
adeacd
diff --git a/systemd-units/plymouth-switch-root-initramfs.service.in b/systemd-units/plymouth-switch-root-initramfs.service.in
adeacd
new file mode 100644
adeacd
index 0000000..cb20459
adeacd
--- /dev/null
adeacd
+++ b/systemd-units/plymouth-switch-root-initramfs.service.in
adeacd
@@ -0,0 +1,12 @@
adeacd
+[Unit]
adeacd
+Description=Tell Plymouth To Jump To initramfs
adeacd
+DefaultDependencies=no
adeacd
+After=plymouth-halt.service plymouth-reboot.service plymouth-poweroff.service dracut-shutdown.service
adeacd
+ConditionPathExists=/run/initramfs/bin/sh
adeacd
+
adeacd
+[Service]
adeacd
+Type=oneshot
adeacd
+RemainAfterExit=yes
adeacd
+ExecStart=-@PLYMOUTH_CLIENT_DIR@/plymouth update-root-fs --new-root-dir=/run/initramfs
adeacd
+Type=oneshot
adeacd
+RemainAfterExit=yes
647dcb
-- 
647dcb
2.26.0
647dcb