]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sysupdate: Compute temporary paths before vacuuming
authorDaan De Meyer <daan@amutable.com>
Thu, 12 Feb 2026 15:17:36 +0000 (16:17 +0100)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 13 Feb 2026 06:46:52 +0000 (15:46 +0900)
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
src/sysupdate/sysupdate-transfer.h
src/sysupdate/sysupdate.c

index 04b1fd09cd880c4d83a7675485cad8947a18c87b..868917b00993cd0fcfdce13e2405fdada9b4561e 100644 (file)
@@ -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.<VERSION>` to `.sysupdate.pending.<VERSION>` 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;
                 }
 
index f5976f0477f32bcffa2e5666eb05ba33c651f9c7..d6dee0234aad8745bf4317fc460096644a747d0d 100644 (file)
@@ -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);
index 9af09b497d8b1bf09d53aa3676df522725e88b10..7693ec373caac3eeedffe6e066322a4ec9dcea56 100644 (file)
@@ -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;
         }