chiark / gitweb /
service: don't print a warning if we are in autorestart state, and can't start a...
[elogind.git] / src / core / service.c
index 4f0375465986680f6be34e911f7e712b327dbaed..5dc06b36cc221948b61343aa2a31643b6627ae59 100644 (file)
@@ -108,6 +108,26 @@ 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);
         int i;
@@ -264,9 +284,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
@@ -504,17 +521,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);
 
@@ -540,7 +561,8 @@ 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;
         }
@@ -551,13 +573,13 @@ static int service_load_sysv_path(Service *s, const char *path) {
                 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;
@@ -565,6 +587,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;
 
@@ -698,7 +722,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);
 
@@ -855,7 +879,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);
 
@@ -904,10 +928,6 @@ 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;
 
         /* We use the long description only if
@@ -981,7 +1001,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;
 
@@ -1003,7 +1023,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;
 
@@ -1018,7 +1038,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;
 
@@ -1225,6 +1245,10 @@ 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;
+
                 service_fix_output(s);
 
                 if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
@@ -1258,6 +1282,10 @@ static int service_load(Unit *u) {
                 if (UNIT(s)->default_dependencies)
                         if ((r = service_add_default_dependencies(s)) < 0)
                                 return r;
+
+                r = unit_patch_working_directory(UNIT(s), &s->exec_context);
+                if (r < 0)
+                        return r;
         }
 
         return service_verify(s);
@@ -1337,12 +1365,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));
 
@@ -1469,8 +1495,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;
 
@@ -1553,7 +1582,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;
 }
 
@@ -1781,6 +1810,7 @@ static int service_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);
 
@@ -1862,6 +1892,8 @@ 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 ||
@@ -1875,8 +1907,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
                         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;
 
@@ -2132,7 +2163,7 @@ static void service_enter_start(Service *s) {
 
         r = service_spawn(s,
                           c,
-                          s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY,
+                          s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY || s->type == SERVICE_ONESHOT,
                           true,
                           true,
                           true,
@@ -2227,10 +2258,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;
@@ -2244,6 +2277,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;
 
@@ -2347,7 +2384,7 @@ static void service_run_next_main(Service *s) {
 
         r = service_spawn(s,
                           s->main_command,
-                          false,
+                          true,
                           true,
                           true,
                           true,
@@ -2436,7 +2473,17 @@ 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);
@@ -2460,8 +2507,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 */
@@ -2473,7 +2519,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;
@@ -2684,9 +2730,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) {
@@ -2708,7 +2758,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
 
@@ -3189,7 +3239,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;
 
@@ -3368,7 +3418,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;
@@ -3403,7 +3453,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;
@@ -3616,29 +3666,8 @@ 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) {
@@ -3780,7 +3809,6 @@ 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),
         .sections =
                 "Unit\0"
@@ -3818,8 +3846,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,