From: Philip Withnall Date: Mon, 19 Jan 2026 17:19:39 +0000 (+0000) Subject: updatectl: Use sysupdated’s Acquire() and Install() methods X-Git-Tag: v260-rc1~38^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a5ff474a2bf13a95075519d0193f88537f6e979d;p=thirdparty%2Fsystemd.git updatectl: Use sysupdated’s Acquire() and Install() methods Rather than calling `Update()`. This should allow us to eventually drop `Update()`. This should just be an internal change, and should not result in any user-visible changes to the behaviour of `updatectl update`. Signed-off-by: Philip Withnall Helps: https://github.com/systemd/systemd/issues/34814 --- diff --git a/src/sysupdate/updatectl.c b/src/sysupdate/updatectl.c index 5eae86e4ea4..7638bbff795 100644 --- a/src/sysupdate/updatectl.c +++ b/src/sysupdate/updatectl.c @@ -72,6 +72,9 @@ typedef struct Operation { sd_event_source *job_interrupt_source; sd_bus_slot *job_properties_slot; sd_bus_slot *job_finished_slot; + + /* Only used for Acquire()/Install() operations: */ + char *acquired_version; } Operation; static Operation* operation_free(Operation *p) { @@ -86,6 +89,7 @@ static Operation* operation_free(Operation *p) { assert_se(sd_event_exit(p->event, 0) >= 0); free(p->job_path); + free(p->acquired_version); sd_event_source_disable_unref(p->job_interrupt_source); sd_bus_slot_unref(p->job_properties_slot); @@ -804,6 +808,7 @@ static int verb_check(int argc, char **argv, void *userdata) { } #define UPDATE_PROGRESS_FAILED INT_MIN +#define UPDATE_PROGRESS_ACQUIRED (INT_MAX - 1) #define UPDATE_PROGRESS_DONE INT_MAX /* Make sure it doesn't overlap w/ errno values */ assert_cc(UPDATE_PROGRESS_FAILED < -ERRNO_MAX); @@ -853,6 +858,10 @@ static int update_render_progress(sd_event_source *source, void *userdata) { clear_progress_bar_unbuffered(target); fprintf(stderr, "%s: %s %s\n", target, RED_CROSS_MARK(), STRERROR(progress)); total += 100; + } else if (progress == UPDATE_PROGRESS_ACQUIRED) { + clear_progress_bar_unbuffered(target); + fprintf(stderr, "%s: %s Installing\n", target, glyph(GLYPH_DOWNLOAD)); + total += 100; } else if (progress == UPDATE_PROGRESS_DONE) { clear_progress_bar_unbuffered(target); fprintf(stderr, "%s: %s Done\n", target, GREEN_CHECK_MARK()); @@ -920,7 +929,60 @@ static int update_properties_changed(sd_bus_message *m, void *userdata, sd_bus_e return 0; } -static int update_finished(sd_bus_message *m, void *userdata, sd_bus_error *error) { +static int update_install_started(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) { + _cleanup_(operation_freep) Operation *op = ASSERT_PTR(userdata); + OrderedHashmap *map = ASSERT_PTR(op->userdata); + const sd_bus_error *e; + const char *job_path; + int r; + + assert(reply); + + e = sd_bus_message_get_error(reply); + if (e) { + r = -sd_bus_error_get_errno(e); + + r = ordered_hashmap_replace(map, op->target_id, INT_TO_PTR(r)); + if (r < 0) + log_debug_errno(r, "Failed to update hashmap: %m"); + + return 0; + } + + r = sd_bus_message_read(reply, "sto", NULL, &op->job_id, &job_path); + if (r < 0) + return bus_log_parse_error(r); + r = free_and_strdup_warn(&op->job_path, job_path); + if (r < 0) + return r; + + /* Update this job in the hashmap. */ + r = ordered_hashmap_replace(map, op->target_id, INT_TO_PTR(UPDATE_PROGRESS_ACQUIRED)); + if (r < 0) + log_debug_errno(r, "Failed to update hashmap: %m"); + + /* Register for progress notifications for this Install() D-Bus call; previously + * op->job_properties_slot was registered for progress notifications for the Acquire() D-Bus call. */ + sd_bus_slot_unref(TAKE_PTR(op->job_properties_slot)); + r = sd_bus_match_signal_async( + op->bus, + &op->job_properties_slot, + bus_sysupdate_mgr->destination, + job_path, + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + update_properties_changed, + NULL, + op); + if (r < 0) + return log_bus_error(r, NULL, op->target_id, "listen for PropertiesChanged"); + + TAKE_PTR(op); /* update_install_finished/update_interrupted take ownership of the data */ + + return 0; +} + +static int update_install_finished(sd_bus_message *m, void *userdata, sd_bus_error *error) { _cleanup_(operation_freep) Operation *op = ASSERT_PTR(userdata); OrderedHashmap *map = ASSERT_PTR(op->userdata); uint64_t id; @@ -951,6 +1013,64 @@ static int update_finished(sd_bus_message *m, void *userdata, sd_bus_error *erro return 0; } +static int update_acquire_finished(sd_bus_message *m, void *userdata, sd_bus_error *error) { + _cleanup_(operation_freep) Operation *op = ASSERT_PTR(userdata); + OrderedHashmap *map = ASSERT_PTR(op->userdata); + uint64_t id; + int r, status; + + assert(m); + + r = sd_bus_message_read(m, "toi", &id, NULL, &status); + if (r < 0) { + bus_log_parse_error_debug(r); + return 0; + } + + if (id != op->job_id) { + TAKE_PTR(op); + return 0; + } + + if (status == 0) /* success */ + status = UPDATE_PROGRESS_ACQUIRED; + else if (status > 0) /* exit status without errno */ + status = UPDATE_PROGRESS_FAILED; /* i.e. EXIT_FAILURE */ + /* else errno */ + + r = ordered_hashmap_replace(map, op->target_id, INT_TO_PTR(status)); + if (r < 0) + log_debug_errno(r, "Failed to update hashmap: %m"); + + /* Renew the JobRemoved notification for the Install() call instead. */ + sd_bus_slot_unref(op->job_finished_slot); + r = bus_match_signal_async( + op->bus, &op->job_finished_slot, bus_sysupdate_mgr, "JobRemoved", update_install_finished, NULL, op); + if (r < 0) + return log_bus_error(r, NULL, op->target_id, "listen for JobRemoved"); + + /* With the Acquire() call finished, immediately call Install() to deploy the downloaded update. + * This reuses the same Operation struct so the progress reporting continues to be done in the same + * slot in the terminal. */ + r = sd_bus_call_method_async( + op->bus, + NULL, + bus_sysupdate_mgr->destination, + op->target_path, + SYSUPDATE_TARGET_INTERFACE, + "Install", + update_install_started, + op, + "st", + op->acquired_version, + 0LU); + if (r < 0) + return log_bus_error(r, NULL, op->target_id, "call Install"); + TAKE_PTR(op); + + return 0; +} + static int update_interrupted(sd_event_source *source, void *userdata) { /* Since the event loop is exiting, we will never receive the JobRemoved * signal. So, we must free the userdata here. */ @@ -959,6 +1079,8 @@ static int update_interrupted(sd_event_source *source, void *userdata) { OrderedHashmap *map = ASSERT_PTR(op->userdata); int r; + /* This call should work regardless of whether we’re cancelling the Acquire() call or the Install() + * call. */ r = sd_bus_call_method(op->bus, bus_sysupdate_mgr->destination, op->job_path, @@ -977,7 +1099,7 @@ static int update_interrupted(sd_event_source *source, void *userdata) { return 0; } -static int update_started(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) { +static int update_acquire_started(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) { _cleanup_(operation_freep) Operation *op = ASSERT_PTR(userdata); OrderedHashmap *map = ASSERT_PTR(op->userdata); const sd_bus_error *e; @@ -1008,6 +1130,12 @@ static int update_started(sd_bus_message *reply, void *userdata, sd_bus_error *r op->job_path = strdup(job_path); if (!op->job_path) return log_oom(); + + /* Store the version for the subsequent Install() call */ + op->acquired_version = strdup(new_version); + if (!op->acquired_version) + return log_oom(); + if (isempty(new_version)) new_version = "latest"; @@ -1047,7 +1175,7 @@ static int update_started(sd_bus_message *reply, void *userdata, sd_bus_error *r if (r < 0) return log_bus_error(r, NULL, op->target_id, "listen for PropertiesChanged"); - TAKE_PTR(op); /* update_finished/update_interrupted take ownership of the data */ + TAKE_PTR(op); /* update_acquire_finished/update_interrupted take ownership of the data */ return 0; } @@ -1094,7 +1222,7 @@ static int do_update(sd_bus *bus, char **targets) { /* Sign up for notification when the associated job finishes */ r = bus_match_signal_async( - op->bus, &op->job_finished_slot, bus_sysupdate_mgr, "JobRemoved", update_finished, NULL, op); + op->bus, &op->job_finished_slot, bus_sysupdate_mgr, "JobRemoved", update_acquire_finished, NULL, op); if (r < 0) return log_bus_error(r, NULL, op->target_id, "listen for JobRemoved"); @@ -1104,14 +1232,14 @@ static int do_update(sd_bus *bus, char **targets) { bus_sysupdate_mgr->destination, target_paths[i], SYSUPDATE_TARGET_INTERFACE, - "Update", - update_started, + "Acquire", + update_acquire_started, op, "st", versions[i], 0LU); if (r < 0) - return log_bus_error(r, NULL, targets[i], "call Update"); + return log_bus_error(r, NULL, targets[i], "call Acquire"); TAKE_PTR(op); remaining++;