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

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