diff options
author | Luca Boccassi <bluca@debian.org> | 2024-03-27 22:14:15 +0100 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2024-03-28 03:19:46 +0100 |
commit | ed358516937780b524a2cfa833427da3df1bc87f (patch) | |
tree | 0da580c12f77f32ae511c89201083eeda51c36bb /src/run | |
parent | Merge pull request #31989 from mrc0mmand/test-loop-dev-check (diff) | |
download | systemd-ed358516937780b524a2cfa833427da3df1bc87f.tar.xz systemd-ed358516937780b524a2cfa833427da3df1bc87f.zip |
run: fix generated unit name clash after soft-reboot
When sd-run connects to D-Bus rather than the private socket, it will
generate the transient unit name using the bus ID assigned by the D-Bus
broker/daemon. The issue is that this ID is only unique per D-Bus run,
if the broker/daemon restarts it starts again from 1, and it's a simple
incremental counter for each client.
So if a transient unit run-u6.service starts and fails, and it is not
collected (default on failure), and the system soft-reboots, any new
transient unit might conflict as the counter will restart:
Failed to start transient service unit: Unit run-u6.service was already loaded or has a fragment file.
Get the soft-reboot counter, and if it's greater than zero, append it
to the autogenerated unit name to avoid clashes.
Diffstat (limited to 'src/run')
-rw-r--r-- | src/run/run.c | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/src/run/run.c b/src/run/run.c index 7f40ed0076..9349bfafbc 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -1313,6 +1313,7 @@ static int transient_timer_set_properties(sd_bus_message *m) { } static int make_unit_name(sd_bus *bus, UnitType t, char **ret) { + unsigned soft_reboots_count = 0; const char *unique, *id; char *p; int r; @@ -1351,9 +1352,23 @@ static int make_unit_name(sd_bus *bus, UnitType t, char **ret) { "Unique name %s has unexpected format.", unique); - p = strjoin("run-u", id, ".", unit_type_to_string(t)); - if (!p) - return log_oom(); + /* The unique D-Bus names are actually unique per D-Bus instance, so on soft-reboot they will wrap + * and start over since the D-Bus broker is restarted. If there's a failed unit left behind that + * hasn't been garbage collected, we'll conflict. Append the soft-reboot counter to avoid clashing. */ + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + r = bus_get_property_trivial( + bus, bus_systemd_mgr, "SoftRebootsCount", &error, 'u', &soft_reboots_count); + if (r < 0) + log_debug_errno(r, "Failed to get SoftRebootsCount property, ignoring: %s", bus_error_message(&error, r)); + + if (soft_reboots_count > 0) { + if (asprintf(&p, "run-u%s-s%u.%s", id, soft_reboots_count, unit_type_to_string(t)) < 0) + return log_oom(); + } else { + p = strjoin("run-u", id, ".", unit_type_to_string(t)); + if (!p) + return log_oom(); + } *ret = p; return 0; |