generators: when creating symlinks, silently ignore existing links in one more place

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.)
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2025-09-08 19:47:28 +02:00
parent bb4c00001d
commit 8a9ab3dbbc

View File

@@ -26,6 +26,14 @@
#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;