logind: add io.systemd.Shutdown varlink Shutdown interface
The shutdown interface is currently only exposed via dbus. This commit adds a comparable varlink implementation. It is inspired by the existing dbus methods and implements PowerOff, Reboot, Halt, Kexec, SoftReboot. It is (intentional) simpler than the dbus for now, i.e. strictly root only. To match dbus we will need to the functionality of verify_shutdown_creds() which is dbus-ish right now and would need some refactor. For the same reason it does not do the Can* methods - we will need the verify_shutdown_creds() equivalent first.
This commit is contained in:
@@ -84,6 +84,15 @@
|
|||||||
<citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
<citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||||
for information about the D-Bus APIs <filename>systemd-logind</filename> provides.</para>
|
for information about the D-Bus APIs <filename>systemd-logind</filename> provides.</para>
|
||||||
|
|
||||||
|
<para>In addition to the D-Bus interface, <filename>systemd-logind</filename> also provides a Varlink
|
||||||
|
interface <constant>io.systemd.Shutdown</constant> for shutting down or rebooting the system. It
|
||||||
|
supports <function>PowerOff</function>, <function>Reboot</function>, <function>Halt</function>,
|
||||||
|
<function>KExec</function>, and <function>SoftReboot</function> methods. Each method accepts an
|
||||||
|
optional <varname>skipInhibitors</varname> boolean parameter to bypass active block inhibitors
|
||||||
|
(matching the <constant>SD_LOGIND_SKIP_INHIBITORS</constant> flag of the D-Bus interface). The
|
||||||
|
interface can be queried with
|
||||||
|
<command>varlinkctl introspect /run/systemd/io.systemd.Login io.systemd.Shutdown</command>.</para>
|
||||||
|
|
||||||
<para>For more information see
|
<para>For more information see
|
||||||
<ulink url="https://systemd.io/INHIBITOR_LOCKS">Inhibitor Locks</ulink>.</para>
|
<ulink url="https://systemd.io/INHIBITOR_LOCKS">Inhibitor Locks</ulink>.</para>
|
||||||
|
|
||||||
|
|||||||
+114
-2
@@ -4,15 +4,19 @@
|
|||||||
#include "sd-event.h"
|
#include "sd-event.h"
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
|
#include "bus-error.h"
|
||||||
|
#include "bus-polkit.h"
|
||||||
#include "cgroup-util.h"
|
#include "cgroup-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
#include "json-util.h"
|
#include "json-util.h"
|
||||||
#include "logind-session.h"
|
#include "login-util.h"
|
||||||
#include "logind.h"
|
#include "logind.h"
|
||||||
#include "logind-dbus.h"
|
#include "logind-dbus.h"
|
||||||
#include "logind-seat.h"
|
#include "logind-seat.h"
|
||||||
|
#include "logind-session.h"
|
||||||
|
#include "logind-shutdown.h"
|
||||||
#include "logind-user.h"
|
#include "logind-user.h"
|
||||||
#include "logind-varlink.h"
|
#include "logind-varlink.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
@@ -20,6 +24,7 @@
|
|||||||
#include "user-record.h"
|
#include "user-record.h"
|
||||||
#include "user-util.h"
|
#include "user-util.h"
|
||||||
#include "varlink-io.systemd.Login.h"
|
#include "varlink-io.systemd.Login.h"
|
||||||
|
#include "varlink-io.systemd.Shutdown.h"
|
||||||
#include "varlink-io.systemd.service.h"
|
#include "varlink-io.systemd.service.h"
|
||||||
#include "varlink-util.h"
|
#include "varlink-util.h"
|
||||||
|
|
||||||
@@ -336,6 +341,107 @@ static int vl_method_release_session(sd_varlink *link, sd_json_variant *paramete
|
|||||||
return sd_varlink_reply(link, NULL);
|
return sd_varlink_reply(link, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int setup_wall_message_timer(Manager *m, sd_varlink *link) {
|
||||||
|
uid_t uid = UID_INVALID;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
(void) sd_varlink_get_peer_uid(link, &uid);
|
||||||
|
m->scheduled_shutdown_uid = uid;
|
||||||
|
|
||||||
|
_cleanup_free_ char *tty = NULL;
|
||||||
|
pid_t pid = 0;
|
||||||
|
r = sd_varlink_get_peer_pid(link, &pid);
|
||||||
|
if (r >= 0)
|
||||||
|
(void) get_ctty(pid, /* ret_devnr= */ NULL, &tty);
|
||||||
|
|
||||||
|
r = free_and_strdup_warn(&m->scheduled_shutdown_tty, tty);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
return manager_setup_wall_message_timer(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int manager_do_shutdown_action(sd_varlink *link, sd_json_variant *parameters, HandleAction action) {
|
||||||
|
Manager *m = ASSERT_PTR(sd_varlink_get_userdata(link));
|
||||||
|
int skip_inhibitors = -1;
|
||||||
|
uid_t uid;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
static const sd_json_dispatch_field dispatch_table[] = {
|
||||||
|
{ "skipInhibitors", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, 0, 0 },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
r = sd_varlink_dispatch(link, parameters, dispatch_table, &skip_inhibitors);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
uint64_t flags = skip_inhibitors > 0 ? SD_LOGIND_SKIP_INHIBITORS : 0;
|
||||||
|
|
||||||
|
const HandleActionData *a = handle_action_lookup(action);
|
||||||
|
assert(a);
|
||||||
|
|
||||||
|
/* TODO: provide full polkit support (matching the D-Bus verify_shutdown_creds() with
|
||||||
|
* multiple-sessions and inhibitor-override checks). This requires some refactor. */
|
||||||
|
r = varlink_check_privileged_peer(link);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = sd_varlink_get_peer_uid(link, &uid);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* Check for active inhibitors, mirroring the D-Bus verify_shutdown_creds() logic,
|
||||||
|
* we need this to ensure we handle the strong INHIBIT_BLOCK
|
||||||
|
* TODO: drop once we do the verify_shutdown_creds() */
|
||||||
|
if (manager_is_inhibited(m, a->inhibit_what, NULL, /* flags= */ 0, uid, /* ret_offending= */ NULL) &&
|
||||||
|
!FLAGS_SET(flags, SD_LOGIND_SKIP_INHIBITORS))
|
||||||
|
return sd_varlink_error(link, "io.systemd.Shutdown.BlockedByInhibitor", /* parameters= */ NULL);
|
||||||
|
|
||||||
|
if (m->delayed_action)
|
||||||
|
return sd_varlink_error(link, "io.systemd.Shutdown.AlreadyInProgress", /* parameters= */ NULL);
|
||||||
|
|
||||||
|
/* Reset in case we're short-circuiting a scheduled shutdown */
|
||||||
|
m->unlink_nologin = false;
|
||||||
|
manager_reset_scheduled_shutdown(m);
|
||||||
|
|
||||||
|
m->scheduled_shutdown_timeout = 0;
|
||||||
|
m->scheduled_shutdown_action = action;
|
||||||
|
|
||||||
|
(void) setup_wall_message_timer(m, link);
|
||||||
|
|
||||||
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
|
r = bus_manager_shutdown_or_sleep_now_or_later(m, a, &error);
|
||||||
|
if (r < 0) {
|
||||||
|
log_warning_errno(r, "Failed to execute %s: %s",
|
||||||
|
handle_action_to_string(action),
|
||||||
|
bus_error_message(&error, r));
|
||||||
|
return sd_varlink_error_errno(link, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sd_varlink_reply(link, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vl_method_power_off(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||||
|
return manager_do_shutdown_action(link, parameters, HANDLE_POWEROFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vl_method_reboot(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||||
|
return manager_do_shutdown_action(link, parameters, HANDLE_REBOOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vl_method_halt(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||||
|
return manager_do_shutdown_action(link, parameters, HANDLE_HALT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vl_method_kexec(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||||
|
return manager_do_shutdown_action(link, parameters, HANDLE_KEXEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vl_method_soft_reboot(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||||
|
return manager_do_shutdown_action(link, parameters, HANDLE_SOFT_REBOOT);
|
||||||
|
}
|
||||||
|
|
||||||
int manager_varlink_init(Manager *m, int fd) {
|
int manager_varlink_init(Manager *m, int fd) {
|
||||||
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *s = NULL;
|
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *s = NULL;
|
||||||
_unused_ _cleanup_close_ int fd_close = fd;
|
_unused_ _cleanup_close_ int fd_close = fd;
|
||||||
@@ -358,14 +464,20 @@ int manager_varlink_init(Manager *m, int fd) {
|
|||||||
r = sd_varlink_server_add_interface_many(
|
r = sd_varlink_server_add_interface_many(
|
||||||
s,
|
s,
|
||||||
&vl_interface_io_systemd_Login,
|
&vl_interface_io_systemd_Login,
|
||||||
|
&vl_interface_io_systemd_Shutdown,
|
||||||
&vl_interface_io_systemd_service);
|
&vl_interface_io_systemd_service);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to add Login interface to varlink server: %m");
|
return log_error_errno(r, "Failed to add varlink interfaces: %m");
|
||||||
|
|
||||||
r = sd_varlink_server_bind_method_many(
|
r = sd_varlink_server_bind_method_many(
|
||||||
s,
|
s,
|
||||||
"io.systemd.Login.CreateSession", vl_method_create_session,
|
"io.systemd.Login.CreateSession", vl_method_create_session,
|
||||||
"io.systemd.Login.ReleaseSession", vl_method_release_session,
|
"io.systemd.Login.ReleaseSession", vl_method_release_session,
|
||||||
|
"io.systemd.Shutdown.PowerOff", vl_method_power_off,
|
||||||
|
"io.systemd.Shutdown.Reboot", vl_method_reboot,
|
||||||
|
"io.systemd.Shutdown.Halt", vl_method_halt,
|
||||||
|
"io.systemd.Shutdown.KExec", vl_method_kexec,
|
||||||
|
"io.systemd.Shutdown.SoftReboot", vl_method_soft_reboot,
|
||||||
"io.systemd.service.Ping", varlink_method_ping,
|
"io.systemd.service.Ping", varlink_method_ping,
|
||||||
"io.systemd.service.SetLogLevel", varlink_method_set_log_level,
|
"io.systemd.service.SetLogLevel", varlink_method_set_log_level,
|
||||||
"io.systemd.service.GetEnvironment", varlink_method_get_environment);
|
"io.systemd.service.GetEnvironment", varlink_method_get_environment);
|
||||||
|
|||||||
@@ -230,6 +230,7 @@ shared_sources = files(
|
|||||||
'varlink-io.systemd.Resolve.c',
|
'varlink-io.systemd.Resolve.c',
|
||||||
'varlink-io.systemd.Resolve.Hook.c',
|
'varlink-io.systemd.Resolve.Hook.c',
|
||||||
'varlink-io.systemd.Resolve.Monitor.c',
|
'varlink-io.systemd.Resolve.Monitor.c',
|
||||||
|
'varlink-io.systemd.Shutdown.c',
|
||||||
'varlink-io.systemd.Udev.c',
|
'varlink-io.systemd.Udev.c',
|
||||||
'varlink-io.systemd.Unit.c',
|
'varlink-io.systemd.Unit.c',
|
||||||
'varlink-io.systemd.UserDatabase.c',
|
'varlink-io.systemd.UserDatabase.c',
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include "bus-polkit.h"
|
||||||
|
#include "varlink-io.systemd.Shutdown.h"
|
||||||
|
|
||||||
|
static SD_VARLINK_DEFINE_METHOD(
|
||||||
|
PowerOff,
|
||||||
|
VARLINK_DEFINE_POLKIT_INPUT,
|
||||||
|
SD_VARLINK_FIELD_COMMENT("Skip active inhibitors and force the operation"),
|
||||||
|
SD_VARLINK_DEFINE_INPUT(skipInhibitors, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
|
||||||
|
static SD_VARLINK_DEFINE_METHOD(
|
||||||
|
Reboot,
|
||||||
|
VARLINK_DEFINE_POLKIT_INPUT,
|
||||||
|
SD_VARLINK_FIELD_COMMENT("Skip active inhibitors and force the operation"),
|
||||||
|
SD_VARLINK_DEFINE_INPUT(skipInhibitors, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
|
||||||
|
static SD_VARLINK_DEFINE_METHOD(
|
||||||
|
Halt,
|
||||||
|
VARLINK_DEFINE_POLKIT_INPUT,
|
||||||
|
SD_VARLINK_FIELD_COMMENT("Skip active inhibitors and force the operation"),
|
||||||
|
SD_VARLINK_DEFINE_INPUT(skipInhibitors, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
|
||||||
|
static SD_VARLINK_DEFINE_METHOD(
|
||||||
|
KExec,
|
||||||
|
VARLINK_DEFINE_POLKIT_INPUT,
|
||||||
|
SD_VARLINK_FIELD_COMMENT("Skip active inhibitors and force the operation"),
|
||||||
|
SD_VARLINK_DEFINE_INPUT(skipInhibitors, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
|
||||||
|
static SD_VARLINK_DEFINE_METHOD(
|
||||||
|
SoftReboot,
|
||||||
|
VARLINK_DEFINE_POLKIT_INPUT,
|
||||||
|
SD_VARLINK_FIELD_COMMENT("Skip active inhibitors and force the operation"),
|
||||||
|
SD_VARLINK_DEFINE_INPUT(skipInhibitors, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
|
||||||
|
|
||||||
|
static SD_VARLINK_DEFINE_ERROR(AlreadyInProgress);
|
||||||
|
static SD_VARLINK_DEFINE_ERROR(BlockedByInhibitor);
|
||||||
|
|
||||||
|
SD_VARLINK_DEFINE_INTERFACE(
|
||||||
|
io_systemd_Shutdown,
|
||||||
|
"io.systemd.Shutdown",
|
||||||
|
SD_VARLINK_INTERFACE_COMMENT("APIs for shutting down or rebooting the system."),
|
||||||
|
SD_VARLINK_SYMBOL_COMMENT("Power off the system"),
|
||||||
|
&vl_method_PowerOff,
|
||||||
|
SD_VARLINK_SYMBOL_COMMENT("Reboot the system"),
|
||||||
|
&vl_method_Reboot,
|
||||||
|
SD_VARLINK_SYMBOL_COMMENT("Halt the system"),
|
||||||
|
&vl_method_Halt,
|
||||||
|
SD_VARLINK_SYMBOL_COMMENT("Reboot the system via kexec"),
|
||||||
|
&vl_method_KExec,
|
||||||
|
SD_VARLINK_SYMBOL_COMMENT("Reboot userspace only"),
|
||||||
|
&vl_method_SoftReboot,
|
||||||
|
SD_VARLINK_SYMBOL_COMMENT("Another shutdown or sleep operation is already in progress"),
|
||||||
|
&vl_error_AlreadyInProgress,
|
||||||
|
SD_VARLINK_SYMBOL_COMMENT("Operation denied due to active block inhibitor"),
|
||||||
|
&vl_error_BlockedByInhibitor);
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sd-varlink-idl.h"
|
||||||
|
|
||||||
|
extern const sd_varlink_interface vl_interface_io_systemd_Shutdown;
|
||||||
@@ -13,7 +13,7 @@ Documentation=man:systemd-logind.service(8)
|
|||||||
|
|
||||||
[Socket]
|
[Socket]
|
||||||
ListenStream=/run/systemd/io.systemd.Login
|
ListenStream=/run/systemd/io.systemd.Login
|
||||||
Symlinks=/run/varlink/registry/io.systemd.Login
|
Symlinks=/run/varlink/registry/io.systemd.Login /run/varlink/registry/io.systemd.Shutdown /run/systemd/io.systemd.Shutdown
|
||||||
FileDescriptorName=varlink
|
FileDescriptorName=varlink
|
||||||
SocketMode=0666
|
SocketMode=0666
|
||||||
Service=systemd-logind.service
|
Service=systemd-logind.service
|
||||||
|
|||||||
Reference in New Issue
Block a user