From 7b9600a6b25de5fc63f565a783cc50faf8794194 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 12 Feb 2026 16:17:36 +0100 Subject: [PATCH] sysupdate: Compute temporary paths before vacuuming We don't want to vacuum anything if we're just going to fail just afterwards because a GPT partition label exceeds the maximum size so let's compute the temporary paths for all transfers before we do any vacuuming or acquiring. --- src/sysupdate/sysupdate-transfer.c | 43 +++++++++++++----------------- src/sysupdate/sysupdate-transfer.h | 3 ++- src/sysupdate/sysupdate.c | 19 ++++++++++++- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/sysupdate/sysupdate-transfer.c b/src/sysupdate/sysupdate-transfer.c index 04b1fd09cd8..868917b0099 100644 --- a/src/sysupdate/sysupdate-transfer.c +++ b/src/sysupdate/sysupdate-transfer.c @@ -1171,7 +1171,7 @@ static int run_callout( /* Build the filenames and paths which is normally done by transfer_acquire_instance(), but for partial * and pending instances which are about to be installed (in which case, transfer_acquire_instance() is * skipped). */ -static int transfer_compute_temporary_paths(Transfer *t, Instance *i, InstanceMetadata *f) { +int transfer_compute_temporary_paths(Transfer *t, Instance *i, InstanceMetadata *f) { _cleanup_free_ char *formatted_pattern = NULL, *formatted_partial_pattern = NULL, *formatted_pending_pattern = NULL; int r; @@ -1260,16 +1260,16 @@ static int transfer_compute_temporary_paths(Transfer *t, Instance *i, InstanceMe return 0; } -int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, void *userdata) { +int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, TransferProgress cb, void *userdata) { _cleanup_free_ char *digest = NULL; char offset[DECIMAL_STR_MAX(uint64_t)+1], max_size[DECIMAL_STR_MAX(uint64_t)+1]; const char *where = NULL; - InstanceMetadata f; Instance *existing; int r; assert(t); assert(i); + assert(f); assert(i->resource == &t->source); assert(cb); @@ -1282,11 +1282,6 @@ int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, voi return 0; } - /* Compute up the temporary paths */ - r = transfer_compute_temporary_paths(t, i, &f); - if (r < 0) - return r; - if (RESOURCE_IS_FILESYSTEM(t->target.type)) { r = mkdir_parents(t->temporary_partial_path, 0755); if (r < 0) @@ -1502,10 +1497,10 @@ int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, voi assert(t->temporary_pending_path); /* Apply file attributes if set */ - if (f.mtime != USEC_INFINITY) { + if (f->mtime != USEC_INFINITY) { struct timespec ts; - timespec_store(&ts, f.mtime); + timespec_store(&ts, f->mtime); if (utimensat(AT_FDCWD, t->temporary_partial_path, (struct timespec[2]) { ts, ts }, AT_SYMLINK_NOFOLLOW) < 0) return log_error_errno(errno, "Failed to adjust mtime of '%s': %m", t->temporary_partial_path); @@ -1513,12 +1508,12 @@ int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, voi need_sync = true; } - if (f.mode != MODE_INVALID) { + if (f->mode != MODE_INVALID) { /* Try with AT_SYMLINK_NOFOLLOW first, because it's the safe thing to do. Older * kernels don't support that however, in that case we fall back to chmod(). Not as * safe, but shouldn't be a problem, given that we don't create symlinks here. */ - if (fchmodat(AT_FDCWD, t->temporary_partial_path, f.mode, AT_SYMLINK_NOFOLLOW) < 0 && - (!ERRNO_IS_NOT_SUPPORTED(errno) || chmod(t->temporary_partial_path, f.mode) < 0)) + if (fchmodat(AT_FDCWD, t->temporary_partial_path, f->mode, AT_SYMLINK_NOFOLLOW) < 0 && + (!ERRNO_IS_NOT_SUPPORTED(errno) || chmod(t->temporary_partial_path, f->mode) < 0)) return log_error_errno(errno, "Failed to adjust mode of '%s': %m", t->temporary_partial_path); need_sync = true; @@ -1536,7 +1531,7 @@ int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, voi return log_error_errno(r, "Failed to synchronize file system backing '%s': %m", t->temporary_partial_path); } - t->install_read_only = f.read_only; + t->install_read_only = f->read_only; /* Rename the file from `.sysupdate.partial.` to `.sysupdate.pending.` to indicate it’s ready to install. */ log_debug("Renaming resource instance '%s' to '%s'.", t->temporary_partial_path, t->temporary_pending_path); @@ -1557,28 +1552,28 @@ int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, voi return r; t->partition_change = PARTITION_LABEL; - if (f.partition_uuid_set) { - t->partition_info.uuid = f.partition_uuid; + if (f->partition_uuid_set) { + t->partition_info.uuid = f->partition_uuid; t->partition_change |= PARTITION_UUID; } - if (f.partition_flags_set) { - t->partition_info.flags = f.partition_flags; + if (f->partition_flags_set) { + t->partition_info.flags = f->partition_flags; t->partition_change |= PARTITION_FLAGS; } - if (f.no_auto >= 0) { - t->partition_info.no_auto = f.no_auto; + if (f->no_auto >= 0) { + t->partition_info.no_auto = f->no_auto; t->partition_change |= PARTITION_NO_AUTO; } - if (f.read_only >= 0) { - t->partition_info.read_only = f.read_only; + if (f->read_only >= 0) { + t->partition_info.read_only = f->read_only; t->partition_change |= PARTITION_READ_ONLY; } - if (f.growfs >= 0) { - t->partition_info.growfs = f.growfs; + if (f->growfs >= 0) { + t->partition_info.growfs = f->growfs; t->partition_change |= PARTITION_GROWFS; } diff --git a/src/sysupdate/sysupdate-transfer.h b/src/sysupdate/sysupdate-transfer.h index f5976f0477f..d6dee0234aa 100644 --- a/src/sysupdate/sysupdate-transfer.h +++ b/src/sysupdate/sysupdate-transfer.h @@ -66,7 +66,8 @@ int transfer_resolve_paths(Transfer *t, const char *root, const char *node); int transfer_vacuum(Transfer *t, uint64_t space, const char *extra_protected_version); -int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, void *userdata); +int transfer_compute_temporary_paths(Transfer *t, Instance *i, InstanceMetadata *f); +int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, TransferProgress cb, void *userdata); int transfer_process_partial_and_pending_instance(Transfer *t, Instance *i); int transfer_install_instance(Transfer *t, Instance *i, const char *root); diff --git a/src/sysupdate/sysupdate.c b/src/sysupdate/sysupdate.c index 9af09b497d8..7693ec373ca 100644 --- a/src/sysupdate/sysupdate.c +++ b/src/sysupdate/sysupdate.c @@ -1055,6 +1055,23 @@ static int context_acquire( log_info("Selected update '%s' for install.", us->version); + _cleanup_free_ InstanceMetadata *metadata = new0(InstanceMetadata, c->n_transfers); + if (!metadata) + return log_oom(); + + /* Compute up the temporary paths before vacuuming so we don't vacuum anything if we fail to compute + * any paths because of failed validations (e.g. exceeding the gpt partition label size). */ + for (size_t i = 0; i < c->n_transfers; i++) { + Instance *inst = us->instances[i]; + Transfer *t = c->transfers[i]; + + assert(inst); + + r = transfer_compute_temporary_paths(t, inst, metadata + i); + if (r < 0) + return r; + } + (void) sd_notifyf(/* unset_environment= */ false, "READY=1\n" "X_SYSUPDATE_VERSION=%s\n" @@ -1090,7 +1107,7 @@ static int context_acquire( continue; } - r = transfer_acquire_instance(t, inst, context_on_acquire_progress, c); + r = transfer_acquire_instance(t, inst, metadata + i, context_on_acquire_progress, c); if (r < 0) return r; } -- 2.47.3