]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sysupdate: Add basic varlink interface scaffolding
authorPhilip Withnall <pwithnall@gnome.org>
Fri, 29 May 2026 12:37:16 +0000 (13:37 +0100)
committerPhilip Withnall <pwithnall@gnome.org>
Fri, 26 Jun 2026 12:01:31 +0000 (13:01 +0100)
This adds the scaffolding for being able to call sysupdate via varlink,
but it doesn’t yet define or implement any methods. Those will come in
following commits.

The existing `systemd-sysupdate.service` and `systemd-sysupdate.timer`
(which periodically ran `systemd-sysupdate update`) have been renamed
to `systemd-sysupdate-update.{service,timer}` to make way for a new
`systemd-sysupdate@.service` and `systemd-sysupdate.socket` file to
handle varlink activation.

Compatibility symlinks have been added for them.

13 files changed:
NEWS
man/rules/meson.build
man/systemd-sysupdate.xml
src/libsystemd/sd-varlink/test-varlink-idl.c
src/shared/meson.build
src/shared/varlink-io.systemd.SysUpdate.c [new file with mode: 0644]
src/shared/varlink-io.systemd.SysUpdate.h [new file with mode: 0644]
src/sysupdate/sysupdate.c
units/meson.build
units/systemd-sysupdate-update.service [moved from units/systemd-sysupdate.service with 86% similarity]
units/systemd-sysupdate-update.timer [moved from units/systemd-sysupdate.timer with 94% similarity]
units/systemd-sysupdate.socket [new file with mode: 0644]
units/systemd-sysupdate@.service [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index e482c3f898f3ac8382f484eb25bacb55fbdb6ac3..d34215377ebc90b3f8ce173f354a1704fe2f31c0 100644 (file)
--- 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:
index 974d9eee4ba24b8edeeffba336ddf549b3512b83..13025b8993cf7d8f61e136edee38b17e392bf9f7 100644 (file)
@@ -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'],
index 7f4b08903159da24d6174f767d39143e591f85d9..2855c650c8856d7c52e909a8500b5d6832d8df7c 100644 (file)
 
   <refnamediv>
     <refname>systemd-sysupdate</refname>
-    <refname>systemd-sysupdate.service</refname>
-    <refname>systemd-sysupdate.timer</refname>
+    <refname>systemd-sysupdate-update.service</refname>
+    <refname>systemd-sysupdate-update.timer</refname>
     <refname>systemd-sysupdate-reboot.service</refname>
     <refname>systemd-sysupdate-reboot.timer</refname>
+
+    <!-- Compatibility symlinks for old names of systemd-sysupdate-update.{service,timer} -->
+    <refname>systemd-sysupdate.service</refname>
+    <refname>systemd-sysupdate.timer</refname>
+
     <refpurpose>Automatically Update OS or Other Resources</refpurpose>
   </refnamediv>
 
@@ -31,7 +36,7 @@
       <arg choice="opt" rep="repeat">OPTIONS</arg>
     </cmdsynopsis>
 
-    <para><filename>systemd-sysupdate.service</filename></para>
+    <para><filename>systemd-sysupdate-update.service</filename></para>
   </refsynopsisdiv>
 
   <refsect1>
@@ -73,9 +78,9 @@
     embedded in the disk images. For the latter, see <option>--image=</option> below. The latter is
     particularly interesting to update container images or portable service images.</para>
 
-    <para>The <filename>systemd-sysupdate.service</filename> system service will automatically update the
+    <para>The <filename>systemd-sysupdate-update.service</filename> system service will automatically update the
     host OS based on the installed transfer files. It is triggered in regular intervals via
-    <filename>systemd-sysupdate.timer</filename>. The <filename>systemd-sysupdate-reboot.service</filename>
+    <filename>systemd-sysupdate-update.timer</filename>. The <filename>systemd-sysupdate-reboot.service</filename>
     will automatically reboot the system after a new version is installed. It is triggered via
     <filename>systemd-sysupdate-reboot.timer</filename>. 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
index 0b3304a43c80a4f69e462d9bc4a26b71d22ace7e..a1ed9a0f4292ba698671239df0dc0d4513b80c1a 100644 (file)
@@ -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,
index 6fa42163056502bdd856dfa575c6e0ddd27be0fd..e2bef83bd267273333e87b22d6c82476cca8880e 100644 (file)
@@ -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 (file)
index 0000000..67595fe
--- /dev/null
@@ -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 (file)
index 0000000..8399cdf
--- /dev/null
@@ -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;
index f0f4ccefc1d9d87dd0ff6e797573b1d7c5730370..f1ba327c5db1310f37cf14a9ef8abb6bb559b72c 100644 (file)
@@ -2,11 +2,13 @@
 
 #include <unistd.h>
 
+#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);
 }
 
index 83dae605fad157689cbebe21d81156db3e075c99..569aa2e2a2cf0439b200ccbd2877dfa099c15536 100644 (file)
@@ -849,13 +849,24 @@ 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.timer',
+          'file' : 'systemd-sysupdate@.service',
           'conditions' : ['ENABLE_SYSUPDATE'],
         },
+        {
+          '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',
           'conditions' : ['ENABLE_SYSUPDATED'],
similarity index 86%
rename from units/systemd-sysupdate.service
rename to units/systemd-sysupdate-update.service
index 92ec7266e8c1db7245d0a8b9b2670457b9efdbe4..e8a634bfff52f37e9158da3cae23cfe00a4e13c2 100644 (file)
@@ -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
similarity index 94%
rename from units/systemd-sysupdate.timer
rename to units/systemd-sysupdate-update.timer
index b2c7cd480873ef46230febee8aa61e92b6a0d37a..d055948c297e8ecdacb829b0b0e7c770864d8af0 100644 (file)
@@ -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 (file)
index 0000000..d91ec79
--- /dev/null
@@ -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 (file)
index 0000000..f8e86dd
--- /dev/null
@@ -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