]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
generators: when creating symlinks, silently ignore existing links in one more place
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 8 Sep 2025 17:47:28 +0000 (19:47 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 15 Sep 2025 09:11:01 +0000 (11:11 +0200)
After the update to systemd 257.7 in Fedora, there are reports that we fail to
create a symlink:
  systemd-gpt-auto-generator[585]: Failed to create symlink /run/systemd/generator/local-fs.target.wants/systemd-fsck-root.service: File exists
  (sd-exec-[574]: /usr/lib/systemd/system-generators/systemd-gpt-auto-generator failed with exit status 1.

I guess that some other generator created the symlink. We silently ignore
EEXIST in similar codepaths, so add that in one more place. (The target of the
symlink doesn't really matter. The name of the link matters. So something like
symlink_idempotent would not be better. For example, a different generator
might use a slightly different target path, and symlink_idempotent would be too
strict.)

src/shared/generator.c

index f978d43fe897676cd2acebf7a724c3c05a762456..f7ae848d6e195cffe9db980b1f47edf181b73f4a 100644 (file)
 #include "tmpfile-util.h"
 #include "unit-name.h"
 
+static int symlink_unless_exists(const char *to, const char *from) {
+        (void) mkdir_parents(from, 0755);
+
+        if (symlink(to, from) < 0 && errno != EEXIST)
+                return log_error_errno(errno, "Failed to create symlink %s: %m", from);
+        return 0;
+}
+
 int generator_open_unit_file_full(
                 const char *dir,
                 const char *source,
@@ -134,12 +142,7 @@ int generator_add_symlink_full(
         if (!to)
                 return log_oom();
 
-        (void) mkdir_parents_label(to, 0755);
-
-        if (symlink(from, to) < 0 && errno != EEXIST)
-                return log_error_errno(errno, "Failed to create symlink \"%s\": %m", to);
-
-        return 0;
+        return symlink_unless_exists(from, to);
 }
 
 static int generator_add_ordering(
@@ -331,19 +334,16 @@ int generator_write_fsck_deps(
         }
 
         if (path_equal(where, "/")) {
-                const char *lnk;
-
                 /* We support running the fsck instance for the root fs while it is already mounted, for
                  * compatibility with non-initrd boots. It's ugly, but it is how it is. Since – unlike for
                  * regular file systems – this means the ordering is reversed (i.e. mount *before* fsck) we
                  * have a separate fsck unit for this, independent of systemd-fsck@.service. */
 
-                lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/" SPECIAL_FSCK_ROOT_SERVICE);
-
-                (void) mkdir_parents(lnk, 0755);
-                if (symlink(SYSTEM_DATA_UNIT_DIR "/" SPECIAL_FSCK_ROOT_SERVICE, lnk) < 0)
-                        return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
+                const char *lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/" SPECIAL_FSCK_ROOT_SERVICE);
 
+                r = symlink_unless_exists(SYSTEM_DATA_UNIT_DIR "/" SPECIAL_FSCK_ROOT_SERVICE, lnk);
+                if (r < 0)
+                        return r;
         } else {
                 _cleanup_free_ char *_fsck = NULL;
                 const char *fsck, *dep;