44a72b9
From 7d9e4212490f7c42d419de4befb438e173380da7 Mon Sep 17 00:00:00 2001
44a72b9
From: Alan Jenkins <alan.christopher.jenkins@gmail.com>
44a72b9
Date: Mon, 21 Aug 2017 17:28:35 +0100
44a72b9
Subject: [PATCH] logind: respect "delay" inhibitors in scheduled shutdowns
44a72b9
44a72b9
There is no justification not to wait an extra (default) 5 seconds, for
44a72b9
a more graceful shutdown of user programs.  Again, you don't get to ignore
44a72b9
delay inhibitors for unscheduled shutdowns, short of
44a72b9
`systemctl poweroff -f`.
44a72b9
44a72b9
It is simplest if we move the test for `m->shutdown_dry_run` into
44a72b9
manager_scheduled_shutdown_handler().
44a72b9
44a72b9
However we need to not add such delays during a "dry run".  Otherwise, we
44a72b9
would still have to be considered "in progress" for some seconds after our
44a72b9
admin has seen the final wall message.  If they go to `poweroff`, we would
44a72b9
have blocked them with a misleading error message.  Note this `poweroff`
44a72b9
will still process delay inhibitors as needed.  If the admin planned to
44a72b9
use a more forceful method... eh.  It's their responsibility to assess
44a72b9
whether that's safe.
44a72b9
44a72b9
There is an argument that the alternative behaviour could be used (racily!)
44a72b9
to kludge around them not being able to shutdown to "single user mode".  If
44a72b9
we cared about that case, we would have easily preserved non-racy support
44a72b9
for it in `shutdown`.
44a72b9
44a72b9
Additionally, though I think this code does read more easily by reducing
44a72b9
inconsistencies, we didn't come up with any use case for delay inhibitors
44a72b9
v.s. shutdown.[1]  The SIGTERM v.s. SIGKILL delay is more general, and we
44a72b9
allow a whole 90 seconds for it, not just 5.  So I don't think keeping this
44a72b9
approach bears a risk of significant damage.
44a72b9
44a72b9
[1] https://www.freedesktop.org/wiki/Software/systemd/inhibit/
44a72b9
44a72b9
(cherry picked from commit df75a1a8aa5420335a56093077fa8cfcbfffac78)
44a72b9
---
44a72b9
 src/login/logind-dbus.c | 91 ++++++++++++++++++++++++++-----------------------
44a72b9
 1 file changed, 48 insertions(+), 43 deletions(-)
