diff --git a/NEWS b/NEWS
index e482c3f898..d34215377e 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,14 @@ CHANGES WITH 262:
the symlink target. Previously, these were only expanded in the
source.
+ * As part of changes to systemd-sysupdate, the existing
+ "systemd-sysupdate.service" and "systemd-sysupdate.timer" units –
+ which periodically ran "systemd-sysupdate" to update the host system –
+ have been renamed to "systemd-sysupdate-update.service" and
+ "systemd-sysupdate-update.timer" respectively. Compatibility symlinks
+ have been provided. This clears the way for a new
+ "systemd-sysupdate@.service" unit for varlink activation of sysupdate.
+
CHANGES WITH 261:
Announcements of Future Feature Removals and Incompatible Changes:
diff --git a/man/rules/meson.build b/man/rules/meson.build
index 974d9eee4b..13025b8993 100644
--- a/man/rules/meson.build
+++ b/man/rules/meson.build
@@ -1267,6 +1267,8 @@ manpages = [
'8',
['systemd-sysupdate-reboot.service',
'systemd-sysupdate-reboot.timer',
+ 'systemd-sysupdate-update.service',
+ 'systemd-sysupdate-update.timer',
'systemd-sysupdate.service',
'systemd-sysupdate.timer'],
'ENABLE_SYSUPDATE'],
diff --git a/man/systemd-sysupdate.xml b/man/systemd-sysupdate.xml
index 7f4b089031..2855c650c8 100644
--- a/man/systemd-sysupdate.xml
+++ b/man/systemd-sysupdate.xml
@@ -18,10 +18,15 @@
systemd-sysupdate
- systemd-sysupdate.service
- systemd-sysupdate.timer
+ systemd-sysupdate-update.service
+ systemd-sysupdate-update.timer
systemd-sysupdate-reboot.service
systemd-sysupdate-reboot.timer
+
+
+ systemd-sysupdate.service
+ systemd-sysupdate.timer
+
Automatically Update OS or Other Resources
@@ -31,7 +36,7 @@
OPTIONS
- systemd-sysupdate.service
+ systemd-sysupdate-update.service
@@ -73,9 +78,9 @@
embedded in the disk images. For the latter, see below. The latter is
particularly interesting to update container images or portable service images.
- The systemd-sysupdate.service system service will automatically update the
+ The systemd-sysupdate-update.service system service will automatically update the
host OS based on the installed transfer files. It is triggered in regular intervals via
- systemd-sysupdate.timer. The systemd-sysupdate-reboot.service
+ systemd-sysupdate-update.timer. The systemd-sysupdate-reboot.service
will automatically reboot the system after a new version is installed. It is triggered via
systemd-sysupdate-reboot.timer. The two services are separate from each other as it
is typically advisable to download updates regularly while the system is up, but delay reboots until the
diff --git a/src/libsystemd/sd-varlink/test-varlink-idl.c b/src/libsystemd/sd-varlink/test-varlink-idl.c
index 0b3304a43c..a1ed9a0f42 100644
--- a/src/libsystemd/sd-varlink/test-varlink-idl.c
+++ b/src/libsystemd/sd-varlink/test-varlink-idl.c
@@ -51,6 +51,7 @@
#include "varlink-io.systemd.Resolve.Monitor.h"
#include "varlink-io.systemd.Shutdown.h"
#include "varlink-io.systemd.StorageProvider.h"
+#include "varlink-io.systemd.SysUpdate.h"
#include "varlink-io.systemd.SysUpdate.Notify.h"
#include "varlink-io.systemd.Udev.h"
#include "varlink-io.systemd.Unit.h"
@@ -228,6 +229,7 @@ TEST(parse_format) {
&vl_interface_io_systemd_Resolve_Monitor,
&vl_interface_io_systemd_Shutdown,
&vl_interface_io_systemd_StorageProvider,
+ &vl_interface_io_systemd_SysUpdate,
&vl_interface_io_systemd_SysUpdate_Notify,
&vl_interface_io_systemd_Udev,
&vl_interface_io_systemd_Unit,
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 6fa4216305..e2bef83bd2 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -251,6 +251,7 @@ shared_sources = files(
'varlink-io.systemd.Resolve.Monitor.c',
'varlink-io.systemd.Shutdown.c',
'varlink-io.systemd.StorageProvider.c',
+ 'varlink-io.systemd.SysUpdate.c',
'varlink-io.systemd.SysUpdate.Notify.c',
'varlink-io.systemd.Udev.c',
'varlink-io.systemd.Unit.c',
diff --git a/src/shared/varlink-io.systemd.SysUpdate.c b/src/shared/varlink-io.systemd.SysUpdate.c
new file mode 100644
index 0000000000..67595fe9ee
--- /dev/null
+++ b/src/shared/varlink-io.systemd.SysUpdate.c
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "bus-polkit.h"
+#include "varlink-io.systemd.SysUpdate.h"
+
+SD_VARLINK_DEFINE_INTERFACE(
+ io_systemd_SysUpdate,
+ "io.systemd.SysUpdate",
+ SD_VARLINK_INTERFACE_COMMENT("APIs to manage system updates"));
diff --git a/src/shared/varlink-io.systemd.SysUpdate.h b/src/shared/varlink-io.systemd.SysUpdate.h
new file mode 100644
index 0000000000..8399cdfbc3
--- /dev/null
+++ b/src/shared/varlink-io.systemd.SysUpdate.h
@@ -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_SysUpdate;
diff --git a/src/sysupdate/sysupdate.c b/src/sysupdate/sysupdate.c
index f0f4ccefc1..f1ba327c5d 100644
--- a/src/sysupdate/sysupdate.c
+++ b/src/sysupdate/sysupdate.c
@@ -2,11 +2,13 @@
#include
+#include "sd-bus.h"
#include "sd-daemon.h"
#include "sd-json.h"
#include "sd-varlink.h"
#include "build.h"
+#include "bus-polkit.h"
#include "conf-files.h"
#include "constants.h"
#include "dissect-image.h"
@@ -19,6 +21,7 @@
#include "help-util.h"
#include "hexdecoct.h"
#include "image-policy.h"
+#include "json-util.h"
#include "loop-util.h"
#include "main-func.h"
#include "mount-util.h"
@@ -39,6 +42,7 @@
#include "sysupdate-transfer.h"
#include "sysupdate-update-set.h"
#include "sysupdate-util.h"
+#include "varlink-io.systemd.SysUpdate.h"
#include "varlink-util.h"
#include "verbs.h"
@@ -58,6 +62,7 @@ static int arg_verify = -1;
static ImagePolicy *arg_image_policy = NULL;
static bool arg_offline = false;
static char *arg_transfer_source = NULL;
+static bool arg_varlink = false;
STATIC_DESTRUCTOR_REGISTER(arg_definitions, freep);
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
@@ -154,6 +159,25 @@ static int context_from_cmdline(Context *ret) {
return 0;
}
+/* Stores any long-running server state which needs to persist between varlink calls, such as state for
+ * pending polkit requests */
+typedef struct Server {
+ sd_bus *system_bus;
+ Hashmap *polkit_registry;
+} Server;
+
+#define SERVER_NULL \
+ (Server) { \
+ /* all fields fine with being initialised to NULL */ \
+ }
+
+static void server_done(Server *s) {
+ assert(s);
+
+ s->polkit_registry = hashmap_free(s->polkit_registry);
+ s->system_bus = sd_bus_flush_close_unref(s->system_bus);
+}
+
static DEFINE_POINTER_ARRAY_FREE_FUNC(Transfer*, transfer_free);
static int read_definitions(
@@ -1413,6 +1437,29 @@ static int context_install(
return 1;
}
+static int verify_polkit(Context *context, sd_varlink *link, const char *action, const char **details) {
+ int r;
+ Server *s = ASSERT_PTR(sd_varlink_get_userdata(ASSERT_PTR(link)));
+
+ assert(context);
+
+ if (!s->system_bus) {
+ r = sd_bus_open_system_with_description(&s->system_bus, "sysupdate-system");
+ if (r < 0)
+ return log_error_errno(r, "Failed to get system bus connection: %m");
+
+ r = sd_bus_attach_event(s->system_bus, sd_varlink_get_event(link), SD_EVENT_PRIORITY_NORMAL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to attach system bus to event loop: %m");
+ }
+
+ return varlink_verify_polkit_async(link,
+ s->system_bus,
+ action,
+ details,
+ &s->polkit_registry);
+}
+
VERB(verb_list, "list", "[VERSION]", VERB_ANY, 2, VERB_DEFAULT,
"Show installed and available versions");
static int verb_list(int argc, char *argv[], uintptr_t _data, void *userdata) {
@@ -2220,10 +2267,43 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) {
if (arg_definitions && arg_component)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "The --definitions= and --component= switches may not be combined.");
+ r = sd_varlink_invocation(SD_VARLINK_ALLOW_ACCEPT);
+ if (r < 0)
+ return log_error_errno(r, "Failed to check if invoked in Varlink mode: %m");
+ if (r > 0)
+ arg_varlink = true;
+
*remaining_args = option_parser_get_args(&opts);
return 1;
}
+static int vl_server(void) {
+ _cleanup_(sd_varlink_server_unrefp) sd_varlink_server *varlink_server = NULL;
+ _cleanup_(server_done) Server server = SERVER_NULL;
+ int r;
+
+ r = varlink_server_new(&varlink_server,
+ SD_VARLINK_SERVER_ACCOUNT_UID|SD_VARLINK_SERVER_INHERIT_USERDATA,
+ &server);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate Varlink server: %m");
+
+ r = sd_varlink_server_add_interface(varlink_server, &vl_interface_io_systemd_SysUpdate);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add Varlink interface: %m");
+
+ r = sd_varlink_server_bind_method_many(
+ varlink_server);
+ if (r < 0)
+ return log_error_errno(r, "Failed to bind Varlink method: %m");
+
+ r = sd_varlink_server_loop_auto(varlink_server);
+ if (r < 0)
+ return log_error_errno(r, "Failed to run Varlink event loop: %m");
+
+ return 0;
+}
+
static int run(int argc, char *argv[]) {
int r;
@@ -2234,6 +2314,9 @@ static int run(int argc, char *argv[]) {
if (r <= 0)
return r;
+ if (arg_varlink)
+ return vl_server(); /* Invocation as Varlink service */
+
return dispatch_verb(args, NULL);
}
diff --git a/units/meson.build b/units/meson.build
index 83dae605fa..569aa2e2a2 100644
--- a/units/meson.build
+++ b/units/meson.build
@@ -849,12 +849,23 @@ units = [
'conditions' : ['ENABLE_SYSUPDATE'],
},
{
- 'file' : 'systemd-sysupdate.service',
+ 'file' : 'systemd-sysupdate-update.service',
+ 'conditions' : ['ENABLE_SYSUPDATE'],
+ 'symlinks' : ['systemd-sysupdate.service'], # compatibility after rename
+ },
+ {
+ 'file' : 'systemd-sysupdate@.service',
'conditions' : ['ENABLE_SYSUPDATE'],
},
{
- 'file' : 'systemd-sysupdate.timer',
+ 'file' : 'systemd-sysupdate.socket',
'conditions' : ['ENABLE_SYSUPDATE'],
+ 'symlinks' : ['sockets.target.wants/'],
+ },
+ {
+ 'file' : 'systemd-sysupdate-update.timer',
+ 'conditions' : ['ENABLE_SYSUPDATE'],
+ 'symlinks' : ['systemd-sysupdate.timer'], # compatibility after rename
},
{
'file' : 'systemd-sysupdated.service.in',
diff --git a/units/systemd-sysupdate.service b/units/systemd-sysupdate-update.service
similarity index 86%
rename from units/systemd-sysupdate.service
rename to units/systemd-sysupdate-update.service
index 92ec7266e8..e8a634bfff 100644
--- a/units/systemd-sysupdate.service
+++ b/units/systemd-sysupdate-update.service
@@ -9,7 +9,7 @@
[Unit]
Description=Automatic System Update
-Documentation=man:systemd-sysupdate.service(8)
+Documentation=man:systemd-sysupdate-update.service(8)
Wants=network-online.target
After=network-online.target
ConditionVirtualization=!container
@@ -18,6 +18,8 @@ ConditionVirtualization=!container
Type=simple
NotifyAccess=main
ExecStart=systemd-sysupdate update --cleanup=yes
+
+# Keep this sandboxing synchronised with systemd-sysupdate@.service
CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD CAP_SETFCAP CAP_SYS_ADMIN CAP_SETPCAP CAP_DAC_OVERRIDE CAP_LINUX_IMMUTABLE
NoNewPrivileges=yes
MemoryDenyWriteExecute=yes
@@ -31,4 +33,4 @@ SystemCallArchitectures=native
LockPersonality=yes
[Install]
-Also=systemd-sysupdate.timer
+Also=systemd-sysupdate-update.timer
diff --git a/units/systemd-sysupdate.timer b/units/systemd-sysupdate-update.timer
similarity index 94%
rename from units/systemd-sysupdate.timer
rename to units/systemd-sysupdate-update.timer
index b2c7cd4808..d055948c29 100644
--- a/units/systemd-sysupdate.timer
+++ b/units/systemd-sysupdate-update.timer
@@ -9,7 +9,7 @@
[Unit]
Description=Automatic System Update
-Documentation=man:systemd-sysupdate.service(8)
+Documentation=man:systemd-sysupdate-update.service(8)
# For containers we assume that the manager will handle updates. And we likely
# can't even access our backing block device anyway.
diff --git a/units/systemd-sysupdate.socket b/units/systemd-sysupdate.socket
new file mode 100644
index 0000000000..d91ec793e7
--- /dev/null
+++ b/units/systemd-sysupdate.socket
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=System Updates
+Documentation=man:systemd-sysupdate(8)
+DefaultDependencies=no
+Before=sockets.target
+
+[Socket]
+ListenStream=/run/systemd/io.systemd.SysUpdate
+Symlinks=/run/varlink/registry/io.systemd.SysUpdate
+FileDescriptorName=varlink
+SocketMode=0666
+Accept=yes
+MaxConnectionsPerSource=16
+XAttrEntryPoint=user.varlink=entrypoint
+XAttrListen=user.varlink=listen
+XAttrAccept=user.varlink=server
+
+[Install]
+WantedBy=sockets.target
diff --git a/units/systemd-sysupdate@.service b/units/systemd-sysupdate@.service
new file mode 100644
index 0000000000..f8e86dd2c4
--- /dev/null
+++ b/units/systemd-sysupdate@.service
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=System Updates
+Documentation=man:systemd-sysupdate(8)
+DefaultDependencies=no
+Conflicts=shutdown.target
+Before=shutdown.target
+
+[Service]
+ExecStart=-systemd-sysupdate
+
+# Keep this sandboxing synchronised with systemd-sysupdate-update.service
+CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD CAP_SETFCAP CAP_SYS_ADMIN CAP_SETPCAP CAP_DAC_OVERRIDE CAP_LINUX_IMMUTABLE
+NoNewPrivileges=yes
+MemoryDenyWriteExecute=yes
+ProtectHostname=yes
+RestrictRealtime=yes
+RestrictNamespaces=net
+RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
+SystemCallFilter=@system-service @mount
+SystemCallErrorNumber=EPERM
+SystemCallArchitectures=native
+LockPersonality=yes