chiark / gitweb /
unit: split unit_printf() and friends into its own .c file
[elogind.git] / src / core / service.c
index 2be6ee5d99a992459cfdc0478d5add4c73928fb7..1e3e875c3fd36dde473baeef694733184537cb33 100644 (file)
@@ -33,6 +33,7 @@
 #include "log.h"
 #include "strv.h"
 #include "unit-name.h"
+#include "unit-printf.h"
 #include "dbus-service.h"
 #include "special.h"
 #include "bus-errors.h"
@@ -130,12 +131,12 @@ static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] =
 
 static void service_init(Unit *u) {
         Service *s = SERVICE(u);
-        int i;
 
         assert(u);
         assert(u->load_state == UNIT_STUB);
 
-        s->timeout_usec = DEFAULT_TIMEOUT_USEC;
+        s->timeout_start_usec = DEFAULT_TIMEOUT_USEC;
+        s->timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
         s->restart_usec = DEFAULT_RESTART_USEC;
         s->type = _SERVICE_TYPE_INVALID;
 
@@ -150,9 +151,7 @@ static void service_init(Unit *u) {
         s->guess_main_pid = true;
 
         exec_context_init(&s->exec_context);
-        for (i = 0; i < RLIMIT_NLIMITS; i++)
-                if (UNIT(s)->manager->rlimit[i])
-                        s->exec_context.rlimit[i] = newdup(struct rlimit, UNIT(s)->manager->rlimit[i], 1);
+        kill_context_init(&s->kill_context);
 
         RATELIMIT_INIT(s->start_limit, 10*USEC_PER_SEC, 5);
 
@@ -296,6 +295,16 @@ static void service_done(Unit *u) {
         s->control_command = NULL;
         s->main_command = NULL;
 
+        set_free(s->restart_ignore_status.code);
+        s->restart_ignore_status.code = NULL;
+        set_free(s->restart_ignore_status.signal);
+        s->restart_ignore_status.signal = NULL;
+
+        set_free(s->success_status.code);
+        s->success_status.code = NULL;
+        set_free(s->success_status.signal);
+        s->success_status.signal = NULL;
+
         /* This will leak a process, but at least no memory or any of
          * our resources */
         service_unwatch_main_pid(s);
@@ -567,7 +576,6 @@ static int service_load_sysv_path(Service *s, const char *path) {
                 goto finish;
         }
 
-        zero(st);
         if (fstat(fileno(f), &st) < 0) {
                 r = -errno;
                 goto finish;
@@ -918,9 +926,12 @@ static int service_load_sysv_path(Service *s, const char *path) {
                 UNIT(s)->default_dependencies = false;
 
                 /* Don't timeout special services during boot (like fsck) */
-                s->timeout_usec = 0;
-        } else
-                s->timeout_usec = DEFAULT_SYSV_TIMEOUT_USEC;
+                s->timeout_start_usec = 0;
+                s->timeout_stop_usec = 0;
+        } else {
+                s->timeout_start_usec = DEFAULT_SYSV_TIMEOUT_USEC;
+                s->timeout_stop_usec = DEFAULT_SYSV_TIMEOUT_USEC;
+        }
 
         /* Special setting for all SysV services */
         s->type = SERVICE_FORKING;
@@ -928,7 +939,7 @@ static int service_load_sysv_path(Service *s, const char *path) {
         s->guess_main_pid = false;
         s->restart = SERVICE_RESTART_NO;
         s->exec_context.ignore_sigpipe = false;
-        s->exec_context.kill_mode = KILL_PROCESS;
+        s->kill_context.kill_mode = KILL_PROCESS;
 
         /* We use the long description only if
          * no short description is set. */
@@ -1164,7 +1175,7 @@ static int service_verify(Service *s) {
         if (s->bus_name && s->type != SERVICE_DBUS)
                 log_warning("%s has a D-Bus service name specified, but is not of type dbus. Ignoring.", UNIT(s)->id);
 
-        if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) {
+        if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
                 log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id);
                 return -EINVAL;
         }
@@ -1245,9 +1256,9 @@ static int service_load(Unit *u) {
                 if (s->type == _SERVICE_TYPE_INVALID)
                         s->type = s->bus_name ? SERVICE_DBUS : SERVICE_SIMPLE;
 
-                /* Oneshot services have disabled timeout by default */
-                if (s->type == SERVICE_ONESHOT && !s->timeout_defined)
-                        s->timeout_usec = 0;
+                /* Oneshot services have disabled start timeout by default */
+                if (s->type == SERVICE_ONESHOT && !s->start_timeout_defined)
+                        s->timeout_start_usec = 0;
 
                 service_fix_output(s);
 
@@ -1282,6 +1293,10 @@ static int service_load(Unit *u) {
                 if (UNIT(s)->default_dependencies)
                         if ((r = service_add_default_dependencies(s)) < 0)
                                 return r;
+
+                r = unit_exec_context_defaults(u, &s->exec_context);
+                if (r < 0)
+                        return r;
         }
 
         return service_verify(s);
@@ -1347,6 +1362,7 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
                         prefix, s->bus_name,
                         prefix, yes_no(s->bus_name_good));
 
+        kill_context_dump(&s->kill_context, f, prefix);
         exec_context_dump(&s->exec_context, f, prefix);
 
         for (c = 0; c < _SERVICE_EXEC_COMMAND_MAX; c++) {
@@ -1602,11 +1618,10 @@ static int service_coldplug(Unit *u) {
                     s->deserialized_state == SERVICE_FINAL_SIGTERM ||
                     s->deserialized_state == SERVICE_FINAL_SIGKILL ||
                     s->deserialized_state == SERVICE_AUTO_RESTART) {
-
-                        if (s->deserialized_state == SERVICE_AUTO_RESTART || s->timeout_usec > 0) {
+                        if (s->deserialized_state == SERVICE_AUTO_RESTART || s->timeout_start_usec > 0) {
                                 usec_t k;
 
-                                k = s->deserialized_state == SERVICE_AUTO_RESTART ? s->restart_usec : s->timeout_usec;
+                                k = s->deserialized_state == SERVICE_AUTO_RESTART ? s->restart_usec : s->timeout_start_usec;
 
                                 if ((r = unit_watch_timer(UNIT(s), k, &s->timer_watch)) < 0)
                                         return r;
@@ -1752,8 +1767,9 @@ static int service_spawn(
                 }
         }
 
-        if (timeout && s->timeout_usec) {
-                if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
+        if (timeout && s->timeout_start_usec) {
+                r = unit_watch_timer(UNIT(s), s->timeout_start_usec, &s->timer_watch);
+                if (r < 0)
                         goto fail;
         } else
                 unit_unwatch_timer(UNIT(s), &s->timer_watch);
@@ -1896,7 +1912,12 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
              (s->restart == SERVICE_RESTART_ON_SUCCESS && s->result == SERVICE_SUCCESS) ||
              (s->restart == SERVICE_RESTART_ON_FAILURE && s->result != SERVICE_SUCCESS) ||
              (s->restart == SERVICE_RESTART_ON_ABORT && (s->result == SERVICE_FAILURE_SIGNAL ||
-                                                         s->result == SERVICE_FAILURE_CORE_DUMP)))) {
+                                                         s->result == SERVICE_FAILURE_CORE_DUMP))) &&
+            (s->result != SERVICE_FAILURE_EXIT_CODE ||
+             !set_contains(s->restart_ignore_status.code, INT_TO_PTR(s->main_exec_status.status))) &&
+            (s->result != SERVICE_FAILURE_SIGNAL ||
+             !set_contains(s->restart_ignore_status.signal, INT_TO_PTR(s->main_exec_status.status)))
+                ) {
 
                 r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch);
                 if (r < 0)
@@ -1963,8 +1984,8 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
         if (f != SERVICE_SUCCESS)
                 s->result = f;
 
-        if (s->exec_context.kill_mode != KILL_NONE) {
-                int sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? s->exec_context.kill_signal : SIGKILL;
+        if (s->kill_context.kill_mode != KILL_NONE) {
+                int sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? s->kill_context.kill_signal : SIGKILL;
 
                 if (s->main_pid > 0) {
                         if (kill_and_sigcont(s->main_pid, sig) < 0 && errno != ESRCH)
@@ -1980,9 +2001,10 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
                                 wait_for_exit = true;
                 }
 
-                if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) {
+                if (s->kill_context.kill_mode == KILL_CONTROL_GROUP) {
 
-                        if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
+                        pid_set = set_new(trivial_hash_func, trivial_compare_func);
+                        if (!pid_set) {
                                 r = -ENOMEM;
                                 goto fail;
                         }
@@ -2009,9 +2031,11 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
         }
 
         if (wait_for_exit) {
-                if (s->timeout_usec > 0)
-                        if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
+                if (s->timeout_stop_usec > 0) {
+                        r = unit_watch_timer(UNIT(s), s->timeout_stop_usec, &s->timer_watch);
+                        if (r < 0)
                                 goto fail;
+                }
 
                 service_set_state(s, state);
         } else if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL)
@@ -2254,10 +2278,12 @@ static void service_enter_restart(Service *s) {
         assert(s);
         dbus_error_init(&error);
 
-        if (UNIT(s)->job) {
-                log_info("Job pending for unit, delaying automatic restart.");
+        if (UNIT(s)->job && UNIT(s)->job->type == JOB_STOP) {
+                /* Don't restart things if we are going down anyway */
+                log_info("Stop job pending for unit, delaying automatic restart.");
 
-                if ((r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch)) < 0)
+                r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch);
+                if (r < 0)
                         goto fail;
 
                 return;
@@ -2271,6 +2297,10 @@ static void service_enter_restart(Service *s) {
         if (r < 0)
                 goto fail;
 
+        /* Note that we stay in the SERVICE_AUTO_RESTART state here,
+         * it will be canceled as part of the service_stop() call that
+         * is executed as part of JOB_RESTART. */
+
         log_debug("%s scheduled restart job.", UNIT(s)->id);
         return;
 
@@ -2464,20 +2494,21 @@ static int service_start(Unit *u) {
                 return 0;
 
         /* A service that will be restarted must be stopped first to
-         * trigger BindTo and/or OnFailure dependencies. If a user
+         * trigger BindsTo and/or OnFailure dependencies. If a user
          * does not want to wait for the holdoff time to elapse, the
-         * service should be manually restarted, not started. */
-        if (s->state == SERVICE_AUTO_RESTART) {
-                log_warning("%s automatic restart is pending, must be stopped before issuing start request.", UNIT(s)->id);
-                return -ECANCELED;
-        }
+         * service should be manually restarted, not started. We
+         * simply return EAGAIN here, so that any start jobs stay
+         * queued, and assume that the auto restart timer will
+         * eventually trigger the restart. */
+        if (s->state == SERVICE_AUTO_RESTART)
+                return -EAGAIN;
 
         assert(s->state == SERVICE_DEAD || s->state == SERVICE_FAILED);
 
         /* Make sure we don't enter a busy loop of some kind. */
         r = service_start_limit_test(s);
         if (r < 0) {
-                service_notify_sockets_dead(s, true);
+                service_enter_dead(s, SERVICE_FAILURE_START_LIMIT, false);
                 return r;
         }
 
@@ -2858,7 +2889,8 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         assert(s);
         assert(pid >= 0);
 
-        if (UNIT(s)->fragment_path ? is_clean_exit(code, status) : is_clean_exit_lsb(code, status))
+        if (UNIT(s)->fragment_path ? is_clean_exit(code, status, &s->success_status) :
+                                     is_clean_exit_lsb(code, status, &s->success_status))
                 f = SERVICE_SUCCESS;
         else if (code == CLD_EXITED)
                 f = SERVICE_FAILURE_EXIT_CODE;
@@ -2929,12 +2961,10 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                                         else
                                                 service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
                                         break;
-                                } else {
-                                        assert(s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY);
-
-                                        /* Fall through */
                                 }
 
+                                /* Fall through */
+
                         case SERVICE_RUNNING:
                                 service_enter_running(s, f);
                                 break;
@@ -3004,7 +3034,9 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                                 break;
 
                         case SERVICE_START:
-                                assert(s->type == SERVICE_FORKING);
+                                if (s->type != SERVICE_FORKING)
+                                        /* Maybe spurious event due to a reload that changed the type? */
+                                        break;
 
                                 if (f != SERVICE_SUCCESS) {
                                         service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
@@ -3133,7 +3165,7 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
                 break;
 
         case SERVICE_STOP_SIGTERM:
-                if (s->exec_context.send_sigkill) {
+                if (s->kill_context.send_sigkill) {
                         log_warning("%s stopping timed out. Killing.", u->id);
                         service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
                 } else {
@@ -3158,7 +3190,7 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
                 break;
 
         case SERVICE_FINAL_SIGTERM:
-                if (s->exec_context.send_sigkill) {
+                if (s->kill_context.send_sigkill) {
                         log_warning("%s stopping timed out (2). Killing.", u->id);
                         service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
                 } else {
@@ -3659,7 +3691,7 @@ static void service_reset_failed(Unit *u) {
         RATELIMIT_RESET(s->start_limit);
 }
 
-static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
+static int service_kill(Unit *u, KillWho who, int signo, DBusError *error) {
         Service *s = SERVICE(u);
         int r = 0;
         Set *pid_set = NULL;
@@ -3686,28 +3718,33 @@ static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusErro
                         if (kill(s->main_pid, signo) < 0)
                                 r = -errno;
 
-        if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) {
+        if (who == KILL_ALL) {
                 int q;
 
-                if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
+                pid_set = set_new(trivial_hash_func, trivial_compare_func);
+                if (!pid_set)
                         return -ENOMEM;
 
                 /* Exclude the control/main pid from being killed via the cgroup */
-                if (s->control_pid > 0)
-                        if ((q = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) {
+                if (s->control_pid > 0) {
+                        q = set_put(pid_set, LONG_TO_PTR(s->control_pid));
+                        if (q < 0) {
                                 r = q;
                                 goto finish;
                         }
+                }
 
-                if (s->main_pid > 0)
-                        if ((q = set_put(pid_set, LONG_TO_PTR(s->main_pid))) < 0) {
+                if (s->main_pid > 0) {
+                        q = set_put(pid_set, LONG_TO_PTR(s->main_pid));
+                        if (q < 0) {
                                 r = q;
                                 goto finish;
                         }
+                }
+
                 q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, false, pid_set, NULL);
-                if (q < 0)
-                        if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
-                                r = q;
+                if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
+                        r = q;
         }
 
 finish:
@@ -3784,7 +3821,8 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = {
         [SERVICE_FAILURE_EXIT_CODE] = "exit-code",
         [SERVICE_FAILURE_SIGNAL] = "signal",
         [SERVICE_FAILURE_CORE_DUMP] = "core-dump",
-        [SERVICE_FAILURE_WATCHDOG] = "watchdog"
+        [SERVICE_FAILURE_WATCHDOG] = "watchdog",
+        [SERVICE_FAILURE_START_LIMIT] = "start-limit"
 };
 
 DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);