]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/service.c
Merge pull request #1668 from ssahani/net1
[thirdparty/systemd.git] / src / core / service.c
index c941689dd7c1b4f0832ef02673e1163025ecf014..abcbd4954f181de77f3fe42798956ec1df0c5062 100644 (file)
 #include <unistd.h>
 
 #include "async.h"
-#include "manager.h"
-#include "unit.h"
-#include "service.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit-printf.h"
+#include "bus-error.h"
+#include "bus-kernel.h"
+#include "bus-util.h"
 #include "dbus-service.h"
-#include "special.h"
-#include "exit-status.h"
 #include "def.h"
-#include "path-util.h"
-#include "util.h"
-#include "utf8.h"
 #include "env-util.h"
+#include "escape.h"
+#include "exit-status.h"
+#include "fd-util.h"
 #include "fileio.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "bus-kernel.h"
 #include "formats-util.h"
+#include "load-dropin.h"
+#include "load-fragment.h"
+#include "log.h"
+#include "manager.h"
+#include "path-util.h"
 #include "process-util.h"
+#include "service.h"
 #include "signal-util.h"
+#include "special.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "unit-printf.h"
+#include "unit.h"
+#include "utf8.h"
+#include "util.h"
 
 static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
         [SERVICE_DEAD] = UNIT_INACTIVE,
