]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
logind: add Halt() and CanHalt() APIs
authorLennart Poettering <lennart@poettering.net>
Mon, 2 Oct 2017 14:03:55 +0000 (16:03 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 4 Oct 2017 18:56:24 +0000 (20:56 +0200)
This adds new method calls Halt() and CanHalt() to the logind bus APIs.
They aren't overly useful (as the whole concept of halting isn't really
too useful), however they clean up one major asymmetry: currently, using
the "shutdown" legacy commands it is possibly to enqueue a "halt"
operation through logind, while logind officially doesn't actually
support this. Moreover, the path through "shutdown" currently ultimately
fails, since the referenced "halt" action isn't actually defined in
PolicyKit.

Finally, the current logic results in an unexpected asymmetry in
systemctl: "systemctl poweroff", "systemctl reboot" are currently
asynchronous (due to the logind involvement) while "systemctl halt"
isnt. Let's clean this up, and make all three APIs implemented by
logind natively, and all three hence asynchronous in "systemctl".

Moreover, let's add the missing PK action.

Fixes: #6957
src/login/logind-dbus.c
src/login/org.freedesktop.login1.conf
src/login/org.freedesktop.login1.policy.in
src/systemctl/systemctl.c

index 1aa67606652f57c82e6123f1b95b185266c49410..b346ab527899b7d9f08c4cc5af152d2fabf700e2 100644 (file)
@@ -1409,12 +1409,12 @@ static int bus_manager_log_shutdown(
         if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
                 p = "MESSAGE=System is powering down";
                 q = "SHUTDOWN=power-off";
-        } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
-                p = "MESSAGE=System is halting";
-                q = "SHUTDOWN=halt";
         } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
                 p = "MESSAGE=System is rebooting";
                 q = "SHUTDOWN=reboot";
+        } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
+                p = "MESSAGE=System is halting";
+                q = "SHUTDOWN=halt";
         } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
                 p = "MESSAGE=System is rebooting with kexec";
                 q = "SHUTDOWN=kexec";
@@ -1822,6 +1822,20 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *
                         error);
 }
 
+static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Manager *m = userdata;
+
+        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",
+                        NULL,
+                        error);
+}
+
 static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
 
@@ -1911,9 +1925,12 @@ fail:
 }
 
 static void reset_scheduled_shutdown(Manager *m) {
+        assert(m);
+
         m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
         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->shutdown_dry_run = false;
@@ -1922,6 +1939,7 @@ static void reset_scheduled_shutdown(Manager *m) {
                 (void) unlink("/run/nologin");
                 m->unlink_nologin = false;
         }
+
         (void) unlink("/run/systemd/shutdown/scheduled");
 }
 
@@ -1940,12 +1958,14 @@ static int manager_scheduled_shutdown_handler(
         if (isempty(m->scheduled_shutdown_type))
                 return 0;
 
-        if (streq(m->scheduled_shutdown_type, "halt"))
-                target = SPECIAL_HALT_TARGET;
-        else if (streq(m->scheduled_shutdown_type, "poweroff"))
+        if (streq(m->scheduled_shutdown_type, "poweroff"))
                 target = SPECIAL_POWEROFF_TARGET;
-        else
+        else if (streq(m->scheduled_shutdown_type, "reboot"))
                 target = SPECIAL_REBOOT_TARGET;
+        else if (streq(m->scheduled_shutdown_type, "halt"))
+                target = SPECIAL_HALT_TARGET;
+        else
+                assert_not_reached("unexpected shutdown type");
 
         /* Don't allow multiple jobs being executed at the same time */
         if (m->action_what) {
@@ -2002,7 +2022,11 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
                 m->shutdown_dry_run = true;
         }
 
-        if (streq(type, "reboot")) {
+        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 (streq(type, "reboot")) {
                 action = "org.freedesktop.login1.reboot";
                 action_multiple_sessions = "org.freedesktop.login1.reboot-multiple-sessions";
                 action_ignore_inhibit = "org.freedesktop.login1.reboot-ignore-inhibit";
@@ -2010,10 +2034,6 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
                 action = "org.freedesktop.login1.halt";
                 action_multiple_sessions = "org.freedesktop.login1.halt-multiple-sessions";
                 action_ignore_inhibit = "org.freedesktop.login1.halt-ignore-inhibit";
-        } else 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
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type");
 
@@ -2260,6 +2280,19 @@ static int method_can_reboot(sd_bus_message *message, void *userdata, sd_bus_err
                         error);
 }
 
+static int method_can_halt(sd_bus_message *message, void *userdata, sd_bus_error *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",
+                        NULL,
+                        error);
+}
+
 static int method_can_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
 