44a72b9
44a72b9
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
44a72b9
index 3f05c86f5c..1fd64d32b7 100644
44a72b9
--- a/src/login/logind-dbus.c
44a72b9
+++ b/src/login/logind-dbus.c
44a72b9
@@ -1399,7 +1399,6 @@ static int have_multiple_sessions(
44a72b9
 
44a72b9
 static int bus_manager_log_shutdown(
44a72b9
                 Manager *m,
44a72b9
-                InhibitWhat w,
44a72b9
                 const char *unit_name) {
44a72b9
 
44a72b9
         const char *p, *q;
44a72b9
@@ -1407,9 +1406,6 @@ static int bus_manager_log_shutdown(
44a72b9
         assert(m);
44a72b9
         assert(unit_name);
44a72b9
 
44a72b9
-        if (w != INHIBIT_SHUTDOWN)
44a72b9
-                return 0;
44a72b9
-
44a72b9
         if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
44a72b9
                 p = "MESSAGE=System is powering down";
44a72b9
                 q = "SHUTDOWN=power-off";
44a72b9
@@ -1484,21 +1480,6 @@ int manager_set_lid_switch_ignore(Manager *m, usec_t until) {
44a72b9
         return r;
44a72b9
 }
44a72b9
 
44a72b9
-static void reset_scheduled_shutdown(Manager *m) {
44a72b9
-        m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
44a72b9
-        m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source);
44a72b9
-        m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
44a72b9
-        m->scheduled_shutdown_type = mfree(m->scheduled_shutdown_type);
44a72b9
-        m->scheduled_shutdown_timeout = 0;
44a72b9
-        m->shutdown_dry_run = false;
44a72b9
-
44a72b9
-        if (m->unlink_nologin) {
44a72b9
-                (void) unlink("/run/nologin");
44a72b9
-                m->unlink_nologin = false;
44a72b9
-        }
44a72b9
-        (void) unlink("/run/systemd/shutdown/scheduled");
44a72b9
-}
44a72b9
-
44a72b9
 static int execute_shutdown_or_sleep(
44a72b9
                 Manager *m,
44a72b9
                 InhibitWhat w,
44a72b9
@@ -1515,32 +1496,28 @@ static int execute_shutdown_or_sleep(
44a72b9
         assert(w < _INHIBIT_WHAT_MAX);
44a72b9
         assert(unit_name);
44a72b9
 
44a72b9
-        bus_manager_log_shutdown(m, w, unit_name);
44a72b9
+        if (w == INHIBIT_SHUTDOWN)
44a72b9
+                bus_manager_log_shutdown(m, unit_name);
44a72b9
 
44a72b9
-        if (m->shutdown_dry_run) {
44a72b9
-                log_info("Running in dry run, suppressing action.");
44a72b9
-                reset_scheduled_shutdown(m);
44a72b9
-        } else {
44a72b9
-                r = sd_bus_call_method(
44a72b9
-                                m->bus,
44a72b9
-                                "org.freedesktop.systemd1",
44a72b9
-                                "/org/freedesktop/systemd1",
44a72b9
-                                "org.freedesktop.systemd1.Manager",
44a72b9
-                                "StartUnit",
44a72b9
-                                error,
44a72b9
-                                &reply,
44a72b9
-                                "ss", unit_name, "replace-irreversibly");
44a72b9
-                if (r < 0)
44a72b9
-                        return r;
44a72b9
+        r = sd_bus_call_method(
44a72b9
+                        m->bus,
44a72b9
+                        "org.freedesktop.systemd1",
44a72b9
+                        "/org/freedesktop/systemd1",
44a72b9
+                        "org.freedesktop.systemd1.Manager",
44a72b9
+                        "StartUnit",
44a72b9
+                        error,
44a72b9
+                        &reply,
44a72b9
+                        "ss", unit_name, "replace-irreversibly");
44a72b9
+        if (r < 0)
44a72b9
+                return r;
44a72b9
 
44a72b9
-                r = sd_bus_message_read(reply, "o", &p);
44a72b9
-                if (r < 0)
44a72b9
-                        return r;
44a72b9
+        r = sd_bus_message_read(reply, "o", &p);
44a72b9
+        if (r < 0)
44a72b9
+                return r;
44a72b9
 
44a72b9
-                c = strdup(p);
44a72b9
-                if (!c)
44a72b9
-                        return -ENOMEM;
44a72b9
-        }
44a72b9
+        c = strdup(p);
44a72b9
+        if (!c)
44a72b9
+                return -ENOMEM;
44a72b9
 
44a72b9
         m->action_unit = unit_name;
44a72b9
         free(m->action_job);
44a72b9
@@ -1924,6 +1901,21 @@ fail:
44a72b9
         return log_error_errno(r, "Failed to write information about scheduled shutdowns: %m");
44a72b9
 }
44a72b9
 
44a72b9
+static void reset_scheduled_shutdown(Manager *m) {
44a72b9
+        m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
44a72b9
+        m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source);
44a72b9
+        m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
44a72b9
+        m->scheduled_shutdown_type = mfree(m->scheduled_shutdown_type);
44a72b9
+        m->scheduled_shutdown_timeout = 0;
44a72b9
+        m->shutdown_dry_run = false;
44a72b9
+
44a72b9
+        if (m->unlink_nologin) {
44a72b9
+                (void) unlink("/run/nologin");
44a72b9
+                m->unlink_nologin = false;
44a72b9
+        }
44a72b9
+        (void) unlink("/run/systemd/shutdown/scheduled");
44a72b9
+}
44a72b9
+
44a72b9
 static int manager_scheduled_shutdown_handler(
44a72b9
                         sd_event_source *s,
44a72b9
                         uint64_t usec,
44a72b9
@@ -1952,7 +1944,20 @@ static int manager_scheduled_shutdown_handler(
44a72b9
                 return -EALREADY;
44a72b9
         }
44a72b9
 
44a72b9
-        r = execute_shutdown_or_sleep(m, INHIBIT_SHUTDOWN, target, &error);
44a72b9
+        if (m->shutdown_dry_run) {
44a72b9
+                /* We do not process delay inhibitors here.  Otherwise, we
44a72b9
+                 * would have to be considered "in progress" (like the check
44a72b9
+                 * above) for some seconds after our admin has seen the final
44a72b9
+                 * wall message. */
44a72b9
+
44a72b9
+                bus_manager_log_shutdown(m, target);
44a72b9
+                log_info("Running in dry run, suppressing action.");
44a72b9
+                reset_scheduled_shutdown(m);
44a72b9
+
44a72b9
+                return 0;
44a72b9
+        }
44a72b9
+
44a72b9
+        r = bus_manager_shutdown_or_sleep_now_or_later(m, target, INHIBIT_SHUTDOWN, &error);
44a72b9
         if (r < 0)
44a72b9
                 return log_error_errno(r, "Scheduled shutdown to %s failed: %m", target);
44a72b9