diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
index 2dfca713e4..68d01cccc5 100644
--- a/man/systemd.socket.xml
+++ b/man/systemd.socket.xml
@@ -804,14 +804,13 @@
Symlinks=
- Takes a list of file system paths. The
- specified paths will be created as symlinks to the AF_UNIX
- socket path or FIFO path of this socket unit. If this setting
- is used, only one AF_UNIX socket in the file system or one
- FIFO may be configured for the socket unit. Use this option to
- manage one or more symlinked alias names for a socket, binding
- their lifecycle together. If the empty string is assigned, the
- list of paths is reset. Defaults to the empty list.
+ Takes a list of file system paths. The specified paths will be created as symlinks to the
+ AF_UNIX socket path or FIFO path of this socket unit. If this setting is used, only one
+ AF_UNIX socket in the file system or one FIFO may be configured for the socket unit. Use
+ this option to manage one or more symlinked alias names for a socket, binding their lifecycle together. Note
+ that if creation of a symlink fails this is not considered fatal for the socket unit, and the socket unit may
+ still start. If an empty string is assigned, the list of paths is reset. Defaults to an empty
+ list.
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index fdedeffb9a..af63171041 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -359,22 +359,25 @@ int touch(const char *path) {
}
int symlink_idempotent(const char *from, const char *to) {
- _cleanup_free_ char *p = NULL;
int r;
assert(from);
assert(to);
if (symlink(from, to) < 0) {
+ _cleanup_free_ char *p = NULL;
+
if (errno != EEXIST)
return -errno;
r = readlink_malloc(to, &p);
- if (r < 0)
+ if (r == -EINVAL) /* Not a symlink? In that case return the original error we encountered: -EEXIST */
+ return -EEXIST;
+ if (r < 0) /* Any other error? In that case propagate it as is */
return r;
- if (!streq(p, from))
- return -EINVAL;
+ if (!streq(p, from)) /* Not the symlink we want it to be? In that case, propagate the original -EEXIST */
+ return -EEXIST;
}
return 0;
diff --git a/src/core/socket.c b/src/core/socket.c
index 3b84ffa2a7..ba70756d83 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -38,6 +38,7 @@
#include "exit-status.h"
#include "fd-util.h"
#include "format-util.h"
+#include "fs-util.h"
#include "in-addr-util.h"
#include "io-util.h"
#include "label.h"
@@ -1174,7 +1175,7 @@ static int fifo_address_create(
assert(path);
- mkdir_parents_label(path, directory_mode);
+ (void) mkdir_parents_label(path, directory_mode);
r = mac_selinux_create_file_prepare(path, S_IFIFO);
if (r < 0)
@@ -1324,6 +1325,7 @@ static int mq_address_create(
static int socket_symlink(Socket *s) {
const char *p;
char **i;
+ int r;
assert(s);
@@ -1331,8 +1333,23 @@ static int socket_symlink(Socket *s) {
if (!p)
return 0;
- STRV_FOREACH(i, s->symlinks)
- symlink_label(p, *i);
+ STRV_FOREACH(i, s->symlinks) {
+ (void) mkdir_parents_label(*i, s->directory_mode);
+
+ r = symlink_idempotent(p, *i);
+
+ if (r == -EEXIST && s->remove_on_stop) {
+ /* If there's already something where we want to create the symlink, and the destructive
+ * RemoveOnStop= mode is set, then we might as well try to remove what already exists and try
+ * again. */
+
+ if (unlink(*i) >= 0)
+ r = symlink_idempotent(p, *i);
+ }
+
+ if (r < 0)
+ log_unit_warning_errno(UNIT(s), r, "Failed to create symlink %s → %s, ignoring: %m", p, *i);
+ }
return 0;
}