Merge pull request #6944 from poettering/suspend-fix

systemctl reboot/suspend tweaks
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2017-10-05 11:26:44 +02:00 committed by GitHub
commit c9905d4dd2
6 changed files with 227 additions and 118 deletions

16
NEWS
View file

@ -190,6 +190,20 @@ CHANGES WITH 235:
used to control how the kernel keyring is set up for executed used to control how the kernel keyring is set up for executed
processes. processes.
* "systemctl poweroff", "systemctl reboot", "systemctl halt",
"systemctl kexec" and "systemctl exit" are now always asynchronous in
behaviour (that is: these commands return immediately after the
operation was enqueued instead of waiting until the operation was
completed). Previously, "systemctl poweroff" and "systemctl reboot"
were asynchronous on systems using systemd-logind (i.e. almost
always, and like they were on sysvinit), and the other three commands
were unconditionally synchronous. With this release this is cleaned
up, and callers will see the same asynchronous behaviour on all
systems for all five operations.
* systemd-logind gained new Halt() and CanHalt() bus calls for halting
the system.
* .timer units now accept calendar specifications in other timezones * .timer units now accept calendar specifications in other timezones
than UTC or the local timezone. than UTC or the local timezone.
@ -222,7 +236,7 @@ CHANGES WITH 235:
userwithuid, Vito Caputo, vliaskov, WaLyong Cho, William Douglas, Xiang userwithuid, Vito Caputo, vliaskov, WaLyong Cho, William Douglas, Xiang
Fan, Yu Watanabe, Zbigniew Jędrzejewski-Szmek Fan, Yu Watanabe, Zbigniew Jędrzejewski-Szmek
— Berlin, 2017-09-XX — Berlin, 2017-10-XX
CHANGES WITH 234: CHANGES WITH 234:

View file

