8d419f
From 5aa2be25e7de16f4d3ff3b322cf8c35574e712c5 Mon Sep 17 00:00:00 2001
8d419f
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
8d419f
Date: Wed, 16 Mar 2022 09:51:24 +0100
8d419f
Subject: [PATCH] =?UTF-8?q?shared/install:=20also=20remove=20symlinks=20li?=
8d419f
 =?UTF-8?q?ke=20.wants/foo@one.service=20=E2=86=92=20../foo@one.service?=
8d419f
MIME-Version: 1.0
8d419f
Content-Type: text/plain; charset=UTF-8
8d419f
Content-Transfer-Encoding: 8bit
8d419f
8d419f
So far 'systemctl enable' would create absolute links to the target template
8d419f
name. And we would remove such symlinks just fine. But the user may create
8d419f
symlinks manually in a different form. In particular, symlinks for instanced
8d419f
units *must* have the instance in the source name, and then it is natural to
8d419f
also include it in the target name (.wants/foo@one.service → ../foo@one.service
8d419f
rather than .wants/foo@one.service → ../foo@.service). We would choke on such
8d419f
links, or not remove them at all. A test is added:
8d419f
8d419f
before:
8d419f
8d419f
+ build-rawhide/systemctl --root=/tmp/systemctl-test.001xda disable templ1@.service
8d419f
Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@seven.service".
8d419f
Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@six.service".
8d419f
Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@five.service".
8d419f
Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@four.service".
8d419f
Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@three.service".
8d419f
Failed to disable unit, refusing to operate on linked unit file /tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@two.service.
8d419f
Failed to disable unit, refusing to operate on linked unit file /tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@two.service.
8d419f
8d419f
after:
8d419f
8d419f
+ build-rawhide/systemctl --root=/tmp/systemctl-test.QVP0ev disable templ1@.service
8d419f
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@seven.service".
8d419f
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@six.service".
8d419f
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@five.service".
8d419f
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@four.service".
8d419f
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@three.service".
8d419f
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@two.service".
8d419f
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@one.service".
8d419f
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@one.service
8d419f
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@two.service
8d419f
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@three.service
8d419f
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@four.service
8d419f
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@five.service
8d419f
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@six.service
8d419f
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@seven.service
8d419f
8d419f
(cherry picked from commit 9f61c9f79e0f77044b71ef2ba5edde20e15c6ad2)
8d419f
8d419f
Related: #2082131
8d419f
---
8d419f
 src/shared/install.c          | 16 +++++++++++++---
8d419f
 test/test-systemctl-enable.sh | 20 ++++++++++++++++++++
8d419f
 2 files changed, 33 insertions(+), 3 deletions(-)
8d419f
8d419f
diff --git a/src/shared/install.c b/src/shared/install.c
8d419f
index 08a9892260..43955519ae 100644
8d419f
--- a/src/shared/install.c
8d419f
+++ b/src/shared/install.c
8d419f
@@ -612,13 +612,23 @@ static int remove_marked_symlinks_fd(
8d419f
                         path_simplify(p);
8d419f
 
8d419f
                         /* We remove all links pointing to a file or path that is marked, as well as all
8d419f
-                         * files sharing the same name as a file that is marked. Do path chasing only if
8d419f
-                         * we don't already know that we want to remove the symlink. */
8d419f
+                         * files sharing the same name as a file that is marked, and files sharing the same
8d419f
+                         * name after the instance has been removed. Do path chasing only if we don't already
8d419f
+                         * know that we want to remove the symlink. */
8d419f
                         found = set_contains(remove_symlinks_to, de->d_name);
8d419f
 
8d419f
                         if (!found) {
8d419f
-                                _cleanup_free_ char *dest = NULL;
8d419f
+                                _cleanup_free_ char *template = NULL;
8d419f
+
8d419f
+                                q = unit_name_template(de->d_name, &template);
8d419f
+                                if (q < 0 && q != -EINVAL)
8d419f
+                                        return q;
8d419f
+                                if (q >= 0)
8d419f
+                                        found = set_contains(remove_symlinks_to, template);
8d419f
+                        }
8d419f
 
8d419f
+                        if (!found) {
8d419f
+                                _cleanup_free_ char *dest = NULL;
8d419f
 
8d419f
                                 q = chase_symlinks(p, lp->root_dir, CHASE_NONEXISTENT, &dest, NULL);
8d419f
                                 if (q == -ENOENT)
8d419f
diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh
8d419f
index 220ebfdab7..4462fb386e 100644
8d419f
--- a/test/test-systemctl-enable.sh
8d419f
+++ b/test/test-systemctl-enable.sh
8d419f
@@ -333,6 +333,26 @@ test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.serv
8d419f
 test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service"
8d419f
 test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@two.service"
8d419f
 
8d419f
+: -------removal of relative enablement symlinks--------------
8d419f
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
8d419f
+ln -s '../templ1@one.service' "$root/etc/systemd/system/services.target.wants/templ1@one.service"
8d419f
+ln -s 'templ1@two.service' "$root/etc/systemd/system/services.target.wants/templ1@two.service"
8d419f
+ln -s '../templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@three.service"
8d419f
+ln -s 'templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@four.service"
8d419f
+ln -s '/usr/lib/systemd/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@five.service"
8d419f
+ln -s '/etc/systemd/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@six.service"
8d419f
+ln -s '/run/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@seven.service"
8d419f
+
8d419f
+# this should remove all links
8d419f
+"$systemctl" --root="$root" disable 'templ1@.service'
8d419f
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service"
8d419f
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service"
8d419f
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@three.service"
8d419f
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@four.service"
8d419f
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@five.service"
8d419f
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@six.service"
8d419f
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@seven.service"
8d419f
+
8d419f
 : -------template enablement for another template-------------
8d419f
 cat >"$root/etc/systemd/system/templ2@.service" <
8d419f
 [Install]