summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/systemd.socket.xml19
-rw-r--r--src/core/dbus-socket.c1
-rw-r--r--src/core/load-fragment-gperf.gperf.m41
-rw-r--r--src/core/socket.c80
-rw-r--r--src/core/socket.h1
-rw-r--r--src/shared/socket-util.c15
-rw-r--r--src/shared/socket-util.h1
7 files changed, 89 insertions, 29 deletions
diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
index c0d7906d7e..d2149409bc 100644
--- a/man/systemd.socket.xml
+++ b/man/systemd.socket.xml
@@ -730,6 +730,25 @@
option.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>RemoveOnStop=</varname></term>
+ <listitem><para>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.</para></listitem>
+ </varlistentry>
+
</variablelist>
<para>Check
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index 67a562775c..7eeccf6def 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 97382d4745..48e2aae72d 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 60dc9d0cd4..624e28744f 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 076a183698..42b1a1fe06 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 997a1ceba3..92564e3193 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 efaaf82ab1..f938f86200 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_;