chiark / gitweb /
core: move ManagerRunningAs to shared
[elogind.git] / src / core / service.c
index bf2e0a9d98f99979b8881f6209a20f3727635b72..7c79dcdd148c8f1a1d7432c48b5a82d43906a2ce 100644 (file)
@@ -6,16 +6,16 @@
   Copyright 2010 Lennart Poettering
 
   systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
   (at your option) any later version.
 
   systemd is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  General Public License for more details.
+  Lesser General Public License for more details.
 
-  You should have received a copy of the GNU General Public License
+  You should have received a copy of the GNU Lesser General Public License
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
 #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"
 #include "exit-status.h"
 #include "def.h"
+#include "path-util.h"
 #include "util.h"
 #include "utf8.h"
 
@@ -107,14 +109,36 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
         [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING
 };
 
+/* For Type=idle we never want to delay any other jobs, hence we
+ * consider idle jobs active as soon as we start working on them */
+static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] = {
+        [SERVICE_DEAD] = UNIT_INACTIVE,
+        [SERVICE_START_PRE] = UNIT_ACTIVE,
+        [SERVICE_START] = UNIT_ACTIVE,
+        [SERVICE_START_POST] = UNIT_ACTIVE,
+        [SERVICE_RUNNING] = UNIT_ACTIVE,
+        [SERVICE_EXITED] = UNIT_ACTIVE,
+        [SERVICE_RELOAD] = UNIT_RELOADING,
+        [SERVICE_STOP] = UNIT_DEACTIVATING,
+        [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
+        [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
+        [SERVICE_STOP_POST] = UNIT_DEACTIVATING,
+        [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
+        [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
+        [SERVICE_FAILED] = UNIT_FAILED,
+        [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING
+};
+
 static void service_init(Unit *u) {
         Service *s = SERVICE(u);
 
         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;
 
         s->watchdog_watch.type = WATCH_INVALID;
 
@@ -127,6 +151,7 @@ static void service_init(Unit *u) {
         s->guess_main_pid = true;
 
         exec_context_init(&s->exec_context);
+        kill_context_init(&s->kill_context);
 
         RATELIMIT_INIT(s->start_limit, 10*USEC_PER_SEC, 5);
 
@@ -258,9 +283,6 @@ static void service_done(Unit *u) {
         s->pid_file = NULL;
 
 #ifdef HAVE_SYSV_COMPAT
-        free(s->sysv_path);
-        s->sysv_path = NULL;
-
         free(s->sysv_runlevels);
         s->sysv_runlevels = NULL;
 #endif
@@ -273,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);
@@ -498,17 +530,21 @@ static int sysv_exec_commands(Service *s) {
         ExecCommand *c;
 
         assert(s);
-        assert(s->sysv_path);
+        assert(s->is_sysv);
+        assert(UNIT(s)->source_path);
 
-        if (!(c = exec_command_new(s->sysv_path, "start")))
+        c = exec_command_new(UNIT(s)->source_path, "start");
+        if (!c)
                 return -ENOMEM;
         exec_command_append_list(s->exec_command+SERVICE_EXEC_START, c);
 
-        if (!(c = exec_command_new(s->sysv_path, "stop")))
+        c = exec_command_new(UNIT(s)->source_path, "stop");
+        if (!c)
                 return -ENOMEM;
         exec_command_append_list(s->exec_command+SERVICE_EXEC_STOP, c);
 
-        if (!(c = exec_command_new(s->sysv_path, "reload")))
+        c = exec_command_new(UNIT(s)->source_path, "reload");
+        if (!c)
                 return -ENOMEM;
         exec_command_append_list(s->exec_command+SERVICE_EXEC_RELOAD, c);
 
@@ -534,24 +570,24 @@ static int service_load_sysv_path(Service *s, const char *path) {
 
         u = UNIT(s);
 
-        if (!(f = fopen(path, "re"))) {
+        f = fopen(path, "re");
+        if (!f) {
                 r = errno == ENOENT ? 0 : -errno;
                 goto finish;
         }
 
-        zero(st);
         if (fstat(fileno(f), &st) < 0) {
                 r = -errno;
                 goto finish;
         }
 
-        free(s->sysv_path);
-        if (!(s->sysv_path = strdup(path))) {
+        free(u->source_path);
+        u->source_path = strdup(path);
+        if (!u->source_path) {
                 r = -ENOMEM;
                 goto finish;
         }
-
-        s->sysv_mtime = timespec_load(&st.st_mtim);
+        u->source_mtime = timespec_load(&st.st_mtim);
 
         if (null_or_empty(&st)) {
                 u->load_state = UNIT_MASKED;
@@ -559,6 +595,8 @@ static int service_load_sysv_path(Service *s, const char *path) {
                 goto finish;
         }
 
+        s->is_sysv = true;
+
         while (!feof(f)) {
                 char l[LINE_MAX], *t;
 
@@ -692,7 +730,7 @@ static int service_load_sysv_path(Service *s, const char *path) {
                                 char *d = NULL;
 
                                 if (chkconfig_description)
-                                        d = join(chkconfig_description, " ", j, NULL);
+                                        d = strjoin(chkconfig_description, " ", j, NULL);
                                 else
                                         d = strdup(j);
 
@@ -721,7 +759,7 @@ static int service_load_sysv_path(Service *s, const char *path) {
                                                 goto finish;
                                         }
 
-                                        r = sysv_translate_facility(n, file_name_from_path(path), &m);
+                                        r = sysv_translate_facility(n, path_get_file_name(path), &m);
                                         free(n);
 
                                         if (r < 0)
@@ -771,7 +809,7 @@ static int service_load_sysv_path(Service *s, const char *path) {
                                                 goto finish;
                                         }
 
-                                        r = sysv_translate_facility(n, file_name_from_path(path), &m);
+                                        r = sysv_translate_facility(n, path_get_file_name(path), &m);
 
                                         if (r < 0) {
                                                 log_error("[%s:%u] Failed to translate LSB dependency %s, ignoring: %s", path, line, n, strerror(-r));
@@ -849,7 +887,7 @@ static int service_load_sysv_path(Service *s, const char *path) {
                                                 char *d = NULL;
 
                                                 if (long_description)
-                                                        d = join(long_description, " ", t, NULL);
+                                                        d = strjoin(long_description, " ", t, NULL);
                                                 else
                                                         d = strdup(j);
 
@@ -888,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;
@@ -898,11 +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;
-
-        if (UNIT(s)->manager->sysv_console)
-                s->exec_context.std_output = EXEC_OUTPUT_JOURNAL_AND_CONSOLE;
-
-        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. */
@@ -975,7 +1012,7 @@ static int service_load_sysv_name(Service *s, const char *name) {
                 char *path;
                 int r;
 
-                path = join(*p, "/", name, NULL);
+                path = strjoin(*p, "/", name, NULL);
                 if (!path)
                         return -ENOMEM;
 
@@ -997,7 +1034,7 @@ static int service_load_sysv_name(Service *s, const char *name) {
                 if (r >= 0 && UNIT(s)->load_state == UNIT_STUB) {
                         /* Try SUSE style boot.* init scripts */
 
-                        path = join(*p, "/boot.", name, NULL);
+                        path = strjoin(*p, "/boot.", name, NULL);
                         if (!path)
                                 return -ENOMEM;
 
@@ -1012,7 +1049,7 @@ static int service_load_sysv_name(Service *s, const char *name) {
                 if (r >= 0 && UNIT(s)->load_state == UNIT_STUB) {
                         /* Try Frugalware style rc.* init scripts */
 
-                        path = join(*p, "/rc.", name, NULL);
+                        path = strjoin(*p, "/rc.", name, NULL);
                         if (!path)
                                 return -ENOMEM;
 
@@ -1135,7 +1172,10 @@ static int service_verify(Service *s) {
                 return -EINVAL;
         }
 
-        if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) {
+        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->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;
         }
@@ -1152,12 +1192,12 @@ static int service_add_default_dependencies(Service *s) {
          * majority of services. */
 
         /* First, pull in base system */
-        if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
+        if (UNIT(s)->manager->running_as == SYSTEMD_SYSTEM) {
 
                 if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
                         return r;
 
-        } else if (UNIT(s)->manager->running_as == MANAGER_USER) {
+        } else if (UNIT(s)->manager->running_as == SYSTEMD_USER) {
 
                 if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SOCKETS_TARGET, NULL, true)) < 0)
                         return r;
@@ -1213,6 +1253,13 @@ static int service_load(Unit *u) {
 
         /* This is a new unit? Then let's add in some extras */
         if (u->load_state == UNIT_LOADED) {
+                if (s->type == _SERVICE_TYPE_INVALID)
+                        s->type = s->bus_name ? SERVICE_DBUS : SERVICE_SIMPLE;
+
+                /* 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);
 
                 if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
@@ -1246,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);
@@ -1311,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++) {
@@ -1325,12 +1377,10 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
         }
 
 #ifdef HAVE_SYSV_COMPAT
-        if (s->sysv_path)
+        if (s->is_sysv)
                 fprintf(f,
-                        "%sSysV Init Script Path: %s\n"
                         "%sSysV Init Script has LSB Header: %s\n"
                         "%sSysVEnabled: %s\n",
-                        prefix, s->sysv_path,
                         prefix, yes_no(s->sysv_has_lsb),
                         prefix, yes_no(s->sysv_enabled));
 
@@ -1457,8 +1507,11 @@ static void service_notify_sockets_dead(Service *s, bool failed_permanent) {
 
 static void service_set_state(Service *s, ServiceState state) {
         ServiceState old_state;
+        const UnitActiveState *table;
         assert(s);
 
+        table = s->type == SERVICE_IDLE ? state_translation_table_idle : state_translation_table;
+
         old_state = s->state;
         s->state = state;
 
@@ -1541,7 +1594,7 @@ static void service_set_state(Service *s, ServiceState state) {
         if (old_state != state)
                 log_debug("%s changed %s -> %s", UNIT(s)->id, service_state_to_string(old_state), service_state_to_string(state));
 
-        unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], s->reload_result == SERVICE_SUCCESS);
+        unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS);
         s->reload_result = SERVICE_SUCCESS;
 }
 
@@ -1565,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;
@@ -1686,6 +1738,7 @@ static int service_spawn(
                 bool apply_chroot,
                 bool apply_tty_stdin,
                 bool set_notify_socket,
+                bool is_control,
                 pid_t *_pid) {
 
         pid_t pid;
@@ -1714,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);
@@ -1767,6 +1821,9 @@ static int service_spawn(
                        UNIT(s)->manager->confirm_spawn,
                        UNIT(s)->cgroup_bondings,
                        UNIT(s)->cgroup_attributes,
+                       is_control ? "control" : NULL,
+                       UNIT(s)->id,
+                       s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL,
                        &pid);
 
         if (r < 0)
@@ -1847,21 +1904,27 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
         if (f != SERVICE_SUCCESS)
                 s->result = f;
 
+        service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
+
         if (allow_restart &&
             !s->forbid_restart &&
             (s->restart == SERVICE_RESTART_ALWAYS ||
              (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)
                         goto fail;
 
                 service_set_state(s, SERVICE_AUTO_RESTART);
-        } else
-                service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
+        }
 
         s->forbid_restart = false;
 
@@ -1886,15 +1949,17 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
         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,
-                                       false,
-                                       !s->permissions_start_only,
-                                       !s->root_directory_start_only,
-                                       true,
-                                       false,
-                                       &s->control_pid)) < 0)
+                r = service_spawn(s,
+                                  s->control_command,
+                                  true,
+                                  false,
+                                  !s->permissions_start_only,
+                                  !s->root_directory_start_only,
+                                  true,
+                                  false,
+                                  true,
+                                  &s->control_pid);
+                if (r < 0)
                         goto fail;
 
 
@@ -1919,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)
@@ -1936,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;
                         }
@@ -1952,7 +2018,8 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
                                 if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0)
                                         goto fail;
 
-                        if ((r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, pid_set)) < 0) {
+                        r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, false, pid_set, NULL);
+                        if (r < 0) {
                                 if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
                                         log_warning("Failed to kill control group: %s", strerror(-r));
                         } else if (r > 0)
@@ -1964,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)
@@ -2001,15 +2070,17 @@ static void service_enter_stop(Service *s, ServiceResult f) {
         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,
-                                       false,
-                                       !s->permissions_start_only,
-                                       !s->root_directory_start_only,
-                                       false,
-                                       false,
-                                       &s->control_pid)) < 0)
+                r = service_spawn(s,
+                                  s->control_command,
+                                  true,
+                                  false,
+                                  !s->permissions_start_only,
+                                  !s->root_directory_start_only,
+                                  false,
+                                  false,
+                                  true,
+                                  &s->control_pid);
+                if (r < 0)
                         goto fail;
 
                 service_set_state(s, SERVICE_STOP);
@@ -2054,15 +2125,17 @@ static void service_enter_start_post(Service *s) {
         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,
-                                       false,
-                                       !s->permissions_start_only,
-                                       !s->root_directory_start_only,
-                                       false,
-                                       false,
-                                       &s->control_pid)) < 0)
+                r = service_spawn(s,
+                                  s->control_command,
+                                  true,
+                                  false,
+                                  !s->permissions_start_only,
+                                  !s->root_directory_start_only,
+                                  false,
+                                  false,
+                                  true,
+                                  &s->control_pid);
+                if (r < 0)
                         goto fail;
 
                 service_set_state(s, SERVICE_START_POST);
@@ -2094,7 +2167,7 @@ static void service_enter_start(Service *s) {
         /* We want to ensure that nobody leaks processes from
          * START_PRE here, so let's go on a killing spree, People
          * should not spawn long running processes from START_PRE. */
-        cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, NULL);
+        cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, true, NULL, "control");
 
         if (s->type == SERVICE_FORKING) {
                 s->control_command_id = SERVICE_EXEC_START;
@@ -2108,18 +2181,20 @@ static void service_enter_start(Service *s) {
                 c = s->main_command = s->exec_command[SERVICE_EXEC_START];
         }
 
-        if ((r = service_spawn(s,
-                               c,
-                               s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY,
-                               true,
-                               true,
-                               true,
-                               true,
-                               s->notify_access != NOTIFY_NONE,
-                               &pid)) < 0)
+        r = service_spawn(s,
+                          c,
+                          s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY || s->type == SERVICE_ONESHOT,
+                          true,
+                          true,
+                          true,
+                          true,
+                          s->notify_access != NOTIFY_NONE,
+                          false,
+                          &pid);
+        if (r < 0)
                 goto fail;
 
-        if (s->type == SERVICE_SIMPLE) {
+        if (s->type == SERVICE_SIMPLE || s->type == SERVICE_IDLE) {
                 /* For simple services we immediately start
                  * the START_POST binaries. */
 
@@ -2168,19 +2243,21 @@ static void service_enter_start_pre(Service *s) {
 
                 /* Before we start anything, let's clear up what might
                  * be left from previous runs. */
-                cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, NULL);
+                cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, true, NULL, "control");
 
                 s->control_command_id = SERVICE_EXEC_START_PRE;
 
-                if ((r = service_spawn(s,
-                                       s->control_command,
-                                       true,
-                                       false,
-                                       !s->permissions_start_only,
-                                       !s->root_directory_start_only,
-                                       true,
-                                       false,
-                                       &s->control_pid)) < 0)
+                r = service_spawn(s,
+                                  s->control_command,
+                                  true,
+                                  false,
+                                  !s->permissions_start_only,
+                                  !s->root_directory_start_only,
+                                  true,
+                                  false,
+                                  true,
+                                  &s->control_pid);
+                if (r < 0)
                         goto fail;
 
                 service_set_state(s, SERVICE_START_PRE);
@@ -2201,11 +2278,15 @@ 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;
         }
 
         /* Any units that are bound to this service must also be
@@ -2216,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;
 
@@ -2236,15 +2321,17 @@ static void service_enter_reload(Service *s) {
         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,
-                                       false,
-                                       !s->permissions_start_only,
-                                       !s->root_directory_start_only,
-                                       false,
-                                       false,
-                                       &s->control_pid)) < 0)
+                r = service_spawn(s,
+                                  s->control_command,
+                                  true,
+                                  false,
+                                  !s->permissions_start_only,
+                                  !s->root_directory_start_only,
+                                  false,
+                                  false,
+                                  true,
+                                  &s->control_pid);
+                if (r < 0)
                         goto fail;
 
                 service_set_state(s, SERVICE_RELOAD);
@@ -2271,16 +2358,18 @@ static void service_run_next_control(Service *s) {
         s->control_command = s->control_command->command_next;
         service_unwatch_control_pid(s);
 
-        if ((r = service_spawn(s,
-                               s->control_command,
-                               true,
-                               false,
-                               !s->permissions_start_only,
-                               !s->root_directory_start_only,
-                               s->control_command_id == SERVICE_EXEC_START_PRE ||
-                               s->control_command_id == SERVICE_EXEC_STOP_POST,
-                               false,
-                               &s->control_pid)) < 0)
+        r = service_spawn(s,
+                          s->control_command,
+                          true,
+                          false,
+                          !s->permissions_start_only,
+                          !s->root_directory_start_only,
+                          s->control_command_id == SERVICE_EXEC_START_PRE ||
+                          s->control_command_id == SERVICE_EXEC_STOP_POST,
+                          false,
+                          true,
+                          &s->control_pid);
+        if (r < 0)
                 goto fail;
 
         return;
@@ -2313,15 +2402,17 @@ static void service_run_next_main(Service *s) {
         s->main_command = s->main_command->command_next;
         service_unwatch_main_pid(s);
 
-        if ((r = service_spawn(s,
-                               s->main_command,
-                               false,
-                               true,
-                               true,
-                               true,
-                               true,
-                               s->notify_access != NOTIFY_NONE,
-                               &pid)) < 0)
+        r = service_spawn(s,
+                          s->main_command,
+                          true,
+                          true,
+                          true,
+                          true,
+                          true,
+                          s->notify_access != NOTIFY_NONE,
+                          false,
+                          &pid);
+        if (r < 0)
                 goto fail;
 
         service_set_main_pid(s, pid);
@@ -2402,12 +2493,22 @@ static int service_start(Unit *u) {
             s->state == SERVICE_START_POST)
                 return 0;
 
-        assert(s->state == SERVICE_DEAD || s->state == SERVICE_FAILED || s->state == SERVICE_AUTO_RESTART);
+        /* A service that will be restarted must be stopped first to
+         * 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. 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;
         }
 
@@ -2426,8 +2527,7 @@ static int service_stop(Unit *u) {
 
         assert(s);
 
-        /* This is a user request, so don't do restarts on this
-         * shutdown. */
+        /* Don't create restart jobs from here. */
         s->forbid_restart = true;
 
         /* Already on it */
@@ -2439,7 +2539,7 @@ static int service_stop(Unit *u) {
             s->state == SERVICE_FINAL_SIGKILL)
                 return 0;
 
-        /* Don't allow a restart */
+        /* A restart will be scheduled or is in progress. */
         if (s->state == SERVICE_AUTO_RESTART) {
                 service_set_state(s, SERVICE_DEAD);
                 return 0;
@@ -2650,9 +2750,13 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
 }
 
 static UnitActiveState service_active_state(Unit *u) {
+        const UnitActiveState *table;
+
         assert(u);
 
-        return state_translation_table[SERVICE(u)->state];
+        table = SERVICE(u)->type == SERVICE_IDLE ? state_translation_table_idle : state_translation_table;
+
+        return table[SERVICE(u)->state];
 }
 
 static const char *service_sub_state_to_string(Unit *u) {
@@ -2674,7 +2778,7 @@ static bool service_check_gc(Unit *u) {
                 return true;
 
 #ifdef HAVE_SYSV_COMPAT
-        if (s->sysv_path)
+        if (s->is_sysv)
                 return true;
 #endif
 
@@ -2785,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;
@@ -2856,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;
@@ -2897,6 +3000,11 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                 if (f != SERVICE_SUCCESS)
                         s->result = f;
 
+                /* Immediately get rid of the cgroup, so that the
+                 * kernel doesn't delay the cgroup empty messages for
+                 * the service cgroup any longer than necessary */
+                cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, true, NULL, "control");
+
                 if (s->control_command &&
                     s->control_command->command_next &&
                     f == SERVICE_SUCCESS) {
@@ -2926,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);
@@ -3055,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 {
@@ -3080,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 {
@@ -3150,7 +3260,7 @@ static void service_cgroup_notify_event(Unit *u) {
         case SERVICE_FINAL_SIGTERM:
         case SERVICE_FINAL_SIGKILL:
                 if (main_pid_good(s) <= 0 && !control_pid_good(s))
-                        service_enter_dead(s, SERVICE_SUCCESS, SERVICE_SUCCESS);
+                        service_enter_dead(s, SERVICE_SUCCESS, true);
 
                 break;
 
@@ -3319,7 +3429,7 @@ static int service_enumerate(Manager *m) {
 
         assert(m);
 
-        if (m->running_as != MANAGER_SYSTEM)
+        if (m->running_as != SYSTEMD_SYSTEM)
                 return 0;
 
         zero(runlevel_services);
@@ -3329,7 +3439,7 @@ static int service_enumerate(Manager *m) {
                         struct dirent *de;
 
                         free(path);
-                        path = join(*p, "/", rcnd_table[i].path, NULL);
+                        path = strjoin(*p, "/", rcnd_table[i].path, NULL);
                         if (!path) {
                                 r = -ENOMEM;
                                 goto finish;
@@ -3364,7 +3474,7 @@ static int service_enumerate(Manager *m) {
                                         continue;
 
                                 free(fpath);
-                                fpath = join(path, "/", de->d_name, NULL);
+                                fpath = strjoin(path, "/", de->d_name, NULL);
                                 if (!fpath) {
                                         r = -ENOMEM;
                                         goto finish;
@@ -3577,32 +3687,11 @@ static void service_reset_failed(Unit *u) {
 
         s->result = SERVICE_SUCCESS;
         s->reload_result = SERVICE_SUCCESS;
-}
 
-static bool service_need_daemon_reload(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-#ifdef HAVE_SYSV_COMPAT
-        if (s->sysv_path) {
-                struct stat st;
-
-                zero(st);
-                if (stat(s->sysv_path, &st) < 0)
-                        /* What, cannot access this anymore? */
-                        return true;
-
-                if (s->sysv_mtime > 0 &&
-                    timespec_load(&st.st_mtim) != s->sysv_mtime)
-                        return true;
-        }
-#endif
-
-        return false;
+        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;
@@ -3629,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;
                         }
+                }
 
-                if ((q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, pid_set)) < 0)
-                        if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
-                                r = q;
+                q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, false, pid_set, NULL);
+                if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
+                        r = q;
         }
 
 finish:
@@ -3695,7 +3789,8 @@ static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
         [SERVICE_FORKING] = "forking",
         [SERVICE_ONESHOT] = "oneshot",
         [SERVICE_DBUS] = "dbus",
-        [SERVICE_NOTIFY] = "notify"
+        [SERVICE_NOTIFY] = "notify",
+        [SERVICE_IDLE] = "idle"
 };
 
 DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
@@ -3726,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);
@@ -3740,13 +3836,13 @@ static const char* const start_limit_action_table[_SERVICE_START_LIMIT_MAX] = {
 DEFINE_STRING_TABLE_LOOKUP(start_limit_action, StartLimitAction);
 
 const UnitVTable service_vtable = {
-        .suffix = ".service",
         .object_size = sizeof(Service),
+        .exec_context_offset = offsetof(Service, exec_context),
+
         .sections =
                 "Unit\0"
                 "Service\0"
                 "Install\0",
-        .show_status = true,
 
         .init = service_init,
         .done = service_done,
@@ -3779,8 +3875,6 @@ const UnitVTable service_vtable = {
 
         .reset_failed = service_reset_failed,
 
-        .need_daemon_reload = service_need_daemon_reload,
-
         .cgroup_notify_empty = service_cgroup_notify_event,
         .notify_message = service_notify_message,
 
@@ -3792,6 +3886,23 @@ const UnitVTable service_vtable = {
         .bus_invalidating_properties =  bus_service_invalidating_properties,
 
 #ifdef HAVE_SYSV_COMPAT
-        .enumerate = service_enumerate
+        .enumerate = service_enumerate,
 #endif
+        .status_message_formats = {
+                .starting_stopping = {
+                        [0] = "Starting %s...",
+                        [1] = "Stopping %s...",
+                },
+                .finished_start_job = {
+                        [JOB_DONE]       = "Started %s.",
+                        [JOB_FAILED]     = "Failed to start %s.",
+                        [JOB_DEPENDENCY] = "Dependency failed for %s.",
+                        [JOB_TIMEOUT]    = "Timed out starting %s.",
+                },
+                .finished_stop_job = {
+                        [JOB_DONE]       = "Stopped %s.",
+                        [JOB_FAILED]     = "Stopped (with error) %s.",
+                        [JOB_TIMEOUT]    = "Timed out stopping %s.",
+                },
+        },
 };