install: allow removing symlinks even for units that are gone
authorLuca Boccassi <bluca@debian.org>
Fri, 7 Jun 2024 20:39:45 +0000 (21:39 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 18 Jun 2024 18:41:01 +0000 (20:41 +0200)
If a symlink is leftover, still allow cleaning it up via 'disable'. This
happens when a unit is stopped and removed, but not disabled, and a reload
has already happened. At that point, cleaning up the old symlinks becomes
impossible through the APIs, and needs to be done manually. Always allow
cleaning up symlinks, if they exist, by only erroring out if there is an
OOM.

Follow-up for f31f10a6207efc9ae9e0b1f73975b5b610914017

(cherry picked from commit 5163c9b1e56293b1bb2803420613c5b374570892)

src/shared/install.c
test/units/TEST-26-SYSTEMCTL.sh

index dd2bd5c94847dcb8076501c143b5d263c4b2797b..c94b456c21ee634bf999ff85c6aa6fb4c5d3416b 100644 (file)
@@ -2282,7 +2282,9 @@ static int install_context_mark_for_removal(
                         else {
                                 log_debug_errno(r, "Unit %s not found, removing name.", i->name);
                                 r = install_changes_add(changes, n_changes, r, i->path ?: i->name, NULL);
-                                if (r < 0)
+                                /* In case there's no unit, we still want to remove any leftover symlink, even if
+                                 * the unit might have been removed already, hence treating ENOENT as non-fatal. */
+                                if (r != -ENOENT)
                                         return r;
                         }
                 } else if (r < 0) {
@@ -2874,9 +2876,13 @@ static int do_unit_file_disable(
                 r = install_info_add(&ctx, *name, NULL, lp->root_dir, /* auxiliary= */ false, &info);
                 if (r >= 0)
                         r = install_info_traverse(&ctx, lp, info, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
-
-                if (r < 0)
-                        return install_changes_add(changes, n_changes, r, *name, NULL);
+                if (r < 0) {
+                        r = install_changes_add(changes, n_changes, r, *name, NULL);
+                        /* In case there's no unit, we still want to remove any leftover symlink, even if
+                         * the unit might have been removed already, hence treating ENOENT as non-fatal. */
+                        if (r != -ENOENT)
+                                return r;
+                }
 
                 /* If we enable multiple units, some with install info and others without,
                  * the "empty [Install] section" warning is not shown. Let's make the behavior
index ae7a5d6eb6637b06bb2efef673af0af29e95c522..1471f3fd9e47be72a720d14f03b25041d67a8f9f 100755 (executable)
@@ -343,6 +343,12 @@ systemctl cat "$UNIT_NAME"
 systemctl help "$UNIT_NAME"
 systemctl service-watchdogs
 systemctl service-watchdogs "$(systemctl service-watchdogs)"
+# Ensure that the enablement symlinks can still be removed after the user is gone, to avoid having leftovers
+systemctl enable "$UNIT_NAME"
+systemctl stop "$UNIT_NAME"
+rm -f "/usr/lib/systemd/system/$UNIT_NAME"
+systemctl daemon-reload
+systemctl disable "$UNIT_NAME"
 
 # show/set-environment
 # Make sure PATH is set