chiark / gitweb /
build-sys: prepare release v18
[elogind.git] / src / service.c
index 431bccc4e1ad5bcb0ec7bd99310f70df2ad22f6b..e928d1a5e0050fd533fdd2bbb64b27756bf06229 100644 (file)
@@ -34,6 +34,7 @@
 #include "dbus-service.h"
 #include "special.h"
 #include "bus-errors.h"
+#include "exit-status.h"
 
 #define COMMENTS "#;\n"
 #define NEWLINES "\n\r"
@@ -117,8 +118,11 @@ static void service_init(Unit *u) {
         s->sysv_start_priority = -1;
 #endif
         s->socket_fd = -1;
+        s->guess_main_pid = true;
 
         exec_context_init(&s->exec_context);
+        s->exec_context.std_output = u->meta.manager->default_std_output;
+        s->exec_context.std_error = u->meta.manager->default_std_error;
 
         RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5);
 
@@ -210,6 +214,7 @@ static void service_done(Unit *u) {
         exec_context_done(&s->exec_context);
         exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
         s->control_command = NULL;
+        s->main_command = NULL;
 
         /* This will leak a process, but at least no memory or any of
          * our resources */
@@ -814,7 +819,7 @@ static int service_load_sysv_path(Service *s, const char *path) {
         s->restart = SERVICE_RESTART_NO;
         s->exec_context.std_output =
                 (s->meta.manager->sysv_console || s->exec_context.std_input == EXEC_INPUT_TTY)
-                ? EXEC_OUTPUT_TTY : EXEC_OUTPUT_NULL;
+                ? EXEC_OUTPUT_TTY : s->meta.manager->default_std_output;
         s->exec_context.kill_mode = KILL_PROCESS_GROUP;
 
         /* We use the long description only if
@@ -1028,6 +1033,12 @@ static int service_verify(Service *s) {
                 return -EINVAL;
         }
 
+        if (s->type == SERVICE_ONESHOT &&
+            s->exec_command[SERVICE_EXEC_RELOAD]) {
+                log_error("%s has an ExecReload setting, which is not allowed for Type=oneshot services. Refusing.", s->meta.id);
+                return -EINVAL;
+        }
+
         if (s->type == SERVICE_DBUS && !s->bus_name) {
                 log_error("%s is of type D-Bus but no D-Bus service name has been specified. Refusing.", s->meta.id);
                 return -EINVAL;
@@ -1143,6 +1154,7 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
                 "%sPermissionsStartOnly: %s\n"
                 "%sRootDirectoryStartOnly: %s\n"
                 "%sRemainAfterExit: %s\n"
+                "%sGuessMainPID: %s\n"
                 "%sType: %s\n"
                 "%sRestart: %s\n"
                 "%sNotifyAccess: %s\n",
@@ -1150,6 +1162,7 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
                 prefix, yes_no(s->permissions_start_only),
                 prefix, yes_no(s->root_directory_start_only),
                 prefix, yes_no(s->remain_after_exit),
+                prefix, yes_no(s->guess_main_pid),
                 prefix, service_type_to_string(s->type),
                 prefix, service_restart_to_string(s->restart),
                 prefix, notify_access_to_string(s->notify_access));
@@ -1228,11 +1241,6 @@ static int service_load_pid_file(Service *s) {
 
         assert(s);
 
-        if (s->main_pid_known)
-                return 0;
-
-        assert(s->main_pid <= 0);
-
         if (!s->pid_file)
                 return -ENOENT;
 
@@ -1267,9 +1275,14 @@ static int service_search_main_pid(Service *s) {
 
         assert(s);
 
+        /* If we know it anyway, don't ever fallback to unreliable
+         * heuristics */
         if (s->main_pid_known)
                 return 0;
 
+        if (!s->guess_main_pid)
+                return 0;
+
         assert(s->main_pid <= 0);
 
         if ((pid = cgroup_bonding_search_main_pid_list(s->meta.cgroup_bondings)) <= 0)
@@ -1393,8 +1406,10 @@ static void service_set_state(Service *s, ServiceState state) {
             state != SERVICE_RELOAD &&
             state != SERVICE_STOP &&
             state != SERVICE_STOP_SIGTERM &&
-            state != SERVICE_STOP_SIGKILL)
+            state != SERVICE_STOP_SIGKILL) {
                 service_unwatch_main_pid(s);
+                s->main_command = NULL;
+        }
 
         if (state != SERVICE_START_PRE &&
             state != SERVICE_START &&
@@ -1775,8 +1790,9 @@ static void service_enter_stop_post(Service *s, bool success) {
 
         service_unwatch_control_pid(s);
 
-        s->control_command_id = SERVICE_EXEC_STOP_POST;
         if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST])) {
+                s->control_command_id = SERVICE_EXEC_STOP_POST;
+
                 if ((r = service_spawn(s,
                                        s->control_command,
                                        true,
@@ -1894,8 +1910,9 @@ static void service_enter_stop(Service *s, bool success) {
 
         service_unwatch_control_pid(s);
 
-        s->control_command_id = SERVICE_EXEC_STOP;
         if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP])) {
+                s->control_command_id = SERVICE_EXEC_STOP;
+
                 if ((r = service_spawn(s,
                                        s->control_command,
                                        true,
@@ -1943,8 +1960,9 @@ static void service_enter_start_post(Service *s) {
 
         service_unwatch_control_pid(s);
 
-        s->control_command_id = SERVICE_EXEC_START_POST;
         if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) {
+                s->control_command_id = SERVICE_EXEC_START_POST;
+
                 if ((r = service_spawn(s,
                                        s->control_command,
                                        true,
@@ -1970,6 +1988,7 @@ fail:
 static void service_enter_start(Service *s) {
         pid_t pid;
         int r;
+        ExecCommand *c;
 
         assert(s);
 
@@ -1981,11 +2000,20 @@ static void service_enter_start(Service *s) {
         else
                 service_unwatch_main_pid(s);
 
-        s->control_command_id = SERVICE_EXEC_START;
-        s->control_command = s->exec_command[SERVICE_EXEC_START];
+        if (s->type == SERVICE_FORKING) {
+                s->control_command_id = SERVICE_EXEC_START;
+                c = s->control_command = s->exec_command[SERVICE_EXEC_START];
+
+                s->main_command = NULL;
+        } else {
+                s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
+                s->control_command = NULL;
+
+                c = s->main_command = s->exec_command[SERVICE_EXEC_START];
+        }
 
         if ((r = service_spawn(s,
-                               s->control_command,
+                               c,
                                s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY,
                                true,
                                true,
@@ -2040,8 +2068,9 @@ static void service_enter_start_pre(Service *s) {
 
         service_unwatch_control_pid(s);
 
-        s->control_command_id = SERVICE_EXEC_START_PRE;
         if ((s->control_command = s->exec_command[SERVICE_EXEC_START_PRE])) {
+                s->control_command_id = SERVICE_EXEC_START_PRE;
+
                 if ((r = service_spawn(s,
                                        s->control_command,
                                        true,
@@ -2100,8 +2129,9 @@ static void service_enter_reload(Service *s) {
 
         service_unwatch_control_pid(s);
 
-        s->control_command_id = SERVICE_EXEC_RELOAD;
         if ((s->control_command = s->exec_command[SERVICE_EXEC_RELOAD])) {
+                s->control_command_id = SERVICE_EXEC_RELOAD;
+
                 if ((r = service_spawn(s,
                                        s->control_command,
                                        true,
@@ -2175,20 +2205,18 @@ static void service_run_next_main(Service *s, bool success) {
         int r;
 
         assert(s);
-        assert(s->control_command);
-        assert(s->control_command->command_next);
+        assert(s->main_command);
+        assert(s->main_command->command_next);
+        assert(s->type == SERVICE_ONESHOT);
 
         if (!success)
                 s->failure = true;
 
-        assert(s->control_command_id == SERVICE_EXEC_START);
-        assert(s->type == SERVICE_ONESHOT);
-
-        s->control_command = s->control_command->command_next;
+        s->main_command = s->main_command->command_next;
         service_unwatch_main_pid(s);
 
         if ((r = service_spawn(s,
-                               s->control_command,
+                               s->main_command,
                                false,
                                true,
                                true,
@@ -2503,10 +2531,14 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                 s->main_pid = 0;
                 exec_status_exit(&s->main_exec_status, pid, code, status, s->exec_context.utmp_id);
 
-                if (s->type != SERVICE_FORKING && s->control_command) {
-                        s->control_command->exec_status = s->main_exec_status;
+                /* If this is not a forking service than the main
+                 * process got started and hence we copy the exit
+                 * status so that it is recorded both as main and as
+                 * control process exit status */
+                if (s->main_command) {
+                        s->main_command->exec_status = s->main_exec_status;
 
-                        if (s->control_command->ignore)
+                        if (s->main_command->ignore)
                                 success = true;
                 }
 
@@ -2514,8 +2546,8 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                          "%s: main process exited, code=%s, status=%i", u->meta.id, sigchld_code_to_string(code), status);
                 s->failure = s->failure || !success;
 
-                if (s->control_command &&
-                    s->control_command->command_next &&
+                if (s->main_command &&
+                    s->main_command->command_next &&
                     success) {
 
                         /* There is another command to *
@@ -2528,9 +2560,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
 
                         /* The service exited, so the service is officially
                          * gone. */
-
-                        s->control_command = NULL;
-                        s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
+                        s->main_command = NULL;
 
                         switch (s->state) {
 
@@ -2649,9 +2679,16 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                                                 log_warning("%s: failed to load PID file %s: %s", s->meta.id, s->pid_file, strerror(-r));
                                 }
 
-                                /* Fall through */
+                                s->reload_failure = !success;
+                                service_enter_running(s, true);
+                                break;
 
                         case SERVICE_RELOAD:
+                                if (success) {
+                                        service_load_pid_file(s);
+                                        service_search_main_pid(s);
+                                }
+
                                 s->reload_failure = !success;
                                 service_enter_running(s, true);
                                 break;