]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shared/install: also remove symlinks like .wants/foo@one.service → ../foo@one.service
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 16 Mar 2022 08:51:24 +0000 (09:51 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 29 Mar 2022 14:17:56 +0000 (16:17 +0200)
So far 'systemctl enable' would create absolute links to the target template
name. And we would remove such symlinks just fine. But the user may create
symlinks manually in a different form. In particular, symlinks for instanced
units *must* have the instance in the source name, and then it is natural to
also include it in the target name (.wants/foo@one.service → ../foo@one.service
rather than .wants/foo@one.service → ../foo@.service). We would choke on such
links, or not remove them at all. A test is added:

before:

+ build-rawhide/systemctl --root=/tmp/systemctl-test.001xda disable templ1@.service
Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@seven.service".
Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@six.service".
Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@five.service".
Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@four.service".
Removed "/tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@three.service".
Failed to disable unit, refusing to operate on linked unit file /tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@two.service.
Failed to disable unit, refusing to operate on linked unit file /tmp/systemctl-test.001xda/etc/systemd/system/services.target.wants/templ1@two.service.

after:

+ build-rawhide/systemctl --root=/tmp/systemctl-test.QVP0ev disable templ1@.service
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@seven.service".
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@six.service".
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@five.service".
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@four.service".
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@three.service".
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@two.service".
Removed "/tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@one.service".
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@one.service
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@two.service
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@three.service
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@four.service
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@five.service
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@six.service
+ test '!' -h /tmp/systemctl-test.QVP0ev/etc/systemd/system/services.target.wants/templ1@seven.service

src/shared/install.c
test/test-systemctl-enable.sh

index ea303d85cf3429b4c74cb9c92a3d3d87df51f7ca..3ec3772e01e5e46cd01931f7e989106bf7f39c6e 100644 (file)
@@ -611,13 +611,23 @@ static int remove_marked_symlinks_fd(
                         path_simplify(p);
 
                         /* We remove all links pointing to a file or path that is marked, as well as all
-                         * files sharing the same name as a file that is marked. Do path chasing only if
-                         * we don't already know that we want to remove the symlink. */
+                         * files sharing the same name as a file that is marked, and files sharing the same
+                         * name after the instance has been removed. Do path chasing only if we don't already
+                         * know that we want to remove the symlink. */
                         found = set_contains(remove_symlinks_to, de->d_name);
 
                         if (!found) {
-                                _cleanup_free_ char *dest = NULL;
+                                _cleanup_free_ char *template = NULL;
+
+                                q = unit_name_template(de->d_name, &template);
+                                if (q < 0 && q != -EINVAL)
+                                        return q;
+                                if (q >= 0)
+                                        found = set_contains(remove_symlinks_to, template);
+                        }
 
+                        if (!found) {
+                                _cleanup_free_ char *dest = NULL;
 
                                 q = chase_symlinks(p, lp->root_dir, CHASE_NONEXISTENT, &dest, NULL);
                                 if (q == -ENOENT)
index 220ebfdab75abfb8f7e95547741aed87ab6beee9..4462fb386e0fc2a196f8de8a3f267ad1f4cf46ac 100644 (file)
@@ -333,6 +333,26 @@ test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.serv
 test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service"
 test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@two.service"
 
+: -------removal of relative enablement symlinks--------------
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
+ln -s '../templ1@one.service' "$root/etc/systemd/system/services.target.wants/templ1@one.service"
+ln -s 'templ1@two.service' "$root/etc/systemd/system/services.target.wants/templ1@two.service"
+ln -s '../templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@three.service"
+ln -s 'templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@four.service"
+ln -s '/usr/lib/systemd/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@five.service"
+ln -s '/etc/systemd/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@six.service"
+ln -s '/run/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@seven.service"
+
+# this should remove all links
+"$systemctl" --root="$root" disable 'templ1@.service'
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service"
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service"
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@three.service"
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@four.service"
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@five.service"
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@six.service"
+test ! -h "$root/etc/systemd/system/services.target.wants/templ1@seven.service"
+
 : -------template enablement for another template-------------
 cat >"$root/etc/systemd/system/templ2@.service" <<EOF
 [Install]