]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
install: don't enter loop when traversing a template symlinks
authorLennart Poettering <lennart@poettering.net>
Tue, 7 Feb 2017 15:22:49 +0000 (16:22 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 7 Feb 2017 15:22:49 +0000 (16:22 +0100)
Before this patch, if we'd encounter an instance or template symlink
while traversing a chain of symlinks we'd fill in the instance name and
retry the iteration. This makes no sense if the resulting name is
actually the same as we are coming from, as we'd just spin a couple of
times in the loop, until the UNIT_FILE_FOLLOW_SYMLINK_MAX iteration
limit is hit.

Fix this, by accepted the symlink as it is, if it identical to what we
filled in.

src/shared/install.c

index 478abac8abfb8fb8f3cf5cbac974cf98361df5d6..975a789ebee56ec07ea2334bd03009197ea7cd53 100644 (file)
@@ -1354,7 +1354,8 @@ static int install_info_follow(
                 InstallContext *c,
                 UnitFileInstallInfo *i,
                 const char *root_dir,
-                SearchFlags flags) {
+                SearchFlags flags,
+                bool ignore_different_name) {
 
         assert(c);
         assert(i);
@@ -1367,7 +1368,7 @@ static int install_info_follow(
         /* If the basename doesn't match, the caller should add a
          * complete new entry for this. */
 
-        if (!streq(basename(i->symlink_target), i->name))
+        if (!ignore_different_name && !streq(basename(i->symlink_target), i->name))
                 return -EXDEV;
 
         free_and_replace(i->path, i->symlink_target);
@@ -1415,7 +1416,7 @@ static int install_info_traverse(
                                 return -ELOOP;
                 }
 
-                r = install_info_follow(c, i, paths->root_dir, flags);
+                r = install_info_follow(c, i, paths->root_dir, flags, false);
                 if (r == -EXDEV) {
                         _cleanup_free_ char *buffer = NULL;
                         const char *bn;
@@ -1439,6 +1440,18 @@ static int install_info_traverse(
                                 if (r < 0)
                                         return r;
 
+                                if (streq(buffer, i->name)) {
+
+                                        /* We filled in the instance, and the target stayed the same? If so, then let's
+                                         * honour the link as it is. */
+
+                                        r = install_info_follow(c, i, paths->root_dir, flags, true);
+                                        if (r < 0)
+                                                return r;
+
+                                        continue;
+                                }
+
                                 bn = buffer;
                         }