summaryrefslogtreecommitdiff
path: root/src/core/socket.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2014-06-04 16:19:00 +0200
committerLennart Poettering <lennart@poettering.net>2014-06-04 16:21:17 +0200
commit811ba7a0e292eda0f2f470613cc28a97bda7ee66 (patch)
tree881f55ee5157cfcf266c674bbe65ffc0930fb6dd /src/core/socket.c
parente9fc29f4ecc9509ccc02eb8a014341e26c0d7831 (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.c68
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(