diff --git a/configure.ac b/configure.ac index 1a2314bb..d2d62287 100644 --- a/configure.ac +++ b/configure.ac @@ -341,6 +341,7 @@ AC_CONFIG_FILES([Makefile po/Makefile.in systemd-units/plymouth-reboot.service systemd-units/plymouth-start.service systemd-units/plymouth-switch-root.service + systemd-units/plymouth-switch-root-initramfs.service systemd-units/systemd-ask-password-plymouth.path systemd-units/systemd-ask-password-plymouth.service systemd-units/Makefile diff --git a/scripts/plymouth-populate-initrd.in b/scripts/plymouth-populate-initrd.in index 616ecc4e..4e35186b 100755 --- a/scripts/plymouth-populate-initrd.in +++ b/scripts/plymouth-populate-initrd.in @@ -22,6 +22,7 @@ [ -z "$PLYMOUTH_POLICYDIR" ] && PLYMOUTH_POLICYDIR="@PLYMOUTH_POLICY_DIR@" [ -z "$PLYMOUTH_DAEMON_PATH" ] && PLYMOUTH_DAEMON_PATH="@PLYMOUTH_DAEMON_DIR@/plymouthd" [ -z "$PLYMOUTH_CLIENT_PATH" ] && PLYMOUTH_CLIENT_PATH="@PLYMOUTH_CLIENT_DIR@/plymouth" +[ -z "$PLYMOUTH_DRM_ESCROW_PATH" ] && PLYMOUTH_DRM_ESCROW_PATH="@PLYMOUTH_LIBEXECDIR@/plymouth/plymouth-drm-escrow" [ -z "$SYSTEMD_UNIT_DIR" ] && SYSTEMD_UNIT_DIR="@SYSTEMD_UNIT_DIR@" # Generic substring function. If $2 is in $1, return 0. @@ -416,6 +417,7 @@ ddebug "Running with PLYMOUTH_LDD_PATH=$PLYMOUTH_LDD_PATH" mkdir -p ${INITRDDIR}${PLYMOUTH_DATADIR}/plymouth/themes inst ${PLYMOUTH_DAEMON_PATH} $INITRDDIR inst ${PLYMOUTH_CLIENT_PATH} $INITRDDIR +inst ${PLYMOUTH_DRM_ESCROW_PATH} $INITRDDIR inst ${PLYMOUTH_DATADIR}/plymouth/themes/text/text.plymouth $INITRDDIR inst ${PLYMOUTH_PLUGIN_PATH}/text.so $INITRDDIR inst ${PLYMOUTH_DATADIR}/plymouth/themes/details/details.plymouth $INITRDDIR diff --git a/src/Makefile.am b/src/Makefile.am index 95ed0192..78f3f788 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,6 +6,7 @@ AM_CPPFLAGS = -I$(top_srcdir) \ -I$(srcdir)/libply \ -I$(srcdir)/libply-splash-core \ -I$(srcdir) \ + -DPLYMOUTH_DRM_ESCROW_DIRECTORY=\"$(libexecdir)/plymouth\" \ -DPLYMOUTH_LOG_DIRECTORY=\"$(localstatedir)/log\" \ -DPLYMOUTH_SPOOL_DIRECTORY=\"$(localstatedir)/spool/plymouth\" \ -DPLYMOUTH_TIME_DIRECTORY=\"$(localstatedir)/lib/plymouth/\" \ @@ -30,6 +31,12 @@ plymouthd_SOURCES = \ plugins/splash/details/plugin.c \ main.c +escrowdir = $(libexecdir)/plymouth +escrow_PROGRAMS = plymouthd-drm-escrow + +plymouthd_drm_escrow_LDFLAGS = -all-static +plymouthd_drm_escrow_SOURCES = plymouthd-drm-escrow.c + plymouthdrundir = $(localstatedir)/run/plymouth plymouthdspooldir = $(localstatedir)/spool/plymouth plymouthdtimedir = $(localstatedir)/lib/plymouth diff --git a/src/main.c b/src/main.c index 8848ad0d..8372f2f8 100644 --- a/src/main.c +++ b/src/main.c @@ -2208,11 +2208,16 @@ main (int argc, } /* Make the first byte in argv be '@' so that we can survive systemd's killing - * spree when going from initrd to /, and so we stay alive all the way until - * the power is killed at shutdown. + * spree when going from initrd to / * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons + * + * If the system is shutting down, we let systemd slay us because otherwise we + * may prevent the root fs from getting remounted read-only. */ - argv[0][0] = '@'; + if (state.mode != PLY_BOOT_SPLASH_MODE_SHUTDOWN && + state.mode != PLY_BOOT_SPLASH_MODE_REBOOT) { + argv[0][0] = '@'; + } state.boot_server = start_boot_server (&state); diff --git a/src/plugins/renderers/drm/Makefile.am b/src/plugins/renderers/drm/Makefile.am index 271b17f4..22a819b6 100644 --- a/src/plugins/renderers/drm/Makefile.am +++ b/src/plugins/renderers/drm/Makefile.am @@ -5,7 +5,8 @@ AM_CPPFLAGS = -I$(top_srcdir) \ -I$(srcdir)/../../.. \ -I$(srcdir)/../.. \ -I$(srcdir)/.. \ - -I$(srcdir) + -I$(srcdir) \ + -DPLYMOUTH_DRM_ESCROW_DIRECTORY=\"$(libexecdir)/plymouth\" plugindir = $(libdir)/plymouth/renderers plugin_LTLIBRARIES = drm.la diff --git a/src/plugins/renderers/drm/plugin.c b/src/plugins/renderers/drm/plugin.c index 4dbf8da8..38bae367 100644 --- a/src/plugins/renderers/drm/plugin.c +++ b/src/plugins/renderers/drm/plugin.c @@ -158,6 +158,7 @@ struct _ply_renderer_backend uint32_t is_active : 1; uint32_t requires_explicit_flushing : 1; uint32_t use_preferred_mode : 1; + uint32_t watching_for_termination : 1; int panel_width; int panel_height; @@ -171,6 +172,11 @@ static bool open_input_source (ply_renderer_backend_t *backend, static void flush_head (ply_renderer_backend_t *backend, ply_renderer_head_t *head); +static void close_device (ply_renderer_backend_t *backend); + +static void watch_for_termination (ply_renderer_backend_t *backend); +static void stop_watching_for_termination (ply_renderer_backend_t *backend); + /* A small helper to determine if we should try to keep the current mode * or pick the best mode ourselves, we keep the current mode only if the * user specified a specific mode using video= on the commandline. @@ -945,6 +951,8 @@ activate (ply_renderer_backend_t *backend) flush_head (backend, head); node = ply_list_get_next_node (backend->heads, node); } + + watch_for_termination (backend); } static void @@ -953,6 +961,8 @@ deactivate (ply_renderer_backend_t *backend) ply_trace ("dropping master"); drmDropMaster (backend->device_fd); backend->is_active = false; + + stop_watching_for_termination (backend); } static void @@ -1005,6 +1015,54 @@ unload_backend (ply_renderer_backend_t *backend) } +static void +on_term_signal (ply_renderer_backend_t *backend) +{ + pid_t pid; + + ply_trace ("got SIGTERM, launching drm escrow to protect splash, and dying"); + + pid = fork(); + + if (pid == 0) { + const char *argv[] = { PLYMOUTH_DRM_ESCROW_DIRECTORY "/plymouthd-drm-escrow", NULL }; + + dup (backend->device_fd); + execve (argv[0], (char * const *) argv, NULL); + + ply_trace ("could not launch drm escrow process: %m"); + + _exit (1); + } + + + close_device (backend); + + exit (0); +} + +static void +watch_for_termination (ply_renderer_backend_t *backend) +{ + if (backend->watching_for_termination) + return; + + ply_trace ("watching for termination signal"); + ply_event_loop_watch_signal (backend->loop, SIGTERM, (ply_event_handler_t) on_term_signal, backend); + backend->watching_for_termination = true; +} + +static void +stop_watching_for_termination (ply_renderer_backend_t *backend) +{ + if (!backend->watching_for_termination) + return; + + ply_trace ("stopping watching for termination signal"); + ply_event_loop_stop_watching_signal (backend->loop, SIGTERM); + backend->watching_for_termination = false; +} + static bool open_device (ply_renderer_backend_t *backend) { @@ -1033,6 +1091,8 @@ open_device (ply_renderer_backend_t *backend) on_active_vt_changed, backend); + watch_for_termination (backend); + return true; } @@ -1043,6 +1103,8 @@ close_device (ply_renderer_backend_t *backend) free_heads (backend); + stop_watching_for_termination (backend); + if (backend->terminal != NULL) { ply_terminal_stop_watching_for_active_vt_change (backend->terminal, (ply_terminal_active_vt_changed_handler_t) diff --git a/src/plymouthd-drm-escrow.c b/src/plymouthd-drm-escrow.c new file mode 100644 index 00000000..9097db91 --- /dev/null +++ b/src/plymouthd-drm-escrow.c @@ -0,0 +1,18 @@ +#include +#include + +int +main(int argc, char **argv) +{ + signal (SIGTERM, SIG_IGN); + + /* Make the first byte in argv be '@' so that we can survive systemd's killing + * spree until the power is killed at shutdown. + * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons + */ + argv[0][0] = '@'; + + while (pause()); + + return 0; +} diff --git a/systemd-units/Makefile.am b/systemd-units/Makefile.am index b1d843b6..bfede172 100644 --- a/systemd-units/Makefile.am +++ b/systemd-units/Makefile.am @@ -1,5 +1,6 @@ systemd_unit_templates = \ plymouth-switch-root.service.in \ + plymouth-switch-root-initramfs.service.in \ plymouth-start.service.in \ plymouth-read-write.service.in \ plymouth-quit.service.in \ @@ -37,17 +38,23 @@ install-data-hook: $(LN_S) ../plymouth-quit.service && \ $(LN_S) ../plymouth-quit-wait.service) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/reboot.target.wants && \ - rm -f plymouth-reboot.service && \ - $(LN_S) ../plymouth-reboot.service) + rm -f plymouth-reboot.service \ + plymouth-switch-root-initramfs.service && \ + $(LN_S) ../plymouth-reboot.service && \ + $(LN_S) ../plymouth-switch-root-initramfs.service) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/kexec.target.wants && \ rm -f plymouth-kexec.service && \ $(LN_S) ../plymouth-kexec.service) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/poweroff.target.wants && \ - rm -f plymouth-poweroff.service && \ - $(LN_S) ../plymouth-poweroff.service) + rm -f plymouth-poweroff.service \ + plymouth-switch-root-initramfs.service && \ + $(LN_S) ../plymouth-poweroff.service && \ + $(LN_S) ../plymouth-switch-root-initramf.services) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/halt.target.wants && \ - rm -f plymouth-halt.service && \ - $(LN_S) ../plymouth-halt.service) + rm -f plymouth-halt.service \ + plymouth-switch-root-initramfs.service && \ + $(LN_S) ../plymouth-halt.service && \ + $(LN_S) ../plymouth-switch-root-initramfs.service) uninstall-hook: (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/initrd-switch-root.target.wants && \ @@ -57,13 +64,16 @@ uninstall-hook: (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/multi-user.target.wants && \ rm -f plymouth-quit.service plymouth-quit-wait.service) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/reboot.target.wants && \ - rm -f plymouth-reboot.service) + rm -f plymouth-reboot.service \ + plymouth-switch-root-initramfs.service) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/kexec.target.wants && \ rm -f plymouth-kexec.service) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/poweroff.target.wants && \ - rm -f plymouth-poweroff.service) + rm -f plymouth-poweroff.service \ + plymouth-switch-root-initramfs.service) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/halt.target.wants && \ - rm -f plymouth-halt.service) + rm -f plymouth-halt.service \ + plymouth-switch-root-initramfs.service) rmdir --ignore-fail-on-non-empty \ $(DESTDIR)$(SYSTEMD_UNIT_DIR)/sysinit.target.wants \ $(DESTDIR)$(SYSTEMD_UNIT_DIR)/multi-user.target.wants \ diff --git a/systemd-units/plymouth-halt.service.in b/systemd-units/plymouth-halt.service.in index cb87c1f4..00f7eed9 100644 --- a/systemd-units/plymouth-halt.service.in +++ b/systemd-units/plymouth-halt.service.in @@ -9,5 +9,6 @@ ConditionVirtualization=!container [Service] ExecStart=@PLYMOUTH_DAEMON_DIR@/plymouthd --mode=shutdown --attach-to-session ExecStartPost=-@PLYMOUTH_CLIENT_DIR@/plymouth show-splash +KillMode=none Type=forking RemainAfterExit=yes diff --git a/systemd-units/plymouth-poweroff.service.in b/systemd-units/plymouth-poweroff.service.in index cf05e47f..a1f78eb4 100644 --- a/systemd-units/plymouth-poweroff.service.in +++ b/systemd-units/plymouth-poweroff.service.in @@ -9,5 +9,6 @@ ConditionVirtualization=!container [Service] ExecStart=@PLYMOUTH_DAEMON_DIR@/plymouthd --mode=shutdown --attach-to-session ExecStartPost=-@PLYMOUTH_CLIENT_DIR@/plymouth show-splash +KillMode=none Type=forking RemainAfterExit=yes diff --git a/systemd-units/plymouth-reboot.service.in b/systemd-units/plymouth-reboot.service.in index 3624550d..8fff576f 100644 --- a/systemd-units/plymouth-reboot.service.in +++ b/systemd-units/plymouth-reboot.service.in @@ -9,5 +9,6 @@ ConditionVirtualization=!container [Service] ExecStart=@PLYMOUTH_DAEMON_DIR@/plymouthd --mode=reboot --attach-to-session ExecStartPost=-@PLYMOUTH_CLIENT_DIR@/plymouth show-splash +KillMode=none Type=forking RemainAfterExit=yes diff --git a/systemd-units/plymouth-switch-root-initramfs.service.in b/systemd-units/plymouth-switch-root-initramfs.service.in new file mode 100644 index 00000000..cb20459d --- /dev/null +++ b/systemd-units/plymouth-switch-root-initramfs.service.in @@ -0,0 +1,12 @@ +[Unit] +Description=Tell Plymouth To Jump To initramfs +DefaultDependencies=no +After=plymouth-halt.service plymouth-reboot.service plymouth-poweroff.service dracut-shutdown.service +ConditionPathExists=/run/initramfs/bin/sh + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=-@PLYMOUTH_CLIENT_DIR@/plymouth update-root-fs --new-root-dir=/run/initramfs +Type=oneshot +RemainAfterExit=yes