diff options
author | Lennart Poettering <lennart@poettering.net> | 2014-06-04 16:19:00 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2014-06-04 16:21:17 +0200 |
commit | 811ba7a0e292eda0f2f470613cc28a97bda7ee66 (patch) | |
tree | 881f55ee5157cfcf266c674bbe65ffc0930fb6dd /src/core/socket.c | |
parent | e9fc29f4ecc9509ccc02eb8a014341e26c0d7831 (diff) |
socket: add new Symlinks= option for socket units
With Symlinks= we can manage one or more symlinks to AF_UNIX or FIFO
nodes in the file system, with the same lifecycle as the socket itself.
This has two benefits: first, this allows us to remove /dev/log and
/dev/initctl from /dev, thus leaving only symlinks, device nodes and
directories in the /dev tree. More importantly however, this allows us
to move /dev/log out of /dev, while still making it accessible there, so
that PrivateDevices= can provide /dev/log too.
Diffstat (limited to 'src/core/socket.c')
-rw-r--r-- | src/core/socket.c | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/src/core/socket.c b/src/core/socket.c index 624e28744f..c158aaf1de 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -145,6 +145,8 @@ static void socket_done(Unit *u) { free(s->smack_ip_in); free(s->smack_ip_out); + strv_free(s->symlinks); + s->timer_event_source = sd_event_source_unref(s->timer_event_source); } @@ -355,6 +357,39 @@ static int socket_add_extras(Socket *s) { return 0; } +static const char *socket_find_symlink_target(Socket *s) { + const char *found = NULL; + SocketPort *p; + + LIST_FOREACH(port, p, s->ports) { + const char *f = NULL; + + switch (p->type) { + + case SOCKET_FIFO: + f = p->path; + break; + + case SOCKET_SOCKET: + if (p->address.sockaddr.un.sun_path[0] != 0) + f = p->address.sockaddr.un.sun_path; + break; + + default: + break; + } + + if (f) { + if (found) + return NULL; + + found = f; + } + } + + return found; +} + static int socket_verify(Socket *s) { assert(s); @@ -387,6 +422,11 @@ static int socket_verify(Socket *s) { return -EINVAL; } + if (!strv_isempty(s->symlinks) && !socket_find_symlink_target(s)) { + log_error_unit(UNIT(s)->id, "%s has symlinks set but none or more than one node in the file system. Refusing.", UNIT(s)->id); + return -EINVAL; + } + return 0; } @@ -692,6 +732,7 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) { static void socket_close_fds(Socket *s) { SocketPort *p; + char **i; assert(s); @@ -732,6 +773,10 @@ static void socket_close_fds(Socket *s) { } } } + + if (s->remove_on_stop) + STRV_FOREACH(i, s->symlinks) + unlink(*i); } static void socket_apply_socket_options(Socket *s, int fd) { @@ -915,7 +960,8 @@ static int special_address_create( assert(path); assert(_fd); - if ((fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) { + fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW); + if (fd < 0) { r = -errno; goto fail; } @@ -968,7 +1014,6 @@ static int mq_address_create( /* Include the original umask in our mask */ umask(~mq_mode | old_mask); - fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr); umask(old_mask); @@ -998,6 +1043,22 @@ fail: return r; } +static int socket_symlink(Socket *s) { + const char *p; + char **i; + + assert(s); + + p = socket_find_symlink_target(s); + if (!p) + return 0; + + STRV_FOREACH(i, s->symlinks) + symlink(p, *i); + + return 0; +} + static int socket_open_fds(Socket *s) { SocketPort *p; int r; @@ -1045,6 +1106,7 @@ static int socket_open_fds(Socket *s) { p->fd = r; socket_apply_socket_options(s, p->fd); + socket_symlink(s); } else if (p->type == SOCKET_SPECIAL) { @@ -1065,6 +1127,8 @@ static int socket_open_fds(Socket *s) { goto rollback; socket_apply_fifo_options(s, p->fd); + socket_symlink(s); + } else if (p->type == SOCKET_MQUEUE) { r = mq_address_create( |