]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
logind: refactor
authorLudwig Nussel <ludwig.nussel@suse.de>
Wed, 15 Dec 2021 17:21:09 +0000 (18:21 +0100)
committerLudwig Nussel <ludwig.nussel@suse.de>
Tue, 25 Jan 2022 16:43:10 +0000 (17:43 +0100)
Avoid hardcoded strings and string compares related to shutdown actions.
Instead put everything into a common structure. Reuse existing
HandleAction as index since it's already exposed as property for the
button handlers.

src/login/logind-action.c
src/login/logind-action.h
src/login/logind-button.c
src/login/logind-dbus.c
src/login/logind-dbus.h
src/login/logind-utmp.c
src/login/logind.c
src/login/logind.h

index e1729109482b031d9f0a896ac4b369d8b325b59d..45f77bc090949cd7ee6b7810d7374753a0a0bc08 100644 (file)
@@ -2,6 +2,8 @@
 
 #include <unistd.h>
 
+#include "sd-messages.h"
+
 #include "alloc-util.h"
 #include "bus-error.h"
 #include "bus-util.h"
 #include "logind-dbus.h"
 #include "logind-session-dbus.h"
 #include "process-util.h"
-#include "sleep-config.h"
 #include "special.h"
 #include "string-table.h"
 #include "terminal-util.h"
 #include "user-util.h"
 
