bootctl: allow extra files on 'link' be specified as literal data

This commit is contained in:
Lennart Poettering
2026-04-20 13:12:44 +02:00
parent a3f75ace9c
commit ea07d7fec3
2 changed files with 37 additions and 18 deletions

View File

@@ -25,6 +25,7 @@
#include "hashmap.h"
#include "id128-util.h"
#include "io-util.h"
#include "iovec-util.h"
#include "json-util.h"
#include "kernel-image.h"
#include "log.h"
@@ -44,6 +45,7 @@ typedef struct ExtraFile {
/* The source and the temporary file we copy it into */
int source_fd, temp_fd;
char *filename, *temp_filename;
struct iovec data; /* Alternative to 'source_fd': literal data */
} ExtraFile;
#define EXTRA_FILE_NULL \
@@ -115,6 +117,7 @@ static void extra_file_done(ExtraFile *x) {
x->temp_fd = safe_close(x->temp_fd);
x->filename = mfree(x->filename);
x->temp_filename = mfree(x->temp_filename);
iovec_done(&x->data);
}
static void profile_done(Profile *p) {
@@ -366,7 +369,8 @@ static int link_context_pick_entry_token(LinkContext *c) {
}
static int begin_copy_file(
int source_fd,
int source_fd, /* Either the source fd is specified, or the 'data' below, not both */
const struct iovec *data,
const char *filename,
int target_dir_fd,
int *ret_tmpfile_fd,
@@ -374,7 +378,6 @@ static int begin_copy_file(
int r;
assert(source_fd >= 0);
assert(filename);
assert(target_dir_fd >= 0);
assert(ret_tmpfile_fd);
@@ -398,11 +401,18 @@ static int begin_copy_file(
CLEANUP_TMPFILE_AT(target_dir_fd, t);
r = copy_bytes(source_fd, write_fd, UINT64_MAX, COPY_REFLINK|COPY_SEEK0_SOURCE);
if (r < 0)
return log_error_errno(r, "Failed to copy data into '%s': %m", filename);
if (source_fd >= 0) {
r = copy_bytes(source_fd, write_fd, UINT64_MAX, COPY_REFLINK|COPY_SEEK0_SOURCE);
if (r < 0)
return log_error_errno(r, "Failed to copy data into '%s': %m", filename);
(void) copy_times(source_fd, write_fd, /* flags= */ 0);
} else if (iovec_is_set(data)) {
r = loop_write(write_fd, data->iov_base, data->iov_len);
if (r < 0)
return log_error_errno(r, "Failed to write data into '%s': %m", filename);
}
(void) copy_times(source_fd, write_fd, /* flags= */ 0);
(void) fchmod(write_fd, 0644);
*ret_tmpfile_fd = TAKE_FD(write_fd);
@@ -824,6 +834,7 @@ static int run_link_now(LinkContext *c) {
r = begin_copy_file(
c->kernel_fd,
/* data= */ NULL,
c->kernel_filename,
c->entry_token_dir_fd,
&c->kernel_temp_fd,
@@ -834,6 +845,7 @@ static int run_link_now(LinkContext *c) {
FOREACH_ARRAY(x, c->extra, c->n_extra) {
r = begin_copy_file(
x->source_fd,
&x->data,
x->filename,
c->entry_token_dir_fd,
&x->temp_fd,
@@ -1043,7 +1055,8 @@ static int dispatch_extras(const char *name, sd_json_variant *v, sd_json_dispatc
static const sd_json_dispatch_field dispatch_table[] = {
{ "filename", SD_JSON_VARIANT_STRING, json_dispatch_loader_entry_resource_filename, offsetof(ExtraParameters, extra_file.filename), SD_JSON_MANDATORY },
{ "fileDescriptor", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint, offsetof(ExtraParameters, fd_index), SD_JSON_MANDATORY },
{ "fileDescriptor", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint, offsetof(ExtraParameters, fd_index), 0 },
{ "data", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(ExtraParameters, extra_file.data), 0 },
{},
};
@@ -1051,17 +1064,21 @@ static int dispatch_extras(const char *name, sd_json_variant *v, sd_json_dispatc
if (r < 0)
return r;
xp.extra_file.source_fd = sd_varlink_peek_dup_fd(c->link, xp.fd_index);
if (xp.extra_file.source_fd < 0)
return log_debug_errno(xp.extra_file.source_fd, "Failed to acquire extra fd from Varlink: %m");
r = fd_verify_safe_flags(xp.extra_file.source_fd);
if (r < 0)
if (iovec_is_set(&xp.extra_file.data) == (xp.fd_index != UINT_MAX))
return sd_varlink_error_invalid_parameter_name(c->link, name);
if (xp.fd_index != UINT_MAX) {
xp.extra_file.source_fd = sd_varlink_peek_dup_fd(c->link, xp.fd_index);
if (xp.extra_file.source_fd < 0)
return log_debug_errno(xp.extra_file.source_fd, "Failed to acquire extra fd from Varlink: %m");
r = fd_verify_regular(xp.extra_file.source_fd);
if (r < 0)
return log_debug_errno(r, "Failed to validate that the extra file is a regular file descriptor: %m");
r = fd_verify_safe_flags(xp.extra_file.source_fd);
if (r < 0)
return sd_varlink_error_invalid_parameter_name(c->link, name);
r = fd_verify_regular(xp.extra_file.source_fd);
if (r < 0)
return log_debug_errno(r, "Failed to validate that the extra file is a regular file descriptor: %m");
}
if (!GREEDY_REALLOC(c->context.extra, c->context.n_extra+1))
return log_oom();

View File

@@ -153,8 +153,10 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
BootEntryExtraFile,
SD_VARLINK_FIELD_COMMENT("The name of the extra file"),
SD_VARLINK_DEFINE_FIELD(filename, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Index into array of file descriptors, pointing to a file descriptor referencing the extra file."),
SD_VARLINK_DEFINE_FIELD(fileDescriptor, SD_VARLINK_INT, 0));
SD_VARLINK_FIELD_COMMENT("Index into array of file descriptors, pointing to a file descriptor referencing the extra file to copy in. Either this or the 'data' field below must be set not both, not neither."),
SD_VARLINK_DEFINE_FIELD(fileDescriptor, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Literal data to place in the extra file."),
SD_VARLINK_DEFINE_FIELD(data, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD(
Link,