chiark / gitweb /
socket: optionally remove sockets/FIFOs in the file system after use
authorLennart Poettering <lennart@poettering.net>
Wed, 4 Jun 2014 11:10:43 +0000 (13:10 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 4 Jun 2014 11:12:34 +0000 (13:12 +0200)
man/systemd.socket.xml
src/core/dbus-socket.c
src/core/load-fragment-gperf.gperf.m4
src/core/socket.c
src/core/socket.h
src/shared/socket-util.c
src/shared/socket-util.h

index c0d7906d7ed652cc9f1c47b4c430e8ea524ae892..d2149409bc68b4e24410e10dd6322df6038bad6c 100644 (file)
                                 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
index 67a562775ce61001f0103b9813257d5d378f96a8..7eeccf6def41eee974e5cd2f37f82ad08312f716 100644 (file)
@@ -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),
index 97382d47456c17a641f5cf306a8135ab6dfee085..48e2aae72d9bd2ce71cddfdc7ef59cdbd0c569a8 100644 (file)
@@ -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)
index 60dc9d0cd4955d7d899165f184156faec4863715..624e28744f0226210b7f3f7d0faafe58886b157b 100644 (file)
@@ -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)
index 076a1836983aef109dc414dd423443a7437b1ecb..42b1a1fe06f8b9b353ae9b907bc2113bfb7cc613 100644 (file)
@@ -126,6 +126,7 @@ struct Socket {
         SocketResult result;
 
         bool accept;
+        bool remove_on_stop;
 
         /* Socket options */
         bool keep_alive;
index 997a1ceba39e35fe324d82da8bd8e648c1f53a9b..92564e31933f8b107a3ffb575c2a8acc648dfcfb 100644 (file)
@@ -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",
index efaaf82ab1fd57f626fb1a8b5c83bd453e2235f6..f938f86200c55da82003c5809d08021530d8e2c9 100644 (file)
@@ -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_;