naccyde / rpms / systemd

Forked from rpms/systemd 11 months ago
Clone
594167
From a7e70c5699a663cf14e9358648698667bd320db7 Mon Sep 17 00:00:00 2001
594167
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
594167
Date: Wed, 16 Mar 2022 10:17:32 +0100
594167
Subject: [PATCH] shared/install: create relative symlinks for enablement and
594167
 aliasing
594167
MIME-Version: 1.0
594167
Content-Type: text/plain; charset=UTF-8
594167
Content-Transfer-Encoding: 8bit
594167
594167
This is a fairly noticable change, but I think it needs to be done.
594167
So far we'd create an absolute symlink to the target unit file:
594167
  .wants/foo.service → /usr/lib/systemd/system/foo.service
594167
or
594167
  alias.service → /etc/systemd/system/aliased.service.
594167
594167
This works reasonably well, except in one case: where the unit file
594167
is linked. When we look at a file link, the name of the physical file
594167
isn't used, and we only take the account the symlink source name.
594167
(In fact, the destination filename may not even be a well-formed unit name,
594167
so we couldn't use it, even if we wanted to.) But this means that if
594167
a file is linked, and specifies aliases, we'd create absolute links for
594167
those aliases, and systemd would consider each "alias" to be a separate
594167
unit. This isn't checked by the tests here, because we don't have a running
594167
systemd instance, but it is easy enough to check manually.
594167
594167
The most reasonable way to fix this is to create relative links to the
594167
unit file:
594167
  .wants/foo.service → ../foo.service
594167
  alias.service → aliased.service.
594167
594167
I opted to use no prefix for aliases, both normal and 'default.target',
594167
and to add "../" for .wants/ and .requires/. Note that the link that is
594167
created doesn't necessarily point to the file. E.g. if we're enabling
594167
a file under /usr/lib/systemd/system, and create a symlink in /etc/systemd/system,
594167
it'll still be "../foo.service", not "../../usr/lib/systemd/system/foo.service".
594167
For our unit loading logic this doesn't matter, and figuring out a path
594167
that actually leads somewhere would be more work. Since the user is allowed
594167
to move the unit file, or add a new unit file in a different location, and
594167
we don't actually follow the symlink, I think it's OK to create a dangling
594167
symlink. The prefix of "../" is useful to give a hint that the link points
594167
to files that are conceptually "one level up" in the directory hierarchy.
594167
594167
With the relative symlinks, systemd knows that those are aliases.
594167
594167
The tests are adjusted to use the new forms. There were a few tests that
594167
weren't really testing something useful: 'test -e x' fails if 'x' is a
594167
a dangling symlink. Absolute links in the chroot would be dangling, even
594167
though the target existed in the expected path, but become non-dangling
594167
when made relative and the test fails.
594167
594167
This should be described in NEWS, but I'm not adding that here, because
594167
it'd likely result in conflicts.
594167
594167
(cherry picked from commit d6c9411072901556176ac130f2ce71a33107aa93)
594167
594167
Related: #2082131
594167
---
594167
 src/shared/install.c          |  14 ++--
594167
 src/test/test-install-root.c  |  65 +++++++++--------
594167
 test/test-systemctl-enable.sh | 128 ++++++++++++++++------------------
594167
 3 files changed, 105 insertions(+), 102 deletions(-)
594167
594167
diff --git a/src/shared/install.c b/src/shared/install.c
594167
index 43955519ae..1a2b0ccf24 100644
594167
--- a/src/shared/install.c
594167
+++ b/src/shared/install.c
594167
@@ -1842,7 +1842,7 @@ static int install_info_symlink_alias(
594167
                 if (!alias_path)
594167
                         return -ENOMEM;
594167
 
594167
-                q = create_symlink(lp, info->path, alias_path, force, changes, n_changes);
594167
+                q = create_symlink(lp, info->name, alias_path, force, changes, n_changes);
594167
                 r = r < 0 ? r : q;
594167
         }
594167
 
594167
@@ -1911,7 +1911,7 @@ static int install_info_symlink_wants(
594167
         }
594167
 
594167
         STRV_FOREACH(s, list) {
594167
-                _cleanup_free_ char *path = NULL, *dst = NULL;
594167
+                _cleanup_free_ char *dst = NULL;
594167
 
594167
                 q = install_name_printf(scope, info, *s, info->root, &dst);
594167
                 if (q < 0) {
594167
@@ -1941,11 +1941,15 @@ static int install_info_symlink_wants(
594167
                         continue;
594167
                 }
594167
 
594167
-                path = strjoin(config_path, "/", dst, suffix, n);
594167
+                _cleanup_free_ char *path = strjoin(config_path, "/", dst, suffix, n);
594167
                 if (!path)
594167
                         return -ENOMEM;
594167
 
594167
-                q = create_symlink(lp, info->path, path, true, changes, n_changes);
594167
+                _cleanup_free_ char *target = strjoin("../", info->name);
594167
+                if (!target)
594167
+                        return -ENOMEM;
594167
+
594167
+                q = create_symlink(lp, target, path, true, changes, n_changes);
594167
                 if (r == 0)
594167
                         r = q;
594167
 
594167
@@ -2853,7 +2857,7 @@ int unit_file_set_default(
594167
                 return r;
594167
 
594167
         new_path = strjoina(lp.persistent_config, "/" SPECIAL_DEFAULT_TARGET);
594167
-        return create_symlink(&lp, info->path, new_path, flags & UNIT_FILE_FORCE, changes, n_changes);
594167
+        return create_symlink(&lp, info->name, new_path, flags & UNIT_FILE_FORCE, changes, n_changes);
594167
 }
594167
 
594167
 int unit_file_get_default(
594167
diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c
594167
index 4f66c12655..dca695d124 100644
594167
--- a/src/test/test-install-root.c
594167
+++ b/src/test/test-install-root.c
594167
@@ -88,7 +88,7 @@ TEST(basic_mask_and_enable) {
594167
         assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == 1);
594167
         assert_se(n_changes == 1);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service"));
594167
+        assert_se(streq(changes[0].source, "../a.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         unit_file_changes_free(changes, n_changes);
594167
@@ -128,7 +128,7 @@ TEST(basic_mask_and_enable) {
594167
         assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("d.service"), &changes, &n_changes) >= 0);
594167
         assert_se(n_changes == 1);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service"));
594167
+        assert_se(streq(changes[0].source, "../a.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         unit_file_changes_free(changes, n_changes);
594167
@@ -147,7 +147,7 @@ TEST(basic_mask_and_enable) {
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[1].source, "/usr/lib/systemd/system/a.service"));
594167
+        assert_se(streq(changes[1].source, "../a.service"));
594167
         assert_se(streq(changes[1].path, p));
594167
         unit_file_changes_free(changes, n_changes);
594167
         changes = NULL; n_changes = 0;
594167
@@ -186,7 +186,7 @@ TEST(basic_mask_and_enable) {
594167
         assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("f.service"), &changes, &n_changes) == 1);
594167
         assert_se(n_changes == 2);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/f.service"));
594167
+        assert_se(streq(changes[0].source, "../f.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/x.target.wants/f.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         assert_se(changes[1].type_or_errno == UNIT_FILE_DESTINATION_NOT_PRESENT);
594167
@@ -280,7 +280,8 @@ TEST(linked_units) {
594167
         q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service");
594167
         for (i = 0 ; i < n_changes; i++) {
594167
                 assert_se(changes[i].type_or_errno == UNIT_FILE_SYMLINK);
594167
-                assert_se(streq(changes[i].source, "/opt/linked.service"));
594167
+                assert_se(STR_IN_SET(changes[i].source,
594167
+                                     "../linked.service", "/opt/linked.service"));
594167
 
594167
                 if (p && streq(changes[i].path, p))
594167
                         p = NULL;
594167
@@ -322,7 +323,8 @@ TEST(linked_units) {
594167
         q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked2.service");
594167
         for (i = 0 ; i < n_changes; i++) {
594167
                 assert_se(changes[i].type_or_errno == UNIT_FILE_SYMLINK);
594167
-                assert_se(streq(changes[i].source, "/opt/linked2.service"));
594167
+                assert_se(STR_IN_SET(changes[i].source,
594167
+                                     "../linked2.service", "/opt/linked2.service"));
594167
 
594167
                 if (p && streq(changes[i].path, p))
594167
                         p = NULL;
594167
@@ -340,7 +342,7 @@ TEST(linked_units) {
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
         assert_se(startswith(changes[0].path, root));
594167
         assert_se(endswith(changes[0].path, "linked3.service"));
594167
-        assert_se(streq(changes[0].source, "/opt/linked3.service"));
594167
+        assert_se(streq(changes[0].source, "../linked3.service"));
594167
         unit_file_changes_free(changes, n_changes);
594167
         changes = NULL; n_changes = 0;
594167
 }
594167
@@ -371,7 +373,7 @@ TEST(default) {
594167
         assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "test-default.target", &changes, &n_changes) >= 0);
594167
         assert_se(n_changes == 1);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/test-default-real.target"));
594167
+        assert_se(streq(changes[0].source, "test-default-real.target"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR "/" SPECIAL_DEFAULT_TARGET);
594167
         assert_se(streq(changes[0].path, p));
594167
         unit_file_changes_free(changes, n_changes);
594167
@@ -401,7 +403,7 @@ TEST(add_dependency) {
594167
         assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, &changes, &n_changes) >= 0);
594167
         assert_se(n_changes == 1);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/real-add-dependency-test-service.service"));
594167
+        assert_se(streq(changes[0].source, "../real-add-dependency-test-service.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         unit_file_changes_free(changes, n_changes);
594167
@@ -442,7 +444,7 @@ TEST(template_enable) {
594167
         assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0);
594167
         assert_se(n_changes == 1);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
594167
+        assert_se(streq(changes[0].source, "../template@.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@def.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         unit_file_changes_free(changes, n_changes);
594167
@@ -473,13 +475,14 @@ TEST(template_enable) {
594167
 
594167
         assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
594167
+        assert_se(streq(changes[0].source, "../template@foo.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@foo.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         unit_file_changes_free(changes, n_changes);
594167
         changes = NULL; n_changes = 0;
594167
 
594167
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
594167
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0);
594167
+        assert_se(state == UNIT_FILE_INDIRECT);
594167
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
594167
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
594167
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
594167
@@ -506,7 +509,7 @@ TEST(template_enable) {
594167
 
594167
         assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template-symlink@quux.service"), &changes, &n_changes) >= 0);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
594167
+        assert_se(streq(changes[0].source, "../template@quux.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@quux.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         unit_file_changes_free(changes, n_changes);
594167
@@ -552,7 +555,7 @@ TEST(indirect) {
594167
         assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0);
594167
         assert_se(n_changes == 1);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/indirectb.service"));
594167
+        assert_se(streq(changes[0].source, "../indirectb.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/indirectb.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         unit_file_changes_free(changes, n_changes);
594167
@@ -604,7 +607,7 @@ TEST(preset_and_list) {
594167
         assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0);
594167
         assert_se(n_changes == 1);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/preset-yes.service"));
594167
+        assert_se(streq(changes[0].source, "../preset-yes.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/preset-yes.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         unit_file_changes_free(changes, n_changes);
594167
@@ -641,7 +644,7 @@ TEST(preset_and_list) {
594167
         for (i = 0; i < n_changes; i++) {
594167
 
594167
                 if (changes[i].type_or_errno == UNIT_FILE_SYMLINK) {
594167
-                        assert_se(streq(changes[i].source, "/usr/lib/systemd/system/preset-yes.service"));
594167
+                        assert_se(streq(changes[i].source, "../preset-yes.service"));
594167
                         assert_se(streq(changes[i].path, p));
594167
                 } else
594167
                         assert_se(changes[i].type_or_errno == UNIT_FILE_UNLINK);
594167
@@ -757,7 +760,7 @@ TEST(preset_order) {
594167
         assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0);
594167
         assert_se(n_changes == 1);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/prefix-1.service"));
594167
+        assert_se(streq(changes[0].source, "../prefix-1.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/prefix-1.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         unit_file_changes_free(changes, n_changes);
594167
@@ -866,8 +869,8 @@ TEST(with_dropin) {
594167
         assert_se(n_changes == 2);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
         assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-1.service"));
594167
-        assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-1.service"));
594167
+        assert_se(streq(changes[0].source, "../with-dropin-1.service"));
594167
+        assert_se(streq(changes[1].source, "../with-dropin-1.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-1.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/graphical.target.wants/with-dropin-1.service");
594167
@@ -880,8 +883,8 @@ TEST(with_dropin) {
594167
         assert_se(n_changes == 2);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
         assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, SYSTEM_CONFIG_UNIT_DIR"/with-dropin-2.service"));
594167
-        assert_se(streq(changes[1].source, SYSTEM_CONFIG_UNIT_DIR"/with-dropin-2.service"));
594167
+        assert_se(streq(changes[0].source, "../with-dropin-2.service"));
594167
+        assert_se(streq(changes[1].source, "../with-dropin-2.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-2.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/graphical.target.wants/with-dropin-2.service");
594167
@@ -894,8 +897,8 @@ TEST(with_dropin) {
594167
         assert_se(n_changes == 2);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
         assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-3.service"));
594167
-        assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-3.service"));
594167
+        assert_se(streq(changes[0].source, "../with-dropin-3.service"));
594167
+        assert_se(streq(changes[1].source, "../with-dropin-3.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-3.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/graphical.target.wants/with-dropin-3.service");
594167
@@ -908,8 +911,8 @@ TEST(with_dropin) {
594167
         assert_se(n_changes == 2);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
         assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-4a.service"));
594167
-        assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-4b.service"));
594167
+        assert_se(streq(changes[0].source, "../with-dropin-4a.service"));
594167
+        assert_se(streq(changes[1].source, "../with-dropin-4b.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-4a.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-4b.service");
594167
@@ -975,8 +978,8 @@ TEST(with_dropin_template) {
594167
         assert_se(n_changes == 2);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
         assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-1@.service"));
594167
-        assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-1@.service"));
594167
+        assert_se(streq(changes[0].source, "../with-dropin-1@instance-1.service"));
594167
+        assert_se(streq(changes[1].source, "../with-dropin-1@instance-1.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-1@instance-1.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/graphical.target.wants/with-dropin-1@instance-1.service");
594167
@@ -988,8 +991,8 @@ TEST(with_dropin_template) {
594167
         assert_se(n_changes == 2);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
         assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-2@.service"));
594167
-        assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-2@.service"));
594167
+        assert_se(streq(changes[0].source, "../with-dropin-2@instance-1.service"));
594167
+        assert_se(streq(changes[1].source, "../with-dropin-2@instance-1.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-2@instance-1.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/graphical.target.wants/with-dropin-2@instance-1.service");
594167
@@ -1000,7 +1003,7 @@ TEST(with_dropin_template) {
594167
         assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2@instance-2.service"), &changes, &n_changes) == 1);
594167
         assert_se(n_changes == 1);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-2@.service"));
594167
+        assert_se(streq(changes[0].source, "../with-dropin-2@instance-2.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-2@instance-2.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         unit_file_changes_free(changes, n_changes);
594167
@@ -1009,7 +1012,7 @@ TEST(with_dropin_template) {
594167
         assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-3@.service"), &changes, &n_changes) == 1);
594167
         assert_se(n_changes == 1);
594167
         assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK);
594167
-        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-3@.service"));
594167
+        assert_se(streq(changes[0].source, "../with-dropin-3@.service"));
594167
         p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-3@instance-2.service");
594167
         assert_se(streq(changes[0].path, p));
594167
         unit_file_changes_free(changes, n_changes);
594167
diff --git a/test/test-systemctl-enable.sh b/test/test-systemctl-enable.sh
594167
index 4462fb386e..9463433c5b 100644
594167
--- a/test/test-systemctl-enable.sh
594167
+++ b/test/test-systemctl-enable.sh
594167
@@ -68,27 +68,27 @@ EOF
594167
 "$systemctl" --root="$root" enable test1 && { echo "Expected failure" >&2; exit 1; }
594167
 test -h "$root/etc/systemd/system/default.target.wants/test1.service"
594167
 test -h "$root/etc/systemd/system/special.target.requires/test1.service"
594167
-test ! -e "$root/etc/systemd/system/test1-goodalias.service"
594167
+test -e "$root/etc/systemd/system/test1-goodalias.service"
594167
 test -h "$root/etc/systemd/system/test1-goodalias.service"
594167
-test ! -e "$root/etc/systemd/system/test1@badalias.service"
594167
-test ! -e "$root/etc/systemd/system/test1-badalias.target"
594167
-test ! -e "$root/etc/systemd/system/test1-badalias.socket"
594167
+test ! -h "$root/etc/systemd/system/test1@badalias.service"
594167
+test ! -h "$root/etc/systemd/system/test1-badalias.target"
594167
+test ! -h "$root/etc/systemd/system/test1-badalias.socket"
594167
+test -e "$root/etc/systemd/system/test1-goodalias2.service"
594167
 test -h "$root/etc/systemd/system/test1-goodalias2.service"
594167
 
594167
 : -------aliases in reeanble----------------------------------
594167
 "$systemctl" --root="$root" reenable test1 && { echo "Expected failure" >&2; exit 1; }
594167
-test -h "$root/etc/systemd/system/default.target.wants/test1.service"
594167
-test ! -e "$root/etc/systemd/system/test1-goodalias.service"
594167
-test -h "$root/etc/systemd/system/test1-goodalias.service"
594167
+islink "$root/etc/systemd/system/default.target.wants/test1.service" "../test1.service"
594167
+islink "$root/etc/systemd/system/test1-goodalias.service" "test1.service"
594167
 
594167
-test ! -e "$root/etc/systemd/system/test1@badalias.service"
594167
-test ! -e "$root/etc/systemd/system/test1-badalias.target"
594167
-test ! -e "$root/etc/systemd/system/test1-badalias.socket"
594167
+test ! -h "$root/etc/systemd/system/test1@badalias.service"
594167
+test ! -h "$root/etc/systemd/system/test1-badalias.target"
594167
+test ! -h "$root/etc/systemd/system/test1-badalias.socket"
594167
 
594167
 "$systemctl" --root="$root" disable test1
594167
-test ! -e "$root/etc/systemd/system/default.target.wants/test1.service"
594167
-test ! -e "$root/etc/systemd/system/special.target.requires/test1.service"
594167
-test ! -e "$root/etc/systemd/system/test1-goodalias.service"
594167
+test ! -h "$root/etc/systemd/system/default.target.wants/test1.service"
594167
+test ! -h "$root/etc/systemd/system/special.target.requires/test1.service"
594167
+test ! -h "$root/etc/systemd/system/test1-goodalias.service"
594167
 
594167
 : -------also units-------------------------------------------
594167
 cat >"$root/etc/systemd/system/test2.socket" <
594167
@@ -165,17 +165,17 @@ test ! -e "$root/etc/systemd/system/link1.path"
594167
 : -------link and enable--------------------------------------
594167
 "$systemctl" --root="$root" enable '/link1.path'
594167
 islink "$root/etc/systemd/system/link1.path" "/link1.path"
594167
-islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path"
594167
+islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path"
594167
 
594167
 : -------enable already linked same path----------------------
594167
 "$systemctl" --root="$root" enable '/link1.path'
594167
 islink "$root/etc/systemd/system/link1.path" "/link1.path"
594167
-islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path"
594167
+islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path"
594167
 
594167
 : -------enable already linked different path-----------------
594167
 "$systemctl" --root="$root" enable '/subdir/link1.path' && { echo "Expected failure" >&2; exit 1; }
594167
 islink "$root/etc/systemd/system/link1.path" "/link1.path"
594167
-islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path"
594167
+islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path"
594167
 
594167
 : -------enable bad suffix------------------------------------
594167
 cp "$root/link1.path" "$root/subdir/link1.suffix"
594167
@@ -204,11 +204,11 @@ test ! -h "$root/etc/systemd/system/paths.target.wants/link1.path"
594167
 
594167
 "$systemctl" --root="$root" enable 'link1.path'
594167
 islink "$root/etc/systemd/system/link1.path" "/link1.path"
594167
-islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path"
594167
+islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path"
594167
 
594167
 "$systemctl" --root="$root" reenable 'link1.path'
594167
 islink "$root/etc/systemd/system/link1.path" "/link1.path"
594167
-islink "$root/etc/systemd/system/paths.target.wants/link1.path" "/link1.path"
594167
+islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path"
594167
 
594167
 : -------manual link------------------------------------------
594167
 cat >"$root/link3.suffix" <
594167
@@ -253,7 +253,7 @@ test ! -h "$root/etc/systemd/system/services.target.wants/link5-also.service"
594167
 
594167
 "$systemctl" --root="$root" enable 'link5-also.service'
594167
 test ! -h "$root/etc/systemd/system/services.target.wants/link5.service"
594167
-islink "$root/etc/systemd/system/services.target.wants/link5-also.service" "/etc/systemd/system/link5-also.service"
594167
+islink "$root/etc/systemd/system/services.target.wants/link5-also.service" "../link5-also.service"
594167
 
594167
 : -------template enablement----------------------------------
594167
 cat >"$root/etc/systemd/system/templ1@.service" <
594167
@@ -267,17 +267,17 @@ test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
594167
 
594167
 "$systemctl" --root="$root" enable 'templ1@one.service'
594167
 test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
594167
-islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "/etc/systemd/system/templ1@.service"
594167
+islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "../templ1@one.service"
594167
 
594167
 "$systemctl" --root="$root" enable 'templ1@two.service'
594167
 test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
594167
-islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "/etc/systemd/system/templ1@.service"
594167
-islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "/etc/systemd/system/templ1@.service"
594167
+islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "../templ1@one.service"
594167
+islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "../templ1@two.service"
594167
 
594167
 "$systemctl" --root="$root" disable 'templ1@one.service'
594167
 test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
594167
 test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service"
594167
-islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "/etc/systemd/system/templ1@.service"
594167
+islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "../templ1@two.service"
594167
 
594167
 "$systemctl" --root="$root" disable 'templ1@two.service'
594167
 test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
594167
@@ -295,33 +295,33 @@ EOF
594167
 
594167
 "$systemctl" --root="$root" enable 'templ1@.service'
594167
 test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
594167
-islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "/etc/systemd/system/templ1@.service"
594167
-islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "/etc/systemd/system/templ1@.service"
594167
+islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "../templ1@.service"
594167
+islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "../templ1@.service"
594167
 
594167
 "$systemctl" --root="$root" enable 'templ1@one.service'
594167
 test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
594167
-islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "/etc/systemd/system/templ1@.service"
594167
-islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "/etc/systemd/system/templ1@.service"
594167
-islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "/etc/systemd/system/templ1@.service"
594167
-islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.service" "/etc/systemd/system/templ1@.service"
594167
+islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "../templ1@.service"
594167
+islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "../templ1@.service"
594167
+islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "../templ1@one.service"
594167
+islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.service" "../templ1@one.service"
594167
 
594167
 "$systemctl" --root="$root" enable 'templ1@two.service'
594167
 test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
594167
-islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "/etc/systemd/system/templ1@.service"
594167
-islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "/etc/systemd/system/templ1@.service"
594167
-islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "/etc/systemd/system/templ1@.service"
594167
-islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.service" "/etc/systemd/system/templ1@.service"
594167
-islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "/etc/systemd/system/templ1@.service"
594167
-islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@two.service" "/etc/systemd/system/templ1@.service"
594167
+islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "../templ1@.service"
594167
+islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "../templ1@.service"
594167
+islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "../templ1@one.service"
594167
+islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.service" "../templ1@one.service"
594167
+islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "../templ1@two.service"
594167
+islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@two.service" "../templ1@two.service"
594167
 
594167
 "$systemctl" --root="$root" disable 'templ1@one.service'
594167
 test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
594167
-islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "/etc/systemd/system/templ1@.service"
594167
-islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "/etc/systemd/system/templ1@.service"
594167
+islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "../templ1@.service"
594167
+islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "../templ1@.service"
594167
 test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service"
594167
 test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.service"
594167
-islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "/etc/systemd/system/templ1@.service"
594167
-islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@two.service" "/etc/systemd/system/templ1@.service"
594167
+islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "../templ1@two.service"
594167
+islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@two.service" "../templ1@two.service"
594167
 
594167
 # disable remaining links here
594167
 "$systemctl" --root="$root" disable 'templ1@.service'
594167
@@ -360,18 +360,18 @@ RequiredBy=another-template@.target
594167
 EOF
594167
 
594167
 "$systemctl" --root="$root" enable 'templ2@.service'
594167
-islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "/etc/systemd/system/templ2@.service"
594167
+islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "../templ2@.service"
594167
 
594167
 "$systemctl" --root="$root" enable 'templ2@two.service'
594167
-islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "/etc/systemd/system/templ2@.service"
594167
-islink "$root/etc/systemd/system/another-template@.target.requires/templ2@two.service" "/etc/systemd/system/templ2@.service"
594167
+islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "../templ2@.service"
594167
+islink "$root/etc/systemd/system/another-template@.target.requires/templ2@two.service" "../templ2@two.service"
594167
 
594167
 "$systemctl" --root="$root" disable 'templ2@other.service'
594167
-islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "/etc/systemd/system/templ2@.service"
594167
-islink "$root/etc/systemd/system/another-template@.target.requires/templ2@two.service" "/etc/systemd/system/templ2@.service"
594167
+islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "../templ2@.service"
594167
+islink "$root/etc/systemd/system/another-template@.target.requires/templ2@two.service" "../templ2@two.service"
594167
 
594167
 "$systemctl" --root="$root" disable 'templ2@two.service'
594167
-islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "/etc/systemd/system/templ2@.service"
594167
+islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "../templ2@.service"
594167
 test ! -h "$root/etc/systemd/system/another-template@.target.requires/templ2@two.service"
594167
 
594167
 "$systemctl" --root="$root" disable 'templ2@.service'
594167
@@ -393,8 +393,8 @@ EOF
594167
 test ! -h "$root/etc/systemd/system/link4.service"  # this is our file
594167
 test ! -h "$root/etc/systemd/system/link4@.service"
594167
 test ! -h "$root/etc/systemd/system/link4@inst.service"
594167
-islink "$root/etc/systemd/system/link4alias.service" "/etc/systemd/system/link4.service"
594167
-islink "$root/etc/systemd/system/link4alias2.service" "/etc/systemd/system/link4.service"
594167
+islink "$root/etc/systemd/system/link4alias.service" "link4.service"
594167
+islink "$root/etc/systemd/system/link4alias2.service" "link4.service"
594167
 
594167
 "$systemctl" --root="$root" disable 'link4.service'
594167
 test ! -h "$root/etc/systemd/system/link4.service"
594167
@@ -413,8 +413,8 @@ EOF
594167
 # Apparently this works. I'm not sure what to think.
594167
 "$systemctl" --root="$root" enable '/etc/systemd/system/link4.service'
594167
 test ! -h "$root/etc/systemd/system/link4.service"  # this is our file
594167
-islink "$root/etc/systemd/system/link4alias.service" "/etc/systemd/system/link4.service"
594167
-islink "$root/etc/systemd/system/link4alias2.service" "/etc/systemd/system/link4.service"
594167
+islink "$root/etc/systemd/system/link4alias.service" "link4.service"
594167
+islink "$root/etc/systemd/system/link4alias2.service" "link4.service"
594167
 
594167
 "$systemctl" --root="$root" disable '/etc/systemd/system/link4.service'
594167
 test ! -h "$root/etc/systemd/system/link4.service"
594167
@@ -432,8 +432,8 @@ EOF
594167
 
594167
 "$systemctl" --root="$root" enable 'link5.service'
594167
 test ! -h "$root/etc/systemd/system/link5.service"  # this is our file
594167
-islink "$root/etc/systemd/system/link5alias.service" "/etc/systemd/system/link5.service"
594167
-islink "$root/etc/systemd/system/link5alias2.service" "/etc/systemd/system/link5.service"
594167
+islink "$root/etc/systemd/system/link5alias.service" "link5.service"
594167
+islink "$root/etc/systemd/system/link5alias2.service" "link5.service"
594167
 
594167
 "$systemctl" --root="$root" disable 'link5.service'
594167
 test ! -h "$root/etc/systemd/system/link5alias.service"
594167
@@ -455,10 +455,6 @@ islink "$root/etc/systemd/system/link5copy.service" '/link5copy.service'
594167
 test ! -h "$root/etc/systemd/system/link5alias.service"
594167
 test ! -h "$root/etc/systemd/system/link5alias2.service"
594167
 
594167
-# FIXME: we must create link5alias2 and link5alias as relative links to link5.service
594167
-# When they are independent links to /link5.service, systemd doesn't know that
594167
-# they are aliases, because we do not follow symlinks outside of the search paths.
594167
-
594167
 "$systemctl" --root="$root" disable 'link5copy.service'
594167
 test ! -h "$root/etc/systemd/system/link5copy.service"
594167
 test ! -h "$root/etc/systemd/system/link5alias.service"
594167
@@ -466,8 +462,8 @@ test ! -h "$root/etc/systemd/system/link5alias2.service"
594167
 
594167
 "$systemctl" --root="$root" enable '/link5copy.service'
594167
 islink "$root/etc/systemd/system/link5copy.service" '/link5copy.service'
594167
-islink "$root/etc/systemd/system/link5alias.service" '/link5copy.service'
594167
-islink "$root/etc/systemd/system/link5alias2.service" '/link5copy.service'
594167
+islink "$root/etc/systemd/system/link5alias.service" 'link5copy.service'
594167
+islink "$root/etc/systemd/system/link5alias2.service" 'link5copy.service'
594167
 
594167
 "$systemctl" --root="$root" disable 'link5copy.service'
594167
 test ! -h "$root/etc/systemd/system/link5copy.service"
594167
@@ -486,10 +482,10 @@ EOF
594167
 
594167
 "$systemctl" --root="$root" enable 'link5@.path'
594167
 test ! -h "$root/etc/systemd/system/link5@.path"  # this is our file
594167
-islink "$root/etc/systemd/system/target5@.target.wants/link5@.path" "/etc/systemd/system/link5@.path"
594167
-islink "$root/etc/systemd/system/target5@.target.requires/link5@.path" "/etc/systemd/system/link5@.path"
594167
-islink "$root/etc/systemd/system/target5@inst.target.wants/link5@.path" "/etc/systemd/system/link5@.path"
594167
-islink "$root/etc/systemd/system/target5@inst.target.requires/link5@.path" "/etc/systemd/system/link5@.path"
594167
+islink "$root/etc/systemd/system/target5@.target.wants/link5@.path" "../link5@.path"
594167
+islink "$root/etc/systemd/system/target5@.target.requires/link5@.path" "../link5@.path"
594167
+islink "$root/etc/systemd/system/target5@inst.target.wants/link5@.path" "../link5@.path"
594167
+islink "$root/etc/systemd/system/target5@inst.target.requires/link5@.path" "../link5@.path"
594167
 
594167
 "$systemctl" --root="$root" disable 'link5@.path'
594167
 test ! -h "$root/etc/systemd/system/link5@.path"  # this is our file
594167
@@ -528,7 +524,7 @@ check_alias() {
594167
 Alias=target@$1:%$1.socket
594167
 EOF
594167
     SYSTEMD_LOG_LEVEL=debug "$systemctl" --root="$root" enable 'some-some-link6@.socket' || return 1
594167
-    islink "$root/etc/systemd/system/target@$1:$2.socket" "/etc/systemd/system/some-some-link6@.socket" || return 2
594167
+    islink "$root/etc/systemd/system/target@$1:$2.socket" "some-some-link6@.socket" || return 2
594167
 }
594167
 
594167
 check_alias a "$(uname -m | tr '_' '-')"
594167
@@ -629,10 +625,10 @@ RequiredBy=another-target2@.target
594167
 EOF
594167
 
594167
 "$systemctl" --root="$root" enable 'some-some-link7.socket'
594167
-islink "$root/etc/systemd/system/target@some-some-link7.target.wants/some-some-link7.socket" "/etc/systemd/system/some-some-link7.socket"
594167
-islink "$root/etc/systemd/system/another-target@.target.wants/some-some-link7.socket" "/etc/systemd/system/some-some-link7.socket"
594167
-islink "$root/etc/systemd/system/target2@some-some-link7.target.requires/some-some-link7.socket" "/etc/systemd/system/some-some-link7.socket"
594167
-islink "$root/etc/systemd/system/another-target2@.target.requires/some-some-link7.socket" "/etc/systemd/system/some-some-link7.socket"
594167
+islink "$root/etc/systemd/system/target@some-some-link7.target.wants/some-some-link7.socket" "../some-some-link7.socket"
594167
+islink "$root/etc/systemd/system/another-target@.target.wants/some-some-link7.socket" "../some-some-link7.socket"
594167
+islink "$root/etc/systemd/system/target2@some-some-link7.target.requires/some-some-link7.socket" "../some-some-link7.socket"
594167
+islink "$root/etc/systemd/system/another-target2@.target.requires/some-some-link7.socket" "../some-some-link7.socket"
594167
 
594167
 "$systemctl" --root="$root" disable 'some-some-link7.socket'
594167
 test ! -h "$root/etc/systemd/system/target@some-some-link7.target.wants/some-some-link7.socket"