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; }