]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/service.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / core / service.c
index ac3f14665d70ff5e7dcb72c24cb536f6385521de..a68e5c9f3df75fb498f80dfa04ae0bddede6320b 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
   This file is part of systemd.
 
@@ -294,6 +295,9 @@ static void service_fd_store_unlink(ServiceFDStore *fs) {
 static void service_release_fd_store(Service *s) {
         assert(s);
 
+        if (s->n_keep_fd_store > 0)
+                return;
+
         log_unit_debug(UNIT(s), "Releasing all stored fds");
         while (s->fd_store)
                 service_fd_store_unlink(s->fd_store);
@@ -301,7 +305,7 @@ static void service_release_fd_store(Service *s) {
         assert(s->n_fd_store == 0);
 }
 
-static void service_release_resources(Unit *u, bool inactive) {
+static void service_release_resources(Unit *u) {
         Service *s = SERVICE(u);
 
         assert(s);
@@ -315,8 +319,7 @@ static void service_release_resources(Unit *u, bool inactive) {
         s->stdout_fd = safe_close(s->stdout_fd);
         s->stderr_fd = safe_close(s->stderr_fd);
 
-        if (inactive)
-                service_release_fd_store(s);
+        service_release_fd_store(s);
 }
 
 static void service_done(Unit *u) {
@@ -360,7 +363,7 @@ static void service_done(Unit *u) {
 
         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
 
-        service_release_resources(u, true);
+        service_release_resources(u);
 }
 
 static int on_fd_store_io(sd_event_source *e, int fd, uint32_t revents, void *userdata) {
@@ -1297,17 +1300,14 @@ static int service_spawn(
                 union sockaddr_union sa;
                 socklen_t salen = sizeof(sa);
 
-                r = getpeername(s->socket_fd, &sa.sa, &salen);
-                if (r < 0) {
-                        r = -errno;
+                /* If this is a per-connection service instance, let's set $REMOTE_ADDR and $REMOTE_PORT to something
+                 * useful. Note that we do this only when we are still connected at this point in time, which we might
+                 * very well not be. Hence we ignore all errors when retrieving peer information (as that might result
+                 * in ENOTCONN), and just use whate we can use. */
 
-                        /* ENOTCONN is legitimate if the endpoint disappeared on shutdown.
-                         * This connection is over, but the socket unit lives on. */
-                        if (r != -ENOTCONN || !IN_SET(s->control_command_id, SERVICE_EXEC_STOP, SERVICE_EXEC_STOP_POST))
-                                return r;
-                }
+                if (getpeername(s->socket_fd, &sa.sa, &salen) >= 0 &&
+                    IN_SET(sa.sa.sa_family, AF_INET, AF_INET6, AF_VSOCK)) {
 
-                if (r == 0 && IN_SET(sa.sa.sa_family, AF_INET, AF_INET6, AF_VSOCK)) {
                         _cleanup_free_ char *addr = NULL;
                         char *t;
                         unsigned port;
@@ -1524,6 +1524,10 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
         if (s->result != SERVICE_SUCCESS)
                 log_unit_warning(UNIT(s), "Failed with result '%s'.", service_result_to_string(s->result));
 
+        /* Make sure service_release_resources() doesn't destroy our FD store, while we are changing through
+         * SERVICE_FAILED/SERVICE_DEAD before entering into SERVICE_AUTO_RESTART. */
+        s->n_keep_fd_store ++;
+
         service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
 
         if (s->result != SERVICE_SUCCESS)
@@ -1532,8 +1536,10 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
         if (allow_restart && service_shall_restart(s)) {
 
                 r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->restart_usec));
-                if (r < 0)
+                if (r < 0) {
+                        s->n_keep_fd_store--;
                         goto fail;
+                }
 
                 service_set_state(s, SERVICE_AUTO_RESTART);
         } else
@@ -1541,6 +1547,11 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
                  * user can still introspect the counter. Do so on the next start. */
                 s->flush_n_restarts = true;
 
+        /* The new state is in effect, let's decrease the fd store ref counter again. Let's also readd us to the GC
+         * queue, so that the fd store is possibly gc'ed again */
+        s->n_keep_fd_store--;
+        unit_add_to_gc_queue(UNIT(s));
+
         /* The next restart might not be a manual stop, hence reset the flag indicating manual stops */
         s->forbid_restart = false;