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 <pwithnall@gnome.org> Helps: https://github.com/systemd/systemd/issues/34814
This commit is contained in:
+135
-7
@@ -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++;
|
||||
|
||||
Reference in New Issue
Block a user