From bd1fe7c79de3d81325afecb7ded46c1627f6c1df Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Jun 2014 13:10:43 +0200 Subject: [PATCH] socket: optionally remove sockets/FIFOs in the file system after use --- man/systemd.socket.xml | 19 +++++++ src/core/dbus-socket.c | 1 + src/core/load-fragment-gperf.gperf.m4 | 1 + src/core/socket.c | 80 +++++++++++++++++---------- src/core/socket.h | 1 + src/shared/socket-util.c | 15 +++++ src/shared/socket-util.h | 1 + 7 files changed, 89 insertions(+), 29 deletions(-) diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index c0d7906d7..d2149409b 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -730,6 +730,25 @@ option. + + RemoveOnStop= + Takes a boolean + argument. If enabled any file nodes + created by this socket unit are + removed when it is stopped. This + applies to AF_UNIX sockets in the file + system, POSIX message queues as well + as FIFOs. Normally it should not be + necessary to use this option, and is + not recommended as services might + continue to run after the socket unit + has been terminated and it should + still be possible to communicate with + them via their file system + node. Defaults to + off. + + Check diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 67a562775..7eeccf6de 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -106,6 +106,7 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("Broadcast", "b", bus_property_get_bool, offsetof(Socket, broadcast), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PassCredentials", "b", bus_property_get_bool, offsetof(Socket, pass_cred), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PassSecurity", "b", bus_property_get_bool, offsetof(Socket, pass_sec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RemoveOnStop", "b", bus_property_get_bool, offsetof(Socket, remove_on_stop), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Listen", "a(ss)", property_get_listen, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Mark", "i", bus_property_get_int, offsetof(Socket, mark), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("MaxConnections", "u", bus_property_get_unsigned, offsetof(Socket, max_connections), SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 97382d474..48e2aae72 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -242,6 +242,7 @@ Socket.TCPCongestion, config_parse_string, 0, Socket.ReusePort, config_parse_bool, 0, offsetof(Socket, reuse_port) Socket.MessageQueueMaxMessages, config_parse_long, 0, offsetof(Socket, mq_maxmsg) Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize) +Socket.RemoveOnStop, config_parse_bool, 0, offsetof(Socket, remove_on_stop) Socket.Service, config_parse_socket_service, 0, 0 m4_ifdef(`HAVE_SMACK', `Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack) diff --git a/src/core/socket.c b/src/core/socket.c index 60dc9d0cd..624e28744 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -451,7 +451,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { "%sBroadcast: %s\n" "%sPassCredentials: %s\n" "%sPassSecurity: %s\n" - "%sTCPCongestion: %s\n", + "%sTCPCongestion: %s\n" + "%sRemoveOnStop: %s\n", prefix, socket_state_to_string(s->state), prefix, socket_result_to_string(s->result), prefix, socket_address_bind_ipv6_only_to_string(s->bind_ipv6_only), @@ -464,7 +465,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { prefix, yes_no(s->broadcast), prefix, yes_no(s->pass_cred), prefix, yes_no(s->pass_sec), - prefix, strna(s->tcp_congestion)); + prefix, strna(s->tcp_congestion), + prefix, yes_no(s->remove_on_stop)); if (s->control_pid > 0) fprintf(f, @@ -702,13 +704,33 @@ static void socket_close_fds(Socket *s) { p->fd = safe_close(p->fd); - /* One little note: we should never delete any sockets - * in the file system here! After all some other - * process we spawned might still have a reference of - * this fd and wants to continue to use it. Therefore - * we delete sockets in the file system before we - * create a new one, not after we stopped using - * one! */ + /* One little note: we should normally not delete any + * sockets in the file system here! After all some + * other process we spawned might still have a + * reference of this fd and wants to continue to use + * it. Therefore we delete sockets in the file system + * before we create a new one, not after we stopped + * using one! */ + + if (s->remove_on_stop) { + switch (p->type) { + + case SOCKET_FIFO: + unlink(p->path); + break; + + case SOCKET_MQUEUE: + mq_unlink(p->path); + break; + + case SOCKET_SOCKET: + socket_address_unlink(&p->address); + break; + + default: + break; + } + } } } @@ -993,17 +1015,15 @@ static int socket_open_fds(Socket *s) { if (!know_label) { - if ((r = socket_instantiate_service(s)) < 0) + r = socket_instantiate_service(s); + if (r < 0) return r; if (UNIT_ISSET(s->service) && SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]) { r = label_get_create_label_from_exe(SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]->path, &label); - - if (r < 0) { - if (r != -EPERM) - return r; - } + if (r < 0 && r != -EPERM) + return r; } know_label = true; @@ -1121,14 +1141,15 @@ static void socket_set_state(Socket *s, SocketState state) { old_state = s->state; s->state = state; - if (state != SOCKET_START_PRE && - state != SOCKET_START_POST && - state != SOCKET_STOP_PRE && - state != SOCKET_STOP_PRE_SIGTERM && - state != SOCKET_STOP_PRE_SIGKILL && - state != SOCKET_STOP_POST && - state != SOCKET_FINAL_SIGTERM && - state != SOCKET_FINAL_SIGKILL) { + if (!IN_SET(state, + SOCKET_START_PRE, + SOCKET_START_POST, + SOCKET_STOP_PRE, + SOCKET_STOP_PRE_SIGTERM, + SOCKET_STOP_PRE_SIGKILL, + SOCKET_STOP_POST, + SOCKET_FINAL_SIGTERM, + SOCKET_FINAL_SIGKILL)) { s->timer_event_source = sd_event_source_unref(s->timer_event_source); socket_unwatch_control_pid(s); @@ -1139,12 +1160,13 @@ static void socket_set_state(Socket *s, SocketState state) { if (state != SOCKET_LISTENING) socket_unwatch_fds(s); - if (state != SOCKET_START_POST && - state != SOCKET_LISTENING && - state != SOCKET_RUNNING && - state != SOCKET_STOP_PRE && - state != SOCKET_STOP_PRE_SIGTERM && - state != SOCKET_STOP_PRE_SIGKILL) + if (!IN_SET(state, + SOCKET_START_POST, + SOCKET_LISTENING, + SOCKET_RUNNING, + SOCKET_STOP_PRE, + SOCKET_STOP_PRE_SIGTERM, + SOCKET_STOP_PRE_SIGKILL)) socket_close_fds(s); if (state != old_state) diff --git a/src/core/socket.h b/src/core/socket.h index 076a18369..42b1a1fe0 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -126,6 +126,7 @@ struct Socket { SocketResult result; bool accept; + bool remove_on_stop; /* Socket options */ bool keep_alive; diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c index 997a1ceba..92564e319 100644 --- a/src/shared/socket-util.c +++ b/src/shared/socket-util.c @@ -625,6 +625,21 @@ int getsockname_pretty(int fd, char **ret) { return sockaddr_pretty(&sa.sa, salen, false, ret); } +int socket_address_unlink(SocketAddress *a) { + assert(a); + + if (socket_address_family(a) != AF_UNIX) + return 0; + + if (a->sockaddr.un.sun_path[0] == 0) + return 0; + + if (unlink(a->sockaddr.un.sun_path) < 0) + return -errno; + + return 1; +} + static const char* const netlink_family_table[] = { [NETLINK_ROUTE] = "route", [NETLINK_FIREWALL] = "firewall", diff --git a/src/shared/socket-util.h b/src/shared/socket-util.h index efaaf82ab..f938f8620 100644 --- a/src/shared/socket-util.h +++ b/src/shared/socket-util.h @@ -70,6 +70,7 @@ int socket_address_parse(SocketAddress *a, const char *s); int socket_address_parse_netlink(SocketAddress *a, const char *s); int socket_address_print(const SocketAddress *a, char **p); int socket_address_verify(const SocketAddress *a) _pure_; +int socket_address_unlink(SocketAddress *a); bool socket_address_can_accept(const SocketAddress *a) _pure_; -- 2.30.2