@ -407,8 +407,7 @@
<term><option>--no-wall</option></term> <term><option>--no-wall</option></term>
<listitem> <listitem>
<para>Do not send wall message before halt, power-off, <para>Do not send wall message before halt, power-off and reboot.</para>
reboot.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -525,7 +524,7 @@
<option>--force</option> twice with any of these operations might result in data loss. Note that when <option>--force</option> twice with any of these operations might result in data loss. Note that when
<option>--force</option> is specified twice the selected operation is executed by <option>--force</option> is specified twice the selected operation is executed by
<command>systemctl</command> itself, and the system manager is not contacted. This means the command should <command>systemctl</command> itself, and the system manager is not contacted. This means the command should
succeed even when the system manager hangs or crashed.</para> succeed even when the system manager has crashed.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -533,11 +532,9 @@
<term><option>--message=</option></term> <term><option>--message=</option></term>
<listitem> <listitem>
<para>When used with <command>halt</command>, <para>When used with <command>halt</command>, <command>poweroff</command> or <command>reboot</command>, set a
<command>poweroff</command>, <command>reboot</command> or short message explaining the reason for the operation. The message will be logged together with the default
<command>kexec</command>, set a short message explaining the reason shutdown message.</para>
for the operation. The message will be logged together with the
default shutdown message.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -1690,8 +1687,8 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<term><command>default</command></term> <term><command>default</command></term>
<listitem> <listitem>
<para>Enter default mode. This is mostly equivalent to <para>Enter default mode. This is equivalent to <command>systemctl isolate default.target</command>. This
<command>isolate default.target</command>.</para> operation is blocking by default, use <option>--no-block</option> to request asynchronous behavior.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -1699,72 +1696,77 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<term><command>rescue</command></term> <term><command>rescue</command></term>
<listitem> <listitem>
<para>Enter rescue mode. This is mostly equivalent to <para>Enter rescue mode. This is equivalent to <command>systemctl isolate rescue.target</command>. This
<command>isolate rescue.target</command>, but also prints a operation is blocking by default, use <option>--no-block</option> to request asynchronous behavior.</para>
wall message to all users.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><command>emergency</command></term> <term><command>emergency</command></term>
<listitem> <listitem>
<para>Enter emergency mode. This is mostly equivalent to <para>Enter emergency mode. This is equivalent to <command>systemctl isolate
<command>isolate emergency.target</command>, but also prints emergency.target</command>. This operation is blocking by default, use <option>--no-block</option> to
a wall message to all users.</para> request asynchronous behavior.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><command>halt</command></term> <term><command>halt</command></term>
<listitem> <listitem>
<para>Shut down and halt the system. This is mostly equivalent to <command>start halt.target <para>Shut down and halt the system. This is mostly equivalent to <command>systemctl start halt.target
--job-mode=replace-irreversibly</command>, but also prints a wall message to all users. If combined with --job-mode=replace-irreversibly --no-block</command>, but also prints a wall message to all users. This command is
<option>--force</option>, shutdown of all running services is skipped, however all processes are killed and asynchronous; it will return after the halt operation is enqueued, without waiting for it to complete. Note
all file systems are unmounted or mounted read-only, immediately followed by the system halt. If that this operation will simply halt the OS kernel after shutting down, leaving the hardware powered
<option>--force</option> is specified twice, the operation is immediately executed without terminating any on. Use <command>systemctl poweroff</command> for powering off the system (see below).</para>
processes or unmounting any file systems. This may result in data loss. Note that when
<option>--force</option> is specified twice the halt operation is executed by <para>If combined with <option>--force</option>, shutdown of all running services is skipped, however all
<command>systemctl</command> itself, and the system manager is not contacted. This means the command should processes are killed and all file systems are unmounted or mounted read-only, immediately followed by the
succeed even when the system manager hangs or crashed.</para> system halt. If <option>--force</option> is specified twice, the operation is immediately executed without
terminating any processes or unmounting any file systems. This may result in data loss. Note that when
<option>--force</option> is specified twice the halt operation is executed by <command>systemctl</command>
itself, and the system manager is not contacted. This means the command should succeed even when the system
manager has crashed.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><command>poweroff</command></term> <term><command>poweroff</command></term>
<listitem> <listitem>
<para>Shut down and power-off the system. This is mostly equivalent to <command>start poweroff.target <para>Shut down and power-off the system. This is mostly equivalent to <command>systemctl start
--job-mode=replace-irreversibly</command>, but also prints a wall message to all users. If combined with poweroff.target --job-mode=replace-irreversibly --no-block</command>, but also prints a wall message to all
<option>--force</option>, shutdown of all running services is skipped, however all processes are killed and users. This command is asynchronous; it will return after the power-off operation is enqueued, without
all file systems are unmounted or mounted read-only, immediately followed by the powering off. If waiting for it to complete.</para>
<option>--force</option> is specified twice, the operation is immediately executed without terminating any
processes or unmounting any file systems. This may result in data loss. Note that when <para>If combined with <option>--force</option>, shutdown of all running services is skipped, however all
processes are killed and all file systems are unmounted or mounted read-only, immediately followed by the
powering off. If <option>--force</option> is specified twice, the operation is immediately executed without
terminating any processes or unmounting any file systems. This may result in data loss. Note that when
<option>--force</option> is specified twice the power-off operation is executed by <option>--force</option> is specified twice the power-off operation is executed by
<command>systemctl</command> itself, and the system manager is not contacted. This means the command should <command>systemctl</command> itself, and the system manager is not contacted. This means the command should
succeed even when the system manager hangs or crashed.</para> succeed even when the system manager has crashed.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><command>reboot <optional><replaceable>arg</replaceable></optional></command></term> <term><command>reboot <optional><replaceable>arg</replaceable></optional></command></term>
<listitem> <listitem>
<para>Shut down and reboot the system. This is mostly equivalent to <command>start reboot.target <para>Shut down and reboot the system. This is mostly equivalent to <command>systemctl start reboot.target
--job-mode=replace-irreversibly</command>, but also prints a wall message to all users. If combined with --job-mode=replace-irreversibly --no-block</command>, but also prints a wall message to all users. This
<option>--force</option>, shutdown of all running services is skipped, however all processes are killed and command is asynchronous; it will return after the reboot operation is enqueued, without waiting for it to
all file systems are unmounted or mounted read-only, immediately followed by the reboot. If complete.</para>
<option>--force</option> is specified twice, the operation is immediately executed without terminating any
processes or unmounting any file systems. This may result in data loss. Note that when <para>If combined with <option>--force</option>, shutdown of all running services is skipped, however all
processes are killed and all file systems are unmounted or mounted read-only, immediately followed by the
reboot. If <option>--force</option> is specified twice, the operation is immediately executed without
terminating any processes or unmounting any file systems. This may result in data loss. Note that when
<option>--force</option> is specified twice the reboot operation is executed by <option>--force</option> is specified twice the reboot operation is executed by
<command>systemctl</command> itself, and the system manager is not contacted. This means the command should <command>systemctl</command> itself, and the system manager is not contacted. This means the command should
succeed even when the system manager hangs or crashed.</para> succeed even when the system manager has crashed.</para>
<para>If the optional argument <para>If the optional argument <replaceable>arg</replaceable> is given, it will be passed as the optional
<replaceable>arg</replaceable> is given, it will be passed argument to the <citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
as the optional argument to the system call. The value is architecture and firmware specific. As an example, <literal>recovery</literal>
<citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry> might be used to trigger system recovery, and <literal>fota</literal> might be used to trigger a
system call. The value is architecture and firmware
specific. As an example, <literal>recovery</literal> might
be used to trigger system recovery, and
<literal>fota</literal> might be used to trigger a
<quote>firmware over the air</quote> update.</para> <quote>firmware over the air</quote> update.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -1773,13 +1775,14 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<term><command>kexec</command></term> <term><command>kexec</command></term>
<listitem> <listitem>
<para>Shut down and reboot the system via kexec. This is <para>Shut down and reboot the system via <command>kexec</command>. This is equivalent to
mostly equivalent to <command>start kexec.target --job-mode=replace-irreversibly</command>, <command>systemctl start kexec.target --job-mode=replace-irreversibly --no-block</command>. This command is
but also prints a wall message to all users. If combined asynchronous; it will return after the reboot operation is enqueued, without waiting for it to
with <option>--force</option>, shutdown of all running complete.</para>
services is skipped, however all processes are killed and
all file systems are unmounted or mounted read-only, <para>If combined with <option>--force</option>, shutdown of all running services is skipped, however all
immediately followed by the reboot.</para> processes are killed and all file systems are unmounted or mounted read-only, immediately followed by the
reboot.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -1787,14 +1790,13 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<term><command>exit <optional><replaceable>EXIT_CODE</replaceable></optional></command></term> <term><command>exit <optional><replaceable>EXIT_CODE</replaceable></optional></command></term>
<listitem> <listitem>
<para>Ask the systemd manager to quit. This is only <para>Ask the service manager to quit. This is only supported for user service managers (i.e. in
supported for user service managers (i.e. in conjunction conjunction with the <option>--user</option> option) or in containers and is equivalent to
with the <option>--user</option> option) or in containers <command>poweroff</command> otherwise. This command is asynchronous; it will return after the exit
and is equivalent to <command>poweroff</command> otherwise.</para> operation is enqueued, without waiting for it to complete.</para>
<para>The systemd manager can exit with a non-zero exit <para>The service manager will exit with the the specified exit code, if
code if the optional argument <replaceable>EXIT_CODE</replaceable> is passed.</para>
<replaceable>EXIT_CODE</replaceable> is given.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -1818,9 +1820,9 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<term><command>suspend</command></term> <term><command>suspend</command></term>
<listitem> <listitem>
<para>Suspend the system. This will trigger activation of <para>Suspend the system. This will trigger activation of the special target unit
the special <filename>suspend.target</filename> target. <filename>suspend.target</filename>. This command is asynchronous, and will return after the suspend
</para> operation is successfully enqueued. It will not wait for the suspend/resume cycle to complete.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -1828,9 +1830,9 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<term><command>hibernate</command></term> <term><command>hibernate</command></term>
<listitem> <listitem>
<para>Hibernate the system. This will trigger activation of <para>Hibernate the system. This will trigger activation of the special target unit
the special <filename>hibernate.target</filename> target. <filename>hibernate.target</filename>. This command is asynchronous, and will return after the hibernation
</para> operation is successfully enqueued. It will not wait for the hibernate/thaw cycle to complete.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -1838,9 +1840,9 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<term><command>hybrid-sleep</command></term> <term><command>hybrid-sleep</command></term>
<listitem> <listitem>
<para>Hibernate and suspend the system. This will trigger <para>Hibernate and suspend the system. This will trigger activation of the special target unit
activation of the special <filename>hybrid-sleep.target</filename>. This command is asynchronous, and will return after the hybrid
<filename>hybrid-sleep.target</filename> target.</para> sleep operation is successfully enqueued. It will not wait for the sleep/wake-up cycle to complete.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View file