+static const ActionTableItem action_table[_HANDLE_ACTION_MAX] = {
+        [HANDLE_POWEROFF] = {
+                SPECIAL_POWEROFF_TARGET,
+                INHIBIT_SHUTDOWN,
+                "org.freedesktop.login1.power-off",
+                "org.freedesktop.login1.power-off-multiple-sessions",
+                "org.freedesktop.login1.power-off-ignore-inhibit",
+                _SLEEP_OPERATION_INVALID,
+                SD_MESSAGE_SHUTDOWN_STR,
+                "System is powering down",
+                "power-off",
+                },
+        [HANDLE_REBOOT] = {
+                SPECIAL_REBOOT_TARGET,
+                INHIBIT_SHUTDOWN,
+                "org.freedesktop.login1.reboot",
+                "org.freedesktop.login1.reboot-multiple-sessions",
+                "org.freedesktop.login1.reboot-ignore-inhibit",
+                _SLEEP_OPERATION_INVALID,
+                SD_MESSAGE_SHUTDOWN_STR,
+                "System is rebooting",
+                "reboot",
+                },
+        [HANDLE_HALT]  = {
+                SPECIAL_HALT_TARGET,
+                INHIBIT_SHUTDOWN,
+                "org.freedesktop.login1.halt",
+                "org.freedesktop.login1.halt-multiple-sessions",
+                "org.freedesktop.login1.halt-ignore-inhibit",
+                _SLEEP_OPERATION_INVALID,
+                SD_MESSAGE_SHUTDOWN_STR,
+                "System is halting",
+                "halt",
+                },
+        [HANDLE_KEXEC]  = {
+                SPECIAL_KEXEC_TARGET,
+                INHIBIT_SHUTDOWN,
+                "org.freedesktop.login1.reboot",
+                "org.freedesktop.login1.reboot-multiple-sessions",
+                "org.freedesktop.login1.reboot-ignore-inhibit",
+                _SLEEP_OPERATION_INVALID,
+                SD_MESSAGE_SHUTDOWN_STR,
+                "System is rebooting with kexec",
+                "kexec",
+                },
+        [HANDLE_SUSPEND]  = {
+                SPECIAL_SUSPEND_TARGET,
+                INHIBIT_SLEEP,
+                "org.freedesktop.login1.suspend",
+                "org.freedesktop.login1.suspend-multiple-sessions",
+                "org.freedesktop.login1.suspend-ignore-inhibit",
+                SLEEP_SUSPEND,
+                },
+        [HANDLE_HIBERNATE]  = {
+                SPECIAL_HIBERNATE_TARGET,
+                INHIBIT_SLEEP,
+                "org.freedesktop.login1.hibernate",
+                "org.freedesktop.login1.hibernate-multiple-sessions",
+                "org.freedesktop.login1.hibernate-ignore-inhibit",
+                SLEEP_HIBERNATE,
+                },
+        [HANDLE_HYBRID_SLEEP]  = {
+                SPECIAL_HYBRID_SLEEP_TARGET,
+                INHIBIT_SLEEP,
+                "org.freedesktop.login1.hibernate",
+                "org.freedesktop.login1.hibernate-multiple-sessions",
+                "org.freedesktop.login1.hibernate-ignore-inhibit",
+                SLEEP_HYBRID_SLEEP,
+                },
+        [HANDLE_SUSPEND_THEN_HIBERNATE]  = {
+                SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET,
+                INHIBIT_SLEEP,
+                "org.freedesktop.login1.hibernate",
+                "org.freedesktop.login1.hibernate-multiple-sessions",
+                "org.freedesktop.login1.hibernate-ignore-inhibit",
+                SLEEP_SUSPEND_THEN_HIBERNATE,
+                },
+        [HANDLE_FACTORY_RESET]  = {
+                SPECIAL_FACTORY_RESET_TARGET,
+                _INHIBIT_WHAT_INVALID,
+                NULL,
+                NULL,
+                NULL,
+                _SLEEP_OPERATION_INVALID,
+                SD_MESSAGE_FACTORY_RESET_STR,
+                "System is performing factory reset",
+                NULL
+                },
+};
+
 const char* manager_target_for_action(HandleAction handle) {
-        static const char * const target_table[_HANDLE_ACTION_MAX] = {
-                [HANDLE_POWEROFF] = SPECIAL_POWEROFF_TARGET,
-                [HANDLE_REBOOT] = SPECIAL_REBOOT_TARGET,
-                [HANDLE_HALT] = SPECIAL_HALT_TARGET,
-                [HANDLE_KEXEC] = SPECIAL_KEXEC_TARGET,
-                [HANDLE_SUSPEND] = SPECIAL_SUSPEND_TARGET,
-                [HANDLE_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
-                [HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET,
-                [HANDLE_SUSPEND_THEN_HIBERNATE] = SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET,
-                [HANDLE_FACTORY_RESET] = SPECIAL_FACTORY_RESET_TARGET,
-        };
+        assert(handle >= 0);
+        assert(handle < (ssize_t) ELEMENTSOF(action_table));
 
+        return action_table[handle].target;
+}
+
+const ActionTableItem* manager_item_for_handle(HandleAction handle) {
         assert(handle >= 0);
-        if (handle < (ssize_t) ELEMENTSOF(target_table))
-                return target_table[handle];
-        return NULL;
+        assert(handle < (ssize_t) ELEMENTSOF(action_table));
+
+        return &action_table[handle];
+}
+
+HandleAction manager_handle_for_item(const ActionTableItem* a) {
+        if (a && a < action_table + ELEMENTSOF(action_table))
+                return a - action_table;
+        return _HANDLE_ACTION_INVALID;
 }
 
 int manager_handle_action(
@@ -59,7 +151,6 @@ int manager_handle_action(
         InhibitWhat inhibit_operation;
         Inhibitor *offending = NULL;
         bool supported;
-        const char *target;
         int r;
 
         assert(m);
@@ -129,17 +220,13 @@ int manager_handle_action(
                 return log_warning_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
                                          "Requested %s operation not supported, ignoring.", handle_action_to_string(handle));
 
-        if (m->action_what > 0)
+        if (m->delayed_action)
                 return log_debug_errno(SYNTHETIC_ERRNO(EALREADY),
                                        "Action already in progress (%s), ignoring requested %s operation.",
-                                       inhibit_what_to_string(m->action_what),
+                                       inhibit_what_to_string(m->delayed_action->inhibit_what),
                                        handle_action_to_string(handle));
 
-        assert_se(target = manager_target_for_action(handle));
-
-        inhibit_operation = IN_SET(handle, HANDLE_SUSPEND, HANDLE_HIBERNATE,
-                                           HANDLE_HYBRID_SLEEP,
-                                           HANDLE_SUSPEND_THEN_HIBERNATE) ? INHIBIT_SLEEP : INHIBIT_SHUTDOWN;
+        inhibit_operation = manager_item_for_handle(handle)->inhibit_what;
 
         /* If the actual operation is inhibited, warn and fail */
         if (!ignore_inhibited &&
@@ -162,7 +249,7 @@ int manager_handle_action(
 
         log_info("%s", message_table[handle]);
 
-        r = bus_manager_shutdown_or_sleep_now_or_later(m, target, inhibit_operation, &error);
+        r = bus_manager_shutdown_or_sleep_now_or_later(m, manager_item_for_handle(handle), &error);
         if (r < 0)
                 return log_error_errno(r, "Failed to execute %s operation: %s",
                                        handle_action_to_string(handle),
index ec2fece2b7b056ebbae95abff228106a199a6b4b..e6d304774331a59bdd7ce14d056d61b55d9e2c94 100644 (file)
@@ -19,8 +19,26 @@ typedef enum HandleAction {
         _HANDLE_ACTION_INVALID = -EINVAL,
 } HandleAction;
 
+typedef struct ActionTableItem ActionTableItem;
+
+#define handle_action_valid(x) (x && (x < _HANDLE_ACTION_MAX))
+
 #include "logind-inhibit.h"
 #include "logind.h"
+#include "sleep-config.h"
+
+struct ActionTableItem {
+        const char *target;
+        InhibitWhat inhibit_what;
+        const char *polkit_action;
+        const char *polkit_action_multiple_sessions;
+        const char *polkit_action_ignore_inhibit;
+        SleepOperation sleep_operation;
+        const char* message_id;
+        const char* message;
+        const char* log_str;
+
+};
 
 int manager_handle_action(
                 Manager *m,
@@ -33,5 +51,7 @@ const char* handle_action_to_string(HandleAction h) _const_;
 HandleAction handle_action_from_string(const char *s) _pure_;
 
 const char* manager_target_for_action(HandleAction handle);
+const ActionTableItem* manager_item_for_handle(HandleAction handle);
+HandleAction manager_handle_for_item(const ActionTableItem* a);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_handle_action);
index 7fb811463938a6b1b5e5e7a2556e462c3149ab13..0f4e1f1b4173721f992e5be1edad1c4b71ae43f8 100644 (file)
@@ -84,8 +84,7 @@ static void button_lid_switch_handle_action(Manager *manager, bool is_edge) {
          * differently */
         if (manager_is_docked_or_external_displays(manager))
                 handle_action = manager->handle_lid_switch_docked;
-        else if (manager->handle_lid_switch_ep != _HANDLE_ACTION_INVALID &&
-                 manager_is_on_external_power())
+        else if (!handle_action_valid(manager->handle_lid_switch_ep) && manager_is_on_external_power())
                 handle_action = manager->handle_lid_switch_ep;
         else
                 handle_action = manager->handle_lid_switch;
index 223f0da205660b4b29fea5c885a74ee4e86c2b22..cffe445919ec82bf3835f4fe23d6a92ac6c17f72 100644 (file)
@@ -29,6 +29,7 @@
 #include "fileio.h"
 #include "format-util.h"
 #include "fs-util.h"
+#include "logind-action.h"
 #include "logind-dbus.h"
 #include "logind-polkit.h"
 #include "logind-seat-dbus.h"
@@ -53,6 +54,8 @@
 #include "utmp-wtmp.h"
 #include "virt.h"
 
+static void reset_scheduled_shutdown(Manager *m);
+
 static int get_sender_session(
                 Manager *m,
                 sd_bus_message *message,
@@ -309,16 +312,18 @@ static int property_get_preparing(
                 sd_bus_error *error) {
 
         Manager *m = userdata;
-        bool b;
+        bool b = false;
 
         assert(bus);
         assert(reply);
         assert(m);
 
-        if (streq(property, "PreparingForShutdown"))
-                b = m->action_what & INHIBIT_SHUTDOWN;
-        else
-                b = m->action_what & INHIBIT_SLEEP;
+        if (m->delayed_action) {
+                if (streq(property, "PreparingForShutdown"))
+                        b = m->delayed_action->inhibit_what & INHIBIT_SHUTDOWN;
+                else
+                        b = m->delayed_action->inhibit_what & INHIBIT_SLEEP;
+        }
 
         return sd_bus_message_append(reply, "b", b);
 }
@@ -343,7 +348,9 @@ static int property_get_scheduled_shutdown(
         if (r < 0)
                 return r;
 
-        r = sd_bus_message_append(reply, "st", m->scheduled_shutdown_type, m->scheduled_shutdown_timeout);
+        r = sd_bus_message_append(reply, "st",
+                handle_action_to_string(manager_handle_for_item(m->scheduled_shutdown_type)),
+                m->scheduled_shutdown_timeout);
         if (r < 0)
                 return r;
 
@@ -1488,59 +1495,35 @@ static int have_multiple_sessions(
         return false;
 }
 
-_printf_(2, 0)
-static int log_with_wall_message(Manager *m, const char *d, const char *p, const char *q) {
+static int bus_manager_log_shutdown(
+                Manager *m,
+                const ActionTableItem *a) {
+
+        const char *message, *log_str;
+
         assert(m);
+        assert(a);
 
-        if (isempty(m->wall_message))
-                p = strjoina(p, ".");
+        message = a->message;
+        log_str = a->log_str;
+
+        if (message)
+                message = strjoina("MESSAGE=", message);
         else
-                p = strjoina(p, " (", m->wall_message, ").");
+                message = "MESSAGE=System is shutting down";
 
-        return log_struct(LOG_NOTICE, d, p, q);
-}
+        if (isempty(m->wall_message))
+                message = strjoina(message, ".");
+        else
+                message = strjoina(message, " (", m->wall_message, ").");
 
-static int bus_manager_log_shutdown(
-                Manager *m,
-                const char *unit_name) {
+        if (log_str)
+                log_str = strjoina("SHUTDOWN=", log_str);
 
-        assert(m);
-        assert(unit_name);
-
-        if (streq(unit_name, SPECIAL_POWEROFF_TARGET))
-                return log_with_wall_message(m,
-                                             "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
-                                             "MESSAGE=System is powering down",
-                                             "SHUTDOWN=power-off");
-
-        if (streq(unit_name, SPECIAL_REBOOT_TARGET))
-                return log_with_wall_message(m,
-                                             "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
-                                             "MESSAGE=System is rebooting",
-                                             "SHUTDOWN=reboot");
-
-        if (streq(unit_name, SPECIAL_HALT_TARGET))
-                return log_with_wall_message(m,
-                                             "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
-                                             "MESSAGE=System is halting",
-                                             "SHUTDOWN=halt");
-
-        if (streq(unit_name, SPECIAL_KEXEC_TARGET))
-                return log_with_wall_message(m,
-                                             "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
-                                             "MESSAGE=System is rebooting with kexec",
-                                             "SHUTDOWN=kexec");
-
-        if (streq(unit_name, SPECIAL_FACTORY_RESET_TARGET))
-                return log_with_wall_message(m,
-                                             "MESSAGE_ID=" SD_MESSAGE_FACTORY_RESET_STR,
-                                             "MESSAGE=System is performing factory reset",
-                                             NULL);
-
-        return log_with_wall_message(m,
-                                     "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
-                                     "MESSAGE=System is shutting down",
-                                     NULL);
+        return log_struct(LOG_NOTICE,
+                        "MESSAGE_ID=%s", a->message_id ? a->message_id : SD_MESSAGE_SHUTDOWN_STR,
+                        message,
+                        log_str);
 }
 
 static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) {
@@ -1604,8 +1587,7 @@ static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
 
 static int execute_shutdown_or_sleep(
                 Manager *m,
-                InhibitWhat w,
-                const char *unit_name,
+                const ActionTableItem *a,
                 sd_bus_error *error) {
 
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@@ -1613,12 +1595,10 @@ static int execute_shutdown_or_sleep(
         int r;
 
         assert(m);
-        assert(w > 0);
-        assert(w < _INHIBIT_WHAT_MAX);
-        assert(unit_name);
+        assert(a);
 
-        if (w == INHIBIT_SHUTDOWN)
-                bus_manager_log_shutdown(m, unit_name);
+        if (a->inhibit_what == INHIBIT_SHUTDOWN)
+                bus_manager_log_shutdown(m, a);
 
         r = bus_call_method(
                         m->bus,
@@ -1626,7 +1606,7 @@ static int execute_shutdown_or_sleep(
                         "StartUnit",
                         error,
                         &reply,
-                        "ss", unit_name, "replace-irreversibly");
+                        "ss", a->target, "replace-irreversibly");
         if (r < 0)
                 goto error;
 
@@ -1638,8 +1618,7 @@ static int execute_shutdown_or_sleep(
         if (r < 0)
                 goto error;
 
-        m->action_unit = unit_name;
-        m->action_what = w;
+        m->delayed_action = a;
 
         /* Make sure the lid switch is ignored for a while */
         manager_set_lid_switch_ignore(m, usec_add(now(CLOCK_MONOTONIC), m->holdoff_timeout_usec));
@@ -1648,7 +1627,7 @@ static int execute_shutdown_or_sleep(
 
 error:
         /* Tell people that they now may take a lock again */
-        (void) send_prepare_for(m, w, false);
+        (void) send_prepare_for(m, a->inhibit_what, false);
 
         return r;
 }
@@ -1660,10 +1639,10 @@ int manager_dispatch_delayed(Manager *manager, bool timeout) {
 
         assert(manager);
 
-        if (manager->action_what == 0 || manager->action_job)
+        if (!manager->delayed_action || manager->action_job)
                 return 0;
 
-        if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) {
+        if (manager_is_inhibited(manager, manager->delayed_action->inhibit_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) {
                 _cleanup_free_ char *comm = NULL, *u = NULL;
 
                 if (!timeout)
@@ -1678,13 +1657,12 @@ int manager_dispatch_delayed(Manager *manager, bool timeout) {
         }
 
         /* Actually do the operation */
-        r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
+        r = execute_shutdown_or_sleep(manager, manager->delayed_action, &error);
         if (r < 0) {
                 log_warning("Error during inhibitor-delayed operation (already returned success to client): %s",
                             bus_error_message(&error, r));
 
-                manager->action_unit = NULL;
-                manager->action_what = 0;
+                manager->delayed_action = NULL;
         }
 
         return 1; /* We did some work. */
@@ -1705,15 +1683,12 @@ static int manager_inhibit_timeout_handler(
 
 static int delay_shutdown_or_sleep(
                 Manager *m,
-                InhibitWhat w,
-                const char *unit_name) {
+                const ActionTableItem *a) {
 
         int r;
 
         assert(m);
-        assert(w >= 0);
-        assert(w < _INHIBIT_WHAT_MAX);
-        assert(unit_name);
+        assert(a);
 
         if (m->inhibit_timeout_source) {
                 r = sd_event_source_set_time_relative(m->inhibit_timeout_source, m->inhibit_delay_max);
@@ -1733,16 +1708,14 @@ static int delay_shutdown_or_sleep(
                         return r;
         }
 
-        m->action_unit = unit_name;
-        m->action_what = w;
+        m->delayed_action = a;
 
         return 0;
 }
 
 int bus_manager_shutdown_or_sleep_now_or_later(
                 Manager *m,
-                const char *unit_name,
-                InhibitWhat w,
+                const ActionTableItem *a,
                 sd_bus_error *error) {
 
         _cleanup_free_ char *load_state = NULL;
@@ -1750,35 +1723,33 @@ int bus_manager_shutdown_or_sleep_now_or_later(
         int r;
 
         assert(m);
-        assert(unit_name);
-        assert(w > 0);
-        assert(w < _INHIBIT_WHAT_MAX);
+        assert(a);
         assert(!m->action_job);
 
-        r = unit_load_state(m->bus, unit_name, &load_state);
+        r = unit_load_state(m->bus, a->target, &load_state);
         if (r < 0)
                 return r;
 
         if (!streq(load_state, "loaded"))
                 return log_notice_errno(SYNTHETIC_ERRNO(EACCES),
                                         "Unit %s is %s, refusing operation.",
-                                        unit_name, load_state);
+                                        a->target, load_state);
 
         /* Tell everybody to prepare for shutdown/sleep */
-        (void) send_prepare_for(m, w, true);
+        (void) send_prepare_for(m, a->inhibit_what, true);
 
         delayed =
                 m->inhibit_delay_max > 0 &&
-                manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0, NULL);
+                manager_is_inhibited(m, a->inhibit_what, INHIBIT_DELAY, NULL, false, false, 0, NULL);
 
         if (delayed)
                 /* Shutdown is delayed, keep in mind what we
                  * want to do, and start a timeout */
-                r = delay_shutdown_or_sleep(m, w, unit_name);
+                r = delay_shutdown_or_sleep(m, a);
         else
                 /* Shutdown is not delayed, execute it
                  * immediately */
-                r = execute_shutdown_or_sleep(m, w, unit_name, error);
+                r = execute_shutdown_or_sleep(m, a, error);
 
         return r;
 }
@@ -1786,10 +1757,7 @@ int bus_manager_shutdown_or_sleep_now_or_later(
 static int verify_shutdown_creds(
                 Manager *m,
                 sd_bus_message *message,
-                InhibitWhat w,
-                const char *action,
-                const char *action_multiple_sessions,
-                const char *action_ignore_inhibit,
+                const ActionTableItem *a,
                 uint64_t flags,
                 sd_bus_error *error) {
 
@@ -1799,12 +1767,8 @@ static int verify_shutdown_creds(
         int r;
 
         assert(m);
+        assert(a);
         assert(message);
-        assert(w >= 0);
-        assert(w <= _INHIBIT_WHAT_MAX);
-        assert(action);
-        assert(action_multiple_sessions);
-        assert(action_ignore_inhibit);
 
         r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
         if (r < 0)
@@ -1819,11 +1783,19 @@ static int verify_shutdown_creds(
                 return r;
 
         multiple_sessions = r > 0;
-        blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
+        blocked = manager_is_inhibited(m, a->inhibit_what, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
         interactive = flags & SD_LOGIND_INTERACTIVE;
 
         if (multiple_sessions) {
-                r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
+                r = bus_verify_polkit_async(
+                                message,
+                                CAP_SYS_BOOT,
+                                a->polkit_action_multiple_sessions,
+                                NULL,
+                                interactive,
+                                UID_INVALID,
+                                &m->polkit_registry,
+                                error);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -1836,7 +1808,14 @@ static int verify_shutdown_creds(
                         return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED,
                                                  "Access denied to root due to active block inhibitor");
 
-                r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
+                r = bus_verify_polkit_async(message,
+                                CAP_SYS_BOOT,
+                                a->polkit_action_ignore_inhibit,
+                                NULL,
+                                interactive,
+                                UID_INVALID,
+                                &m->polkit_registry,
+                                error);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -1844,7 +1823,14 @@ static int verify_shutdown_creds(
         }
 
         if (!multiple_sessions && !blocked) {
-                r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
+                r = bus_verify_polkit_async(message,
+                                CAP_SYS_BOOT,
+                                a->polkit_action,
+                                NULL,
+                                interactive,
+                                UID_INVALID,
+                                &m->polkit_registry,
+                                error);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -1880,12 +1866,7 @@ static int setup_wall_message_timer(Manager *m, sd_bus_message* message) {
 static int method_do_shutdown_or_sleep(
                 Manager *m,
                 sd_bus_message *message,
-                const char *unit_name,
-                InhibitWhat w,
-                const char *action,
-                const char *action_multiple_sessions,
-                const char *action_ignore_inhibit,
-                SleepOperation sleep_operation,
+                const ActionTableItem *a,
                 bool with_flags,
                 sd_bus_error *error) {
 
@@ -1894,9 +1875,7 @@ static int method_do_shutdown_or_sleep(
 
         assert(m);
         assert(message);
-        assert(unit_name);
-        assert(w >= 0);
-        assert(w <= _INHIBIT_WHAT_MAX);
+        assert(a);
 
         if (with_flags) {
                 /* New style method: with flags parameter (and interactive bool in the bus message header) */
@@ -1905,7 +1884,7 @@ static int method_do_shutdown_or_sleep(
                         return r;
                 if ((flags & ~SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC) != 0)
                         return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
-                if (!streq(unit_name, SPECIAL_REBOOT_TARGET) && (flags & SD_LOGIND_REBOOT_VIA_KEXEC))
+                if (manager_handle_for_item(a) != HANDLE_REBOOT && (flags & SD_LOGIND_REBOOT_VIA_KEXEC))
                         return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Reboot via kexec is only applicable with reboot operations");
         } else {
                 /* Old style method: no flags parameter, but interactive bool passed as boolean in
@@ -1921,33 +1900,39 @@ static int method_do_shutdown_or_sleep(
         }
 
         if ((flags & SD_LOGIND_REBOOT_VIA_KEXEC) && kexec_loaded())
-                unit_name = SPECIAL_KEXEC_TARGET;
+                a = manager_item_for_handle(HANDLE_KEXEC);
 
         /* Don't allow multiple jobs being executed at the same time */
-        if (m->action_what > 0)
+        if (m->delayed_action)
                 return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS,
                                          "There's already a shutdown or sleep operation in progress");
 
-        if (sleep_operation >= 0) {
-                r = can_sleep(sleep_operation);
+        if (a->sleep_operation >= 0) {
+                r = can_sleep(a->sleep_operation);
                 if (r == -ENOSPC)
                         return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
                                                 "Not enough swap space for hibernation");
                 if (r == 0)
                         return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
-                                                 "Sleep verb \"%s\" not supported", sleep_operation_to_string(sleep_operation));
+                                                 "Sleep verb \"%s\" not supported", sleep_operation_to_string(a->sleep_operation));
                 if (r < 0)
                         return r;
         }
 
-        r = verify_shutdown_creds(m, message, w, action, action_multiple_sessions,
-                                  action_ignore_inhibit, flags, error);
+        r = verify_shutdown_creds(m, message, a, flags, error);
         if (r != 0)
                 return r;
 
+        /* reset case we're shorting a scheduled shutdown */
+        m->unlink_nologin = false;
+        reset_scheduled_shutdown(m);
+
+        m->scheduled_shutdown_timeout = 0;
+        m->scheduled_shutdown_type = a;
+
         (void) setup_wall_message_timer(m, message);
 
-        r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
+        r = bus_manager_shutdown_or_sleep_now_or_later(m, a, error);
         if (r < 0)
                 return r;
 
@@ -1957,16 +1942,9 @@ static int method_do_shutdown_or_sleep(
 static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
 
-        (void)free_and_strdup(&m->scheduled_shutdown_type, "poweroff");
-
         return method_do_shutdown_or_sleep(
                         m, message,
-                        SPECIAL_POWEROFF_TARGET,
-                        INHIBIT_SHUTDOWN,
-                        "org.freedesktop.login1.power-off",
-                        "org.freedesktop.login1.power-off-multiple-sessions",
-                        "org.freedesktop.login1.power-off-ignore-inhibit",
-                        _SLEEP_OPERATION_INVALID,
+                        manager_item_for_handle(HANDLE_POWEROFF),
                         sd_bus_message_is_method_call(message, NULL, "PowerOffWithFlags"),
                         error);
 }
@@ -1974,16 +1952,9 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error
 static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
 
-        (void)free_and_strdup(&m->scheduled_shutdown_type, "reboot");
-
         return method_do_shutdown_or_sleep(
                         m, message,
-                        SPECIAL_REBOOT_TARGET,
-                        INHIBIT_SHUTDOWN,
-                        "org.freedesktop.login1.reboot",
-                        "org.freedesktop.login1.reboot-multiple-sessions",
-                        "org.freedesktop.login1.reboot-ignore-inhibit",
-                        _SLEEP_OPERATION_INVALID,
+                        manager_item_for_handle(HANDLE_REBOOT),
                         sd_bus_message_is_method_call(message, NULL, "RebootWithFlags"),
                         error);
 }
@@ -1991,16 +1962,9 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *
 static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
 
-        (void)free_and_strdup(&m->scheduled_shutdown_type, "halt");
-
         return method_do_shutdown_or_sleep(
                         m, message,
-                        SPECIAL_HALT_TARGET,
-                        INHIBIT_SHUTDOWN,
-                        "org.freedesktop.login1.halt",
-                        "org.freedesktop.login1.halt-multiple-sessions",
-                        "org.freedesktop.login1.halt-ignore-inhibit",
-                        _SLEEP_OPERATION_INVALID,
+                        manager_item_for_handle(HANDLE_HALT),
                         sd_bus_message_is_method_call(message, NULL, "HaltWithFlags"),
                         error);
 }
@@ -2008,16 +1972,9 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er
 static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
 
-        (void)free_and_strdup(&m->scheduled_shutdown_type, "suspend");
-
         return method_do_shutdown_or_sleep(
                         m, message,
-                        SPECIAL_SUSPEND_TARGET,
-                        INHIBIT_SLEEP,
-                        "org.freedesktop.login1.suspend",
-                        "org.freedesktop.login1.suspend-multiple-sessions",
-                        "org.freedesktop.login1.suspend-ignore-inhibit",
-                        SLEEP_SUSPEND,
+                        manager_item_for_handle(HANDLE_SUSPEND),
                         sd_bus_message_is_method_call(message, NULL, "SuspendWithFlags"),
                         error);
 }
@@ -2025,16 +1982,9 @@ static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error
 static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
 
-        (void)free_and_strdup(&m->scheduled_shutdown_type, "hibernate");
-
         return method_do_shutdown_or_sleep(
                         m, message,
-                        SPECIAL_HIBERNATE_TARGET,
-                        INHIBIT_SLEEP,
-                        "org.freedesktop.login1.hibernate",
-                        "org.freedesktop.login1.hibernate-multiple-sessions",
-                        "org.freedesktop.login1.hibernate-ignore-inhibit",
-                        SLEEP_HIBERNATE,
+                        manager_item_for_handle(HANDLE_HIBERNATE),
                         sd_bus_message_is_method_call(message, NULL, "HibernateWithFlags"),
                         error);
 }
@@ -2042,16 +1992,9 @@ static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_erro
 static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
 
-        (void)free_and_strdup(&m->scheduled_shutdown_type, "hybrid-sleep");
-
         return method_do_shutdown_or_sleep(
                         m, message,
-                        SPECIAL_HYBRID_SLEEP_TARGET,
-                        INHIBIT_SLEEP,
-                        "org.freedesktop.login1.hibernate",
-                        "org.freedesktop.login1.hibernate-multiple-sessions",
-                        "org.freedesktop.login1.hibernate-ignore-inhibit",
-                        SLEEP_HYBRID_SLEEP,
+                        manager_item_for_handle(HANDLE_HYBRID_SLEEP),
                         sd_bus_message_is_method_call(message, NULL, "HybridSleepWithFlags"),
                         error);
 }
@@ -2059,16 +2002,9 @@ static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_e
 static int method_suspend_then_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
 
-        (void)free_and_strdup(&m->scheduled_shutdown_type, "sleep");
-
         return method_do_shutdown_or_sleep(
                         m, message,
-                        SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET,
-                        INHIBIT_SLEEP,
-                        "org.freedesktop.login1.hibernate",
-                        "org.freedesktop.login1.hibernate-multiple-sessions",
-                        "org.freedesktop.login1.hibernate-ignore-inhibit",
-                        SLEEP_SUSPEND_THEN_HIBERNATE,
+                        manager_item_for_handle(HANDLE_SUSPEND_THEN_HIBERNATE),
                         sd_bus_message_is_method_call(message, NULL, "SuspendThenHibernateWithFlags"),
                         error);
 }
@@ -2116,7 +2052,7 @@ static int update_schedule_file(Manager *m) {
                 "MODE=%s\n",
                 m->scheduled_shutdown_timeout,
                 m->enable_wall_messages,
-                m->scheduled_shutdown_type);
+                handle_action_to_string(manager_handle_for_item(m->scheduled_shutdown_type)));
 
         if (!isempty(m->wall_message)) {
                 _cleanup_free_ char *t = NULL;
@@ -2155,8 +2091,7 @@ static void reset_scheduled_shutdown(Manager *m) {
         m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source);
         m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
 
-        m->scheduled_shutdown_type = mfree(m->scheduled_shutdown_type);
-        m->scheduled_shutdown_timeout = 0;
+        m->scheduled_shutdown_type = NULL;
         m->shutdown_dry_run = false;
 
         if (m->unlink_nologin) {
@@ -2172,31 +2107,20 @@ static int manager_scheduled_shutdown_handler(
                         uint64_t usec,
                         void *userdata) {
 
+        const ActionTableItem *a = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         Manager *m = userdata;
-        const char *target;
         int r;
 
         assert(m);
 
-        if (isempty(m->scheduled_shutdown_type))
-                return 0;
-
-        if (streq(m->scheduled_shutdown_type, "poweroff"))
-                target = SPECIAL_POWEROFF_TARGET;
-        else if (streq(m->scheduled_shutdown_type, "reboot"))
-                target = SPECIAL_REBOOT_TARGET;
-        else if (streq(m->scheduled_shutdown_type, "kexec"))
-                target = SPECIAL_KEXEC_TARGET;
-        else if (streq(m->scheduled_shutdown_type, "halt"))
-                target = SPECIAL_HALT_TARGET;
-        else
-                assert_not_reached();
+        a = m->scheduled_shutdown_type;
+        assert(a);
 
         /* Don't allow multiple jobs being executed at the same time */
-        if (m->action_what > 0) {
+        if (m->delayed_action) {
                 r = -EALREADY;
-                log_error("Scheduled shutdown to %s failed: shutdown or sleep operation already in progress", target);
+                log_error("Scheduled shutdown to %s failed: shutdown or sleep operation already in progress", a->target);
                 goto error;
         }
 
@@ -2206,16 +2130,16 @@ static int manager_scheduled_shutdown_handler(
                  * above) for some seconds after our admin has seen the final
                  * wall message. */
 
-                bus_manager_log_shutdown(m, target);
+                bus_manager_log_shutdown(m, a);
                 log_info("Running in dry run, suppressing action.");
                 reset_scheduled_shutdown(m);
 
                 return 0;
         }
 
-        r = bus_manager_shutdown_or_sleep_now_or_later(m, target, INHIBIT_SHUTDOWN, &error);
+        r = bus_manager_shutdown_or_sleep_now_or_later(m, m->scheduled_shutdown_type, &error);
         if (r < 0) {
-                log_error_errno(r, "Scheduled shutdown to %s failed: %m", target);
+                log_error_errno(r, "Scheduled shutdown to %s failed: %m", a->target);
                 goto error;
         }
 
@@ -2228,9 +2152,8 @@ error:
 
 static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
-        const char *action_multiple_sessions = NULL;
-        const char *action_ignore_inhibit = NULL;
-        const char *action = NULL;
+        HandleAction handle;
+        const ActionTableItem *a;
         uint64_t elapse;
         char *type;
         int r;
@@ -2248,23 +2171,15 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
                 dry_run = true;
         }
 
-        if (streq(type, "poweroff")) {
-                action = "org.freedesktop.login1.power-off";
-                action_multiple_sessions = "org.freedesktop.login1.power-off-multiple-sessions";
-                action_ignore_inhibit = "org.freedesktop.login1.power-off-ignore-inhibit";
-        } else if (STR_IN_SET(type, "reboot", "kexec")) {
-                action = "org.freedesktop.login1.reboot";
-                action_multiple_sessions = "org.freedesktop.login1.reboot-multiple-sessions";
-                action_ignore_inhibit = "org.freedesktop.login1.reboot-ignore-inhibit";
-        } else if (streq(type, "halt")) {
-                action = "org.freedesktop.login1.halt";
-                action_multiple_sessions = "org.freedesktop.login1.halt-multiple-sessions";
-                action_ignore_inhibit = "org.freedesktop.login1.halt-ignore-inhibit";
-        } else
+        handle = handle_action_from_string(type);
+        if (!IN_SET(handle, HANDLE_POWEROFF, HANDLE_REBOOT, HANDLE_HALT, HANDLE_KEXEC))
                 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type");
 
-        r = verify_shutdown_creds(m, message, INHIBIT_SHUTDOWN, action, action_multiple_sessions,
-                                  action_ignore_inhibit, 0, error);
+        a = manager_item_for_handle(handle);
+        assert(a);
+        assert(a->polkit_action);
+
+        r = verify_shutdown_creds(m, message, a, 0, error);
         if (r != 0)
                 return r;
 
@@ -2283,12 +2198,7 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
                         return log_error_errno(r, "sd_event_add_time() failed: %m");
         }
 
-        r = free_and_strdup(&m->scheduled_shutdown_type, type);
-        if (r < 0) {
-                m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
-                return log_oom();
-        }
-
+        m->scheduled_shutdown_type = a;
         m->shutdown_dry_run = dry_run;
 
         if (m->nologin_timeout_source) {
@@ -2323,32 +2233,25 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
 
 static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
-        const char *action;
+        const ActionTableItem *a;
         bool cancelled;
         int r;
 
         assert(m);
         assert(message);
 
-        cancelled = m->scheduled_shutdown_type != NULL;
-
+        cancelled = !IN_SET(manager_handle_for_item(m->scheduled_shutdown_type), HANDLE_IGNORE, _HANDLE_ACTION_INVALID);
         if (!cancelled)
                 goto done;
 
-        // mirrors code in method_schedule_shutdown()
-        if (streq(m->scheduled_shutdown_type, "poweroff")) {
-                action = "org.freedesktop.login1.power-off";
-        } else if (STR_IN_SET(m->scheduled_shutdown_type, "reboot", "kexec")) {
-                action = "org.freedesktop.login1.reboot";
-        } else if (streq(m->scheduled_shutdown_type, "halt")) {
-                action = "org.freedesktop.login1.halt";
-        } else
-                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type");
+        a = m->scheduled_shutdown_type;
+        if (!a->polkit_action)
+                return sd_bus_error_set(error, SD_BUS_ERROR_AUTH_FAILED, "Unsupported shutdown type");
 
         r = bus_verify_polkit_async(
                         message,
                         CAP_SYS_BOOT,
-                        action,
+                        a->polkit_action,
                         NULL,
                         false,
                         UID_INVALID,
@@ -2385,15 +2288,10 @@ done:
 static int method_can_shutdown_or_sleep(
                 Manager *m,
                 sd_bus_message *message,
-                InhibitWhat w,
-                const char *action,
-                const char *action_multiple_sessions,
-                const char *action_ignore_inhibit,
-                SleepOperation sleep_operation,
+                const ActionTableItem *a,
                 sd_bus_error *error) {
 
         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
-        HandleAction handle;
         bool multiple_sessions, challenge, blocked;
         const char *result = NULL;
         uid_t uid;
@@ -2401,14 +2299,10 @@ static int method_can_shutdown_or_sleep(
 
         assert(m);
         assert(message);
-        assert(w >= 0);
-        assert(w <= _INHIBIT_WHAT_MAX);
-        assert(action);
-        assert(action_multiple_sessions);
-        assert(action_ignore_inhibit);
-
-        if (sleep_operation >= 0) {
-                r = can_sleep(sleep_operation);
+        assert(a);
+
+        if (a->sleep_operation >= 0) {
+                r = can_sleep(a->sleep_operation);
                 if (IN_SET(r,  0, -ENOSPC))
                         return sd_bus_reply_method_return(message, "s", "na");
                 if (r < 0)
@@ -2428,9 +2322,9 @@ static int method_can_shutdown_or_sleep(
                 return r;
 
         multiple_sessions = r > 0;
-        blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
+        blocked = manager_is_inhibited(m, a->inhibit_what, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
 
-        handle = handle_action_from_string(sleep_operation_to_string(sleep_operation));
+        HandleAction handle = handle_action_from_string(sleep_operation_to_string(a->sleep_operation));
         if (handle >= 0) {
                 const char *target;
 
@@ -2450,7 +2344,7 @@ static int method_can_shutdown_or_sleep(
         }
 
         if (multiple_sessions) {
-                r = bus_test_polkit(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, UID_INVALID, &challenge, error);
+                r = bus_test_polkit(message, CAP_SYS_BOOT, a->polkit_action_multiple_sessions, NULL, UID_INVALID, &challenge, error);
                 if (r < 0)
                         return r;
 
@@ -2463,7 +2357,7 @@ static int method_can_shutdown_or_sleep(
         }
 
         if (blocked) {
-                r = bus_test_polkit(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, UID_INVALID, &challenge, error);
+                r = bus_test_polkit(message, CAP_SYS_BOOT, a->polkit_action_ignore_inhibit, NULL, UID_INVALID, &challenge, error);
                 if (r < 0)
                         return r;
 
@@ -2481,7 +2375,7 @@ static int method_can_shutdown_or_sleep(
                 /* If neither inhibit nor multiple sessions
                  * apply then just check the normal policy */
 
-                r = bus_test_polkit(message, CAP_SYS_BOOT, action, NULL, UID_INVALID, &challenge, error);
+                r = bus_test_polkit(message, CAP_SYS_BOOT, a->polkit_action, NULL, UID_INVALID, &challenge, error);
                 if (r < 0)
                         return r;
 
@@ -2501,12 +2395,7 @@ static int method_can_poweroff(sd_bus_message *message, void *userdata, sd_bus_e
         Manager *m = userdata;
 
         return method_can_shutdown_or_sleep(
-                        m, message,
-                        INHIBIT_SHUTDOWN,
-                        "org.freedesktop.login1.power-off",
-                        "org.freedesktop.login1.power-off-multiple-sessions",
-                        "org.freedesktop.login1.power-off-ignore-inhibit",
-                        _SLEEP_OPERATION_INVALID,
+                        m, message, manager_item_for_handle(HANDLE_POWEROFF),
                         error);
 }
 
@@ -2514,12 +2403,7 @@ static int method_can_reboot(sd_bus_message *message, void *userdata, sd_bus_err
         Manager *m = userdata;
 
         return method_can_shutdown_or_sleep(
-                        m, message,
-                        INHIBIT_SHUTDOWN,
-                        "org.freedesktop.login1.reboot",
-                        "org.freedesktop.login1.reboot-multiple-sessions",
-                        "org.freedesktop.login1.reboot-ignore-inhibit",
-                        _SLEEP_OPERATION_INVALID,
+                        m, message, manager_item_for_handle(HANDLE_REBOOT),
                         error);
 }
 
@@ -2527,12 +2411,7 @@ static int method_can_halt(sd_bus_message *message, void *userdata, sd_bus_error
         Manager *m = userdata;
 
         return method_can_shutdown_or_sleep(
-                        m, message,
-                        INHIBIT_SHUTDOWN,
-                        "org.freedesktop.login1.halt",
-                        "org.freedesktop.login1.halt-multiple-sessions",
-                        "org.freedesktop.login1.halt-ignore-inhibit",
-                        _SLEEP_OPERATION_INVALID,
+                        m, message, manager_item_for_handle(HANDLE_HALT),
                         error);
 }
 
@@ -2540,12 +2419,7 @@ static int method_can_suspend(sd_bus_message *message, void *userdata, sd_bus_er
         Manager *m = userdata;
 
         return method_can_shutdown_or_sleep(
-                        m, message,
-                        INHIBIT_SLEEP,
-                        "org.freedesktop.login1.suspend",
-                        "org.freedesktop.login1.suspend-multiple-sessions",
-                        "org.freedesktop.login1.suspend-ignore-inhibit",
-                        SLEEP_SUSPEND,
+                        m, message, manager_item_for_handle(HANDLE_SUSPEND),
                         error);
 }
 
@@ -2553,12 +2427,7 @@ static int method_can_hibernate(sd_bus_message *message, void *userdata, sd_bus_
         Manager *m = userdata;
 
         return method_can_shutdown_or_sleep(
-                        m, message,
-                        INHIBIT_SLEEP,
-                        "org.freedesktop.login1.hibernate",
-                        "org.freedesktop.login1.hibernate-multiple-sessions",
-                        "org.freedesktop.login1.hibernate-ignore-inhibit",
-                        SLEEP_HIBERNATE,
+                        m, message, manager_item_for_handle(HANDLE_HIBERNATE),
                         error);
 }
 
@@ -2566,12 +2435,7 @@ static int method_can_hybrid_sleep(sd_bus_message *message, void *userdata, sd_b
         Manager *m = userdata;
 
         return method_can_shutdown_or_sleep(
-                        m, message,
-                        INHIBIT_SLEEP,
-                        "org.freedesktop.login1.hibernate",
-                        "org.freedesktop.login1.hibernate-multiple-sessions",
-                        "org.freedesktop.login1.hibernate-ignore-inhibit",
-                        SLEEP_HYBRID_SLEEP,
+                        m, message, manager_item_for_handle(HANDLE_HYBRID_SLEEP),
                         error);
 }
 
@@ -2579,12 +2443,7 @@ static int method_can_suspend_then_hibernate(sd_bus_message *message, void *user
         Manager *m = userdata;
 
         return method_can_shutdown_or_sleep(
-                        m, message,
-                        INHIBIT_SLEEP,
-                        "org.freedesktop.login1.hibernate",
-                        "org.freedesktop.login1.hibernate-multiple-sessions",
-                        "org.freedesktop.login1.hibernate-ignore-inhibit",
-                        SLEEP_SUSPEND_THEN_HIBERNATE,
+                        m, message, manager_item_for_handle(HANDLE_SUSPEND_THEN_HIBERNATE),
                         error);
 }
 
@@ -3256,6 +3115,15 @@ static int method_set_wall_message(
         if (r < 0)
                 return r;
 
+        /* sysvinit has a 252 (256-(strlen(" \r\n")+1)) character
+         * limit for the wall message. There is no real technical
+         * need for that but doesn't make sense to store arbitrary
+         * armounts either.
+         * https://git.savannah.nongnu.org/cgit/sysvinit.git/tree/src/shutdown.c#n72)
+        */
+        if (strlen(wall_message) > 252)
+                return -EMSGSIZE;
+
         /* Short-circuit the operation if the desired state is already in place, to
          * avoid an unnecessary polkit permission check. */
         if (streq_ptr(m->wall_message, empty_to_null(wall_message)) &&
@@ -3323,7 +3191,7 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
          * executing the operation. We shouldn't create the impression
          * that the lock was successful if the machine is about to go
          * down/suspend any moment. */
-        if (m->action_what & w)
+        if (m->delayed_action && m->delayed_action->inhibit_what & w)
                 return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS,
                                          "The operation inhibition has been requested for is already running");
 
@@ -3830,14 +3698,14 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
         }
 
         if (m->action_job && streq(m->action_job, path)) {
-                log_info("Operation '%s' finished.", inhibit_what_to_string(m->action_what));
+                assert(m->delayed_action);
+                log_info("Operation '%s' finished.", inhibit_what_to_string(m->delayed_action->inhibit_what));
 
                 /* Tell people that they now may take a lock again */
-                (void) send_prepare_for(m, m->action_what, false);
+                (void) send_prepare_for(m, m->delayed_action->inhibit_what, false);
 
                 m->action_job = mfree(m->action_job);
-                m->action_unit = NULL;
-                m->action_what = 0;
+                m->delayed_action = NULL;
                 return 0;
         }
 
index 6b5d3abcd6d1fa43fec633086556902b5af4a52a..13aff11bba8e7b5f3341bc6019c2bc6cf9221bff 100644 (file)
@@ -4,6 +4,7 @@
 #include "sd-bus.h"
 
 #include "bus-object.h"
+#include "logind-action.h"
 #include "logind-session.h"
 #include "logind-user.h"
 #include "logind.h"
@@ -14,7 +15,7 @@ int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char
 
 int manager_dispatch_delayed(Manager *manager, bool timeout);
 
-int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const char *unit_name, InhibitWhat w, sd_bus_error *error);
+int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const ActionTableItem *a, sd_bus_error *error);
 
 int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error);
index d2b2f8b193bc883737056b8d98dc0a1f6274f743..03817f9c1a6c74fc4a77b029968054094e300187 100644 (file)
@@ -72,7 +72,7 @@ static int warn_wall(Manager *m, usec_t n) {
         r = asprintf(&l, "%s%sThe system is going down for %s %s%s!",
                      strempty(m->wall_message),
                      isempty(m->wall_message) ? "" : "\n",
-                     m->scheduled_shutdown_type,
+                     handle_action_to_string(manager_handle_for_item(m->scheduled_shutdown_type)),
                      left ? "at " : "NOW",
                      left ? FORMAT_TIMESTAMP(m->scheduled_shutdown_timeout) : "");
         if (r < 0) {
@@ -130,10 +130,8 @@ int manager_setup_wall_message_timer(Manager *m) {
 
         /* wall message handling */
 
-        if (isempty(m->scheduled_shutdown_type)) {
-                warn_wall(m, n);
+        if (!m->scheduled_shutdown_type)
                 return 0;
-        }
 
         if (elapse > 0 && elapse < n)
                 return 0;
index b24f26485aec56e69e39a3256a70399298fd6fc2..c561b75951fd5da7cffc38e8d6ea2abc3830dc2d 100644 (file)
@@ -168,7 +168,6 @@ static Manager* manager_unref(Manager *m) {
         strv_free(m->kill_only_users);
         strv_free(m->kill_exclude_users);
 
-        free(m->scheduled_shutdown_type);
         free(m->scheduled_shutdown_tty);
         free(m->wall_message);
         free(m->action_job);
index 730c14a46ae708f8c0b386ef071e46fc98637044..5647e5069c154757c516a9a2d3898adf8a45428b 100644 (file)
@@ -68,21 +68,17 @@ struct Manager {
         usec_t inhibit_delay_max;
         usec_t user_stop_delay;
 
-        /* If an action is currently being executed or is delayed,
-         * this is != 0 and encodes what is being done */
-        InhibitWhat action_what;
-
         /* If a shutdown/suspend was delayed due to an inhibitor this
-           contains the unit name we are supposed to start after the
+           contains the action we are supposed to start after the
            delay is over */
-        const char *action_unit;
+        const ActionTableItem *delayed_action;
 
         /* If a shutdown/suspend is currently executed, then this is
          * the job of it */
         char *action_job;
         sd_event_source *inhibit_timeout_source;
 
-        char *scheduled_shutdown_type;
+        const ActionTableItem *scheduled_shutdown_type;
         usec_t scheduled_shutdown_timeout;
         sd_event_source *scheduled_shutdown_timeout_source;
         uid_t scheduled_shutdown_uid;