@@ -108,6 +111,7 @@ static void service_init(Unit *u) {
         s->type = _SERVICE_TYPE_INVALID;
         s->socket_fd = -1;
         s->bus_endpoint_fd = -1;
+        s->stdin_fd = s->stdout_fd = s->stderr_fd = -1;
         s->guess_main_pid = true;
 
         RATELIMIT_INIT(s->start_limit, u->manager->default_start_limit_interval, u->manager->default_start_limit_burst);
@@ -271,11 +275,15 @@ static void service_release_resources(Unit *u) {
 
         assert(s);
 
-        if (!s->fd_store)
+        if (!s->fd_store && s->stdin_fd < 0 && s->stdout_fd < 0 && s->stderr_fd < 0)
                 return;
 
         log_unit_debug(u, "Releasing all resources.");
 
+        s->stdin_fd = safe_close(s->stdin_fd);
+        s->stdout_fd = safe_close(s->stdout_fd);
+        s->stderr_fd = safe_close(s->stderr_fd);
+
         while (s->fd_store)
                 service_fd_store_unlink(s->fd_store);
 
@@ -363,8 +371,10 @@ static int service_add_fd_store(Service *s, int fd, const char *name) {
         fs->fd = fd;
         fs->service = s;
         fs->fdname = strdup(name ?: "stored");
-        if (!fs->fdname)
+        if (!fs->fdname) {
+                free(fs);
                 return -ENOMEM;
+        }
 
         r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
         if (r < 0) {
@@ -889,7 +899,6 @@ static void service_set_state(Service *s, ServiceState state) {
                 log_unit_debug(UNIT(s), "Changed %s -> %s", service_state_to_string(old_state), service_state_to_string(state));
 
         unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS);
-        s->reload_result = SERVICE_SUCCESS;
 }
 
 static int service_coldplug(Unit *u) {
@@ -1089,11 +1098,13 @@ static int service_spawn(
         pid_t pid;
 
         ExecParameters exec_params = {
-                .apply_permissions   = apply_permissions,
-                .apply_chroot        = apply_chroot,
-                .apply_tty_stdin     = apply_tty_stdin,
-                .bus_endpoint_fd     = -1,
-                .selinux_context_net = s->socket_fd_selinux_context_net
+                .apply_permissions = apply_permissions,
+                .apply_chroot      = apply_chroot,
+                .apply_tty_stdin   = apply_tty_stdin,
+                .bus_endpoint_fd   = -1,
+                .stdin_fd          = -1,
+                .stdout_fd         = -1,
+                .stderr_fd         = -1,
         };
 
         int r;
@@ -1207,7 +1218,7 @@ static int service_spawn(
 
         if (is_control && UNIT(s)->cgroup_path) {
                 path = strjoina(UNIT(s)->cgroup_path, "/control");
-                cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
+                (void) cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
         } else
                 path = UNIT(s)->cgroup_path;
 
@@ -1235,8 +1246,12 @@ static int service_spawn(
         exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
         exec_params.watchdog_usec = s->watchdog_usec;
         exec_params.bus_endpoint_path = bus_endpoint_path;
+        exec_params.selinux_context_net = s->socket_fd_selinux_context_net;
         if (s->type == SERVICE_IDLE)
                 exec_params.idle_pipe = UNIT(s)->manager->idle_pipe;
+        exec_params.stdin_fd = s->stdin_fd;
+        exec_params.stdout_fd = s->stdout_fd;
+        exec_params.stderr_fd = s->stderr_fd;
 
         r = exec_spawn(UNIT(s),
                        c,
@@ -1813,6 +1828,7 @@ static void service_enter_reload(Service *s) {
         assert(s);
 
         service_unwatch_control_pid(s);
+        s->reload_result = SERVICE_SUCCESS;
 
         s->control_command = s->exec_command[SERVICE_EXEC_RELOAD];
         if (s->control_command) {
@@ -2036,6 +2052,7 @@ _pure_ static bool service_can_reload(Unit *u) {
 static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
         Service *s = SERVICE(u);
         ServiceFDStore *fs;
+        int r;
 
         assert(u);
         assert(f);
@@ -2054,12 +2071,9 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
         unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known));
         unit_serialize_item(u, f, "bus-name-good", yes_no(s->bus_name_good));
 
-        if (s->status_text) {
-                _cleanup_free_ char *c = NULL;
-
-                c = cescape(s->status_text);
-                unit_serialize_item(u, f, "status-text", strempty(c));
-        }
+        r = unit_serialize_item_escaped(u, f, "status-text", s->status_text);
+        if (r < 0)
+                return r;
 
         /* FIXME: There's a minor uncleanliness here: if there are
          * multiple commands attached here, we will start from the
@@ -2067,25 +2081,22 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
         if (s->control_command_id >= 0)
                 unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id));
 
-        if (s->socket_fd >= 0) {
-                int copy;
-
-                copy = fdset_put_dup(fds, s->socket_fd);
-                if (copy < 0)
-                        return copy;
-
-                unit_serialize_item_format(u, f, "socket-fd", "%i", copy);
-        }
-
-        if (s->bus_endpoint_fd >= 0) {
-                int copy;
-
-                copy = fdset_put_dup(fds, s->bus_endpoint_fd);
-                if (copy < 0)
-                        return copy;
+        r = unit_serialize_item_fd(u, f, fds, "stdin-fd", s->stdin_fd);
+        if (r < 0)
+                return r;
+        r = unit_serialize_item_fd(u, f, fds, "stdout-fd", s->stdout_fd);
+        if (r < 0)
+                return r;
+        r = unit_serialize_item_fd(u, f, fds, "stderr-fd", s->stderr_fd);
+        if (r < 0)
+                return r;
 
-                unit_serialize_item_format(u, f, "endpoint-fd", "%i", copy);
-        }
+        r = unit_serialize_item_fd(u, f, fds, "socket-fd", s->socket_fd);
+        if (r < 0)
+                return r;
+        r = unit_serialize_item_fd(u, f, fds, "endpoint-fd", s->bus_endpoint_fd);
+        if (r < 0)
+                return r;
 
         LIST_FOREACH(fd_store, fs, s->fd_store) {
                 _cleanup_free_ char *c = NULL;
@@ -2114,8 +2125,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
         if (dual_timestamp_is_set(&s->watchdog_timestamp))
                 dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp);
 
-        if (s->forbid_restart)
-                unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart));
+        unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart));
 
         return 0;
 }
@@ -2286,6 +2296,33 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
                         log_unit_debug(u, "Failed to parse forbid-restart value: %s", value);
                 else
                         s->forbid_restart = b;
+        } else if (streq(key, "stdin-fd")) {
+                int fd;
+
+                if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+                        log_unit_debug(u, "Failed to parse stdin-fd value: %s", value);
+                else {
+                        asynchronous_close(s->stdin_fd);
+                        s->stdin_fd = fdset_remove(fds, fd);
+                }
+        } else if (streq(key, "stdout-fd")) {
+                int fd;
+
+                if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+                        log_unit_debug(u, "Failed to parse stdout-fd value: %s", value);
+                else {
+                        asynchronous_close(s->stdout_fd);
+                        s->stdout_fd = fdset_remove(fds, fd);
+                }
+        } else if (streq(key, "stderr-fd")) {
+                int fd;
+
+                if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+                        log_unit_debug(u, "Failed to parse stderr-fd value: %s", value);
+                else {
+                        asynchronous_close(s->stderr_fd);
+                        s->stderr_fd = fdset_remove(fds, fd);
+                }
         } else
                 log_unit_debug(u, "Unknown serialization key: %s", key);