803fb7
From 412044ee341c574e5163bf2be32e5da9618f2640 Mon Sep 17 00:00:00 2001
803fb7
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
803fb7
Date: Sat, 13 Aug 2016 01:20:29 -0400
803fb7
Subject: [PATCH] shared/install: ignore unit symlinks when doing preset-all
803fb7
803fb7
Before, when interating over unit files during preset-all, behaviour was the
803fb7
following:
803fb7
803fb7
- if we hit the real unit name first, presets were queried for that name, and
803fb7
  that unit was enabled or disabled accordingly,
803fb7
803fb7
- if we hit an alias first (one of the symlinks chaining to the real unit), we
803fb7
  checked the presets using the symlink name, and then proceeded to enable or
803fb7
  disable the real unit.
803fb7
803fb7
E.g. for systemd-networkd.service we have the alias dbus-org.freedesktop.network1.service
803fb7
(/usr/lib/systemd/system/dbus-org.freedesktop.network1.service), but the preset
803fb7
is only for the systemd-networkd.service name. The service would be enabled or
803fb7
disabled pseudorandomly depending on the order of iteration.
803fb7
803fb7
For "preset", behaviour was analogous: preset on the alias name disabled the
803fb7
service (following the default disable policy), preset on the "real" name
803fb7
applied the presets.
803fb7
803fb7
With the patch, for "preset" and "preset-all" we silently skip symlinks. This
803fb7
gives mostly the right behaviour, with the limitation that presets on aliases
803fb7
are ignored.  I think that presets on aliases are not that common (at least my
803fb7
preset files on Fedora don't exhibit any such usage), and should not be
803fb7
necessary, since whoever installs the preset can just refer to the real unit
803fb7
file. It would be possible to overcome this limitation by gathering a list of
803fb7
names of a unit first, and then checking whether *any* of the names matches the
803fb7
presets list. That would require a significant redesign of the code, and be
803fb7
a lot slower (since we would have to fully read all unit directories to preset
803fb7
one unit) to so I'm not doing that for now.
803fb7
803fb7
With this patch, two properties are satisfied:
803fb7
- preset-all and preset are idempotent, and the second and subsequent invocations
803fb7
  do not produce any changes,
803fb7
- preset-all and preset for a specific name produce the same state for that unit.
803fb7
803fb7
Fixes #3616.
803fb7
803fb7
Cherry-picked from: 11e11fd57a837ea1cb142009c3048882392f3ed3
803fb7
Related: #1375097
803fb7
---
803fb7
 src/shared/install.c | 12 ++++++++++--
803fb7
 1 file changed, 10 insertions(+), 2 deletions(-)
803fb7
803fb7
diff --git a/src/shared/install.c b/src/shared/install.c
803fb7
index b0a29ddd7..f01a21262 100644
803fb7
--- a/src/shared/install.c
803fb7
+++ b/src/shared/install.c
803fb7
@@ -2270,12 +2270,20 @@ static int preset_prepare_one(
803fb7
                 const char *name) {
803fb7
 
803fb7
         InstallInfo *i;
803fb7
+        _cleanup_(install_context_done) InstallContext tmp = {};
803fb7
         int r;
803fb7
 
803fb7
-        if (install_info_find(plus, name) ||
803fb7
-            install_info_find(minus, name))
803fb7
+        if (install_info_find(plus, name) || install_info_find(minus, name))
803fb7
                 return 0;
803fb7
 
803fb7
+        r = install_info_discover(scope, &tmp, root_dir, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
803fb7
+        if (r < 0)
803fb7
+                return r;
803fb7
+        if (!streq(name, i->name)) {
803fb7
+                log_debug("Skipping %s because is an alias for %s", name, i->name);
803fb7
+                return 0;
803fb7
+        }
803fb7
+
803fb7
         r = unit_file_query_preset(scope, root_dir, name);
803fb7
         if (r < 0)
803fb7
                 return r;