@@ -2612,11 +2645,13 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD("FlushDevices", "b", NULL, method_flush_devices, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("PowerOff", "b", NULL, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("Halt", "b", NULL, method_halt, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanReboot", NULL, "s", method_can_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("CanHalt", NULL, "s", method_can_halt, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
index c89e40457e7f316cf7fae06345423695f51aef49..27aac0dd7c0deb3fd54ff8b6003486caf7272b5d 100644 (file)
                        send_interface="org.freedesktop.login1.Manager"
                        send_member="Reboot"/>
 
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="Halt"/>
+
                 <allow send_destination="org.freedesktop.login1"
                        send_interface="org.freedesktop.login1.Manager"
                        send_member="Suspend"/>
                        send_interface="org.freedesktop.login1.Manager"
                        send_member="CanReboot"/>
 
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="CanHalt"/>
+
                 <allow send_destination="org.freedesktop.login1"
                        send_interface="org.freedesktop.login1.Manager"
                        send_member="CanSuspend"/>
index 66cbce393ce12991763bfc9894032052837b5142..3e8a9bbe3f9fe20d137080e70dfd8a5f42d31437 100644 (file)
                 <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.reboot</annotate>
         </action>
 
+        <action id="org.freedesktop.login1.halt">
+                <_description>Halt the system</_description>
+                <_message>Authentication is required for halting the system.</_message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.set-wall-message</annotate>
+        </action>
+
+        <action id="org.freedesktop.login1.halt-multiple-sessions">
+                <_description>Halt the system while other users are logged in</_description>
+                <_message>Authentication is required for halting the system while other users are logged in.</_message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.halt</annotate>
+        </action>
+
+        <action id="org.freedesktop.login1.halt-ignore-inhibit">
+                <_description>Halt the system while an application asked to inhibit it</_description>
+                <_message>Authentication is required for halting the system while an application asked to inhibit it.</_message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.halt</annotate>
+        </action>
+
         <action id="org.freedesktop.login1.suspend">
                 <_description>Suspend the system</_description>
                 <_message>Authentication is required for suspending the system.</_message>
index 280d786daa422a08e7a996b03dbaf680e70086c5..2a385bf35035711182037922d375c770655414f0 100644 (file)
@@ -3267,14 +3267,19 @@ static int logind_reboot(enum action a) {
 
         switch (a) {
 
+        case ACTION_POWEROFF:
+                method = "PowerOff";
+                description = "power off system";
+                break;
+
         case ACTION_REBOOT:
                 method = "Reboot";
                 description = "reboot system";
                 break;
 
-        case ACTION_POWEROFF:
-                method = "PowerOff";
-                description = "power off system";
+        case ACTION_HALT:
+                method = "Halt";
+                description = "halt system";
                 break;
 
         case ACTION_SUSPEND:
@@ -3568,6 +3573,7 @@ static int start_special(int argc, char *argv[], void *userdata) {
                 if (IN_SET(a,
                            ACTION_POWEROFF,
                            ACTION_REBOOT,
+                           ACTION_HALT,
                            ACTION_SUSPEND,
                            ACTION_HIBERNATE,
                            ACTION_HYBRID_SLEEP)) {
@@ -8503,7 +8509,7 @@ static int halt_main(void) {
                 /* Try logind if we are a normal user and no special
                  * mode applies. Maybe PolicyKit allows us to shutdown
                  * the machine. */
-                if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT)) {
+                if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_HALT)) {
                         r = logind_reboot(arg_action);
                         if (r >= 0)
                                 return r;