Add helpers for talking to /dev/liveupdate

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
This commit is contained in:
Luca Boccassi
2026-05-15 13:46:08 +01:00
parent bc1c56543f
commit 79ac52b810
3 changed files with 117 additions and 0 deletions
+105
View File
@@ -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));
}
+11
View File
@@ -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);
+1
View 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',