]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Add helpers for talking to /dev/liveupdate
authorLuca Boccassi <luca.boccassi@gmail.com>
Mon, 30 Mar 2026 14:43:29 +0000 (15:43 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Fri, 15 May 2026 12:46:08 +0000 (13:46 +0100)
This character device is the main kernel interface to deal with the
Live Update Orchestrator (LUO) feature. Add some basic wrappers for
the ioctls.

https://docs.kernel.org/userspace-api/liveupdate.html

src/shared/luo-util.c [new file with mode: 0644]
src/shared/luo-util.h [new file with mode: 0644]
src/shared/meson.build

diff --git a/src/shared/luo-util.c b/src/shared/luo-util.c
new file mode 100644 (file)
index 0000000..12f5dbc
--- /dev/null
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <fcntl.h>
+#include <linux/liveupdate.h>
+#include <sys/ioctl.h>
+
+#include "errno-util.h"
+#include "fd-util.h"
+#include "luo-util.h"
+#include "string-util.h"
+
+/* Kernel API defined at https://docs.kernel.org/userspace-api/liveupdate.html The /dev/liveupdate is a
+ * single-owner singleton, only a single process at any given time can open it. Callers can create named
+ * "sessions", and then add FDs to them. The session name can be used to retrieve the session after reboot.
+ * To identify an FD, a 64bit token (what we would call an 'index' in our codebase) is passed in, and the
+ * caller is responsible for coming up with the token and tracking them. */
+
+int luo_open_device(void) {
+        return RET_NERRNO(open("/dev/liveupdate", O_RDWR|O_CLOEXEC));
+}
+
+int luo_create_session(int device_fd, const char *name) {
+        struct liveupdate_ioctl_create_session args = {
+                .size = sizeof(args),
+                .fd = -EBADF,
+        };
+
+        assert(device_fd >= 0);
+        assert(name);
+
+        if (strlen(name) >= sizeof(args.name))
+                return -ENAMETOOLONG;
+
+        strncpy_exact((char *) args.name, name, sizeof(args.name));
+
+        if (ioctl(device_fd, LIVEUPDATE_IOCTL_CREATE_SESSION, &args) < 0)
+                return -errno;
+
+        return args.fd;
+}
+
+int luo_retrieve_session(int device_fd, const char *name) {
+        struct liveupdate_ioctl_retrieve_session args = {
+                .size = sizeof(args),
+                .fd = -EBADF,
+        };
+
+        assert(device_fd >= 0);
+        assert(name);
+
+        if (strlen(name) >= sizeof(args.name))
+                return -ENAMETOOLONG;
+
+        strncpy_exact((char *) args.name, name, sizeof(args.name));
+
+        if (ioctl(device_fd, LIVEUPDATE_IOCTL_RETRIEVE_SESSION, &args) < 0)
+                return -errno;
+
+        return args.fd;
+}
+
+int luo_session_preserve_fd(int session_fd, int fd, uint64_t token) {
+        struct liveupdate_session_preserve_fd args = {
+                .size = sizeof(args),
+                .fd = fd,
+                .token = token,
+        };
+
+        assert(session_fd >= 0);
+        assert(fd >= 0);
+
+        return RET_NERRNO(ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, &args));
+}
+
+int luo_session_retrieve_fd(int session_fd, uint64_t token) {
+        struct liveupdate_session_retrieve_fd args = {
+                .size = sizeof(args),
+                .fd = -EBADF,
+                .token = token,
+        };
+        int r;
+
+        assert(session_fd >= 0);
+
+        if (ioctl(session_fd, LIVEUPDATE_SESSION_RETRIEVE_FD, &args) < 0)
+                return -errno;
+
+        r = fd_cloexec(args.fd, true);
+        if (r < 0) {
+                safe_close(args.fd);
+                return r;
+        }
+
+        return args.fd;
+}
+
+int luo_session_finish(int session_fd) {
+        struct liveupdate_session_finish args = {
+                .size = sizeof(args),
+        };
+
+        assert(session_fd >= 0);
+
+        return RET_NERRNO(ioctl(session_fd, LIVEUPDATE_SESSION_FINISH, &args));
+}
diff --git a/src/shared/luo-util.h b/src/shared/luo-util.h
new file mode 100644 (file)
index 0000000..8ff70c1
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "basic-forward.h"
+
+int luo_open_device(void);
+int luo_create_session(int device_fd, const char *name);
+int luo_retrieve_session(int device_fd, const char *name);
+int luo_session_preserve_fd(int session_fd, int fd, uint64_t token);
+int luo_session_retrieve_fd(int session_fd, uint64_t token);
+int luo_session_finish(int session_fd);
index d4cd5ca431233fce5f392da9ecf8ebdc93946a16..9b539f79839d963846606caf47d602f80afcd039 100644 (file)
@@ -129,6 +129,7 @@ shared_sources = files(
         'loop-util.c',
         'loopback-setup.c',
         'lsm-util.c',
+        'luo-util.c',
         'machine-bind-user.c',
         'machine-credential.c',
         'machine-id-setup.c',