@ -1409,12 +1409,12 @@ static int bus_manager_log_shutdown(
if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) { if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
p = "MESSAGE=System is powering down"; p = "MESSAGE=System is powering down";
q = "SHUTDOWN=power-off"; 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)) { } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
p = "MESSAGE=System is rebooting"; p = "MESSAGE=System is rebooting";
q = "SHUTDOWN=reboot"; 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)) { } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
p = "MESSAGE=System is rebooting with kexec"; p = "MESSAGE=System is rebooting with kexec";
q = "SHUTDOWN=kexec"; q = "SHUTDOWN=kexec";
@ -1822,6 +1822,20 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *
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) { static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata; Manager *m = userdata;
@ -1836,6 +1850,34 @@ static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error
error); error);
} }
static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
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",
"hibernate",
error);
}
static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
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",
"hybrid-sleep",
error);
}
static int nologin_timeout_handler( static int nologin_timeout_handler(
sd_event_source *s, sd_event_source *s,
uint64_t usec, uint64_t usec,
@ -1911,9 +1953,12 @@ fail:
} }
static void reset_scheduled_shutdown(Manager *m) { static void reset_scheduled_shutdown(Manager *m) {
assert(m);
m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source); 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->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->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
m->scheduled_shutdown_type = mfree(m->scheduled_shutdown_type); m->scheduled_shutdown_type = mfree(m->scheduled_shutdown_type);
m->scheduled_shutdown_timeout = 0; m->scheduled_shutdown_timeout = 0;
m->shutdown_dry_run = false; m->shutdown_dry_run = false;
@ -1922,6 +1967,7 @@ static void reset_scheduled_shutdown(Manager *m) {
(void) unlink("/run/nologin"); (void) unlink("/run/nologin");
m->unlink_nologin = false; m->unlink_nologin = false;
} }
(void) unlink("/run/systemd/shutdown/scheduled"); (void) unlink("/run/systemd/shutdown/scheduled");
} }
@ -1940,12 +1986,14 @@ static int manager_scheduled_shutdown_handler(
if (isempty(m->scheduled_shutdown_type)) if (isempty(m->scheduled_shutdown_type))
return 0; return 0;
if (streq(m->scheduled_shutdown_type, "halt")) if (streq(m->scheduled_shutdown_type, "poweroff"))
target = SPECIAL_HALT_TARGET;
else if (streq(m->scheduled_shutdown_type, "poweroff"))
target = SPECIAL_POWEROFF_TARGET; target = SPECIAL_POWEROFF_TARGET;
else else if (streq(m->scheduled_shutdown_type, "reboot"))
target = SPECIAL_REBOOT_TARGET; 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 */ /* Don't allow multiple jobs being executed at the same time */
if (m->action_what) { if (m->action_what) {
@ -1989,6 +2037,7 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
uint64_t elapse; uint64_t elapse;
char *type; char *type;
int r; int r;
bool dry_run = false;
assert(m); assert(m);
assert(message); assert(message);
@ -1999,10 +2048,14 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
if (startswith(type, "dry-")) { if (startswith(type, "dry-")) {
type += 4; type += 4;
m->shutdown_dry_run = true; 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 = "org.freedesktop.login1.reboot";
action_multiple_sessions = "org.freedesktop.login1.reboot-multiple-sessions"; action_multiple_sessions = "org.freedesktop.login1.reboot-multiple-sessions";
action_ignore_inhibit = "org.freedesktop.login1.reboot-ignore-inhibit"; action_ignore_inhibit = "org.freedesktop.login1.reboot-ignore-inhibit";
@ -2010,10 +2063,6 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
action = "org.freedesktop.login1.halt"; action = "org.freedesktop.login1.halt";
action_multiple_sessions = "org.freedesktop.login1.halt-multiple-sessions"; action_multiple_sessions = "org.freedesktop.login1.halt-multiple-sessions";
action_ignore_inhibit = "org.freedesktop.login1.halt-ignore-inhibit"; 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 } else
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type"); return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type");
@ -2043,6 +2092,8 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
return log_oom(); return log_oom();
} }
m->shutdown_dry_run = dry_run;
if (m->nologin_timeout_source) { if (m->nologin_timeout_source) {
r = sd_event_source_set_time(m->nologin_timeout_source, elapse); r = sd_event_source_set_time(m->nologin_timeout_source, elapse);
if (r < 0) if (r < 0)
@ -2114,34 +2165,6 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
return sd_bus_reply_method_return(message, "b", cancelled); return sd_bus_reply_method_return(message, "b", cancelled);
} }
static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
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",
"hibernate",
error);
}
static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
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",
"hybrid-sleep",
error);
}
static int method_can_shutdown_or_sleep( static int method_can_shutdown_or_sleep(
Manager *m, Manager *m,
sd_bus_message *message, sd_bus_message *message,
@ -2260,6 +2283,19 @@ static int method_can_reboot(sd_bus_message *message, void *userdata, sd_bus_err
error); 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) { static int method_can_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata; Manager *m = userdata;
@ -2612,11 +2648,13 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("FlushDevices", "b", NULL, method_flush_devices, SD_BUS_VTABLE_UNPRIVILEGED), 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("PowerOff", "b", NULL, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, 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("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, 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("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("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("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("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("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),

View file

@ -132,6 +132,10 @@
send_interface="org.freedesktop.login1.Manager" send_interface="org.freedesktop.login1.Manager"
send_member="Reboot"/> send_member="Reboot"/>
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Manager"
send_member="Halt"/>
<allow send_destination="org.freedesktop.login1" <allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Manager" send_interface="org.freedesktop.login1.Manager"
send_member="Suspend"/> send_member="Suspend"/>
@ -152,6 +156,10 @@
send_interface="org.freedesktop.login1.Manager" send_interface="org.freedesktop.login1.Manager"
send_member="CanReboot"/> send_member="CanReboot"/>
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Manager"
send_member="CanHalt"/>
<allow send_destination="org.freedesktop.login1" <allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Manager" send_interface="org.freedesktop.login1.Manager"
send_member="CanSuspend"/> send_member="CanSuspend"/>

View file

@ -218,6 +218,39 @@
<annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.reboot</annotate> <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.reboot</annotate>
</action> </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"> <action id="org.freedesktop.login1.suspend">
<_description>Suspend the system</_description> <_description>Suspend the system</_description>
<_message>Authentication is required for suspending the system.</_message> <_message>Authentication is required for suspending the system.</_message>

View file

@ -3267,14 +3267,19 @@ static int logind_reboot(enum action a) {
switch (a) { switch (a) {
case ACTION_POWEROFF:
method = "PowerOff";
description = "power off system";
break;
case ACTION_REBOOT: case ACTION_REBOOT:
method = "Reboot"; method = "Reboot";
description = "reboot system"; description = "reboot system";
break; break;
case ACTION_POWEROFF: case ACTION_HALT:
method = "PowerOff"; method = "Halt";
description = "power off system"; description = "halt system";
break; break;
case ACTION_SUSPEND: case ACTION_SUSPEND:
@ -3568,6 +3573,7 @@ static int start_special(int argc, char *argv[], void *userdata) {
if (IN_SET(a, if (IN_SET(a,
ACTION_POWEROFF, ACTION_POWEROFF,
ACTION_REBOOT, ACTION_REBOOT,
ACTION_HALT,
ACTION_SUSPEND, ACTION_SUSPEND,
ACTION_HIBERNATE, ACTION_HIBERNATE,
ACTION_HYBRID_SLEEP)) { ACTION_HYBRID_SLEEP)) {
@ -3579,8 +3585,16 @@ static int start_special(int argc, char *argv[], void *userdata) {
/* requested operation is not supported or already in progress */ /* requested operation is not supported or already in progress */
return r; return r;
/* On all other errors, try low-level operation */ /* On all other errors, try low-level operation. In order to minimize the difference between
} * operation with and without logind, we explicitly enable non-blocking mode for this, as
* logind's shutdown operations are always non-blocking. */
arg_no_block = true;
} else if (IN_SET(a, ACTION_EXIT, ACTION_KEXEC))
/* Since exit/kexec are so close in behaviour to power-off/reboot, let's also make them
* asynchronous, in order to not confuse the user needlessly with unexpected behaviour. */
arg_no_block = true;
r = start_unit(argc, argv, userdata); r = start_unit(argc, argv, userdata);
} }
@ -8503,7 +8517,7 @@ static int halt_main(void) {
/* Try logind if we are a normal user and no special /* Try logind if we are a normal user and no special
* mode applies. Maybe PolicyKit allows us to shutdown * mode applies. Maybe PolicyKit allows us to shutdown
* the machine. */ * 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); r = logind_reboot(arg_action);
if (r >= 0) if (r >= 0)
return r; return r;