chiark / gitweb /
service: when reloading a service fails don't fail the entire service but just the...
[elogind.git] / src / service.c
index ca0db8e7f181e06b5a8bdf65656d67e0c3a46b4b..431bccc4e1ad5bcb0ec7bd99310f70df2ad22f6b 100644 (file)
@@ -237,19 +237,18 @@ static char *sysv_translate_name(const char *name) {
         if (!(r = new(char, strlen(name) + sizeof(".service"))))
                 return NULL;
 
+#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU)
+        if (endswith(name, ".sh"))
+                /* Drop Debian-style .sh suffix */
+                strcpy(stpcpy(r, name) - 3, ".service");
+#endif
+#ifdef TARGET_SUSE
         if (startswith(name, "boot."))
                 /* Drop SuSE-style boot. prefix */
                 strcpy(stpcpy(r, name + 5), ".service");
-        else if (endswith(name, ".sh"))
-                /* Drop Debian-style .sh suffix */
-                strcpy(stpcpy(r, name) - 3, ".service");
-#ifdef TARGET_ARCH
-        else if (startswith(name, "@"))
-                /* Drop Arch-style background prefix */
-                strcpy(stpcpy(r, name + 1), ".service");
 #endif
 #ifdef TARGET_FRUGALWARE
-        else if (startswith(name, "rc."))
+        if (startswith(name, "rc."))
                 /* Drop Frugalware-style rc. prefix */
                 strcpy(stpcpy(r, name + 3), ".service");
 #endif
@@ -324,10 +323,13 @@ static int sysv_translate_facility(const char *name, const char *filename, char
         /* If we don't know this name, fallback heuristics to figure
          * out whether something is a target or a service alias. */
 
-        if (*name == '$')
+        if (*name == '$') {
+                if (!unit_prefix_is_valid(n))
+                        return -EINVAL;
+
                 /* Facilities starting with $ are most likely targets */
                 r = unit_name_build(n, NULL, ".target");
-        else if (filename && streq(name, filename))
+        else if (filename && streq(name, filename))
                 /* Names equalling the file name of the services are redundant */
                 return 0;
         else
@@ -680,10 +682,14 @@ static int service_load_sysv_path(Service *s, const char *path) {
                                         }
 
                                         r = sysv_translate_facility(n, file_name_from_path(path), &m);
-                                        free(n);
 
-                                        if (r < 0)
-                                                goto finish;
+                                        if (r < 0) {
+                                                log_error("[%s:%u] Failed to translate LSB dependency %s, ignoring: %s", path, line, n, strerror(-r));
+                                                free(n);
+                                                continue;
+                                        }
+
+                                        free(n);
 
                                         if (r == 0)
                                                 continue;
@@ -857,10 +863,20 @@ static int service_load_sysv_name(Service *s, const char *name) {
 
         /* For SysV services we strip the boot.*, rc.* and *.sh
          * prefixes/suffixes. */
-        if (startswith(name, "boot.") ||
-            startswith(name, "rc.") ||
-            endswith(name, ".sh.service"))
+#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU)
+        if (endswith(name, ".sh.service"))
+                return -ENOENT;
+#endif
+
+#ifdef TARGET_SUSE
+        if (startswith(name, "boot."))
+                return -ENOENT;
+#endif
+
+#ifdef TARGET_FRUGALWARE
+        if (startswith(name, "rc."))
                 return -ENOENT;
+#endif
 
         STRV_FOREACH(p, s->meta.manager->lookup_paths.sysvinit_path) {
                 char *path;
@@ -1430,7 +1446,8 @@ static void service_set_state(Service *s, ServiceState state) {
         if (old_state != state)
                 log_debug("%s changed %s -> %s", s->meta.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]);
+        unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], !s->reload_failure);
+        s->reload_failure = false;
 }
 
 static int service_coldplug(Unit *u) {
@@ -2104,7 +2121,8 @@ static void service_enter_reload(Service *s) {
 
 fail:
         log_warning("%s failed to run 'reload' task: %s", s->meta.id, strerror(-r));
-        service_enter_stop(s, false);
+        s->reload_failure = true;
+        service_enter_running(s, true);
 }
 
 static void service_run_next_control(Service *s, bool success) {
@@ -2145,7 +2163,10 @@ fail:
                 service_enter_signal(s, SERVICE_STOP_SIGTERM, false);
         else if (s->state == SERVICE_STOP_POST)
                 service_enter_dead(s, false, true);
-        else
+        else if (s->state == SERVICE_RELOAD) {
+                s->reload_failure = true;
+                service_enter_running(s, true);
+        } else
                 service_enter_stop(s, false);
 }
 
@@ -2631,11 +2652,8 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                                 /* Fall through */
 
                         case SERVICE_RELOAD:
-                                if (success)
-                                        service_enter_running(s, true);
-                                else
-                                        service_enter_stop(s, false);
-
+                                s->reload_failure = !success;
+                                service_enter_running(s, true);
                                 break;
 
                         case SERVICE_STOP:
@@ -2685,19 +2703,30 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
                 break;
 
         case SERVICE_START_POST:
-        case SERVICE_RELOAD:
                 log_warning("%s operation timed out. Stopping.", u->meta.id);
                 service_enter_stop(s, false);
                 break;
 
+        case SERVICE_RELOAD:
+                log_warning("%s operation timed out. Stopping.", u->meta.id);
+                s->reload_failure = true;
+                service_enter_running(s, true);
+                break;
+
         case SERVICE_STOP:
                 log_warning("%s stopping timed out. Terminating.", u->meta.id);
                 service_enter_signal(s, SERVICE_STOP_SIGTERM, false);
                 break;
 
         case SERVICE_STOP_SIGTERM:
-                log_warning("%s stopping timed out. Killing.", u->meta.id);
-                service_enter_signal(s, SERVICE_STOP_SIGKILL, false);
+                if (s->exec_context.send_sigkill) {
+                        log_warning("%s stopping timed out. Killing.", u->meta.id);
+                        service_enter_signal(s, SERVICE_STOP_SIGKILL, false);
+                } else {
+                        log_warning("%s stopping timed out. Skipping SIGKILL.", u->meta.id);
+                        service_enter_stop_post(s, false);
+                }
+
                 break;
 
         case SERVICE_STOP_SIGKILL:
@@ -2715,8 +2744,14 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
                 break;
 
         case SERVICE_FINAL_SIGTERM:
-                log_warning("%s stopping timed out (2). Killing.", u->meta.id);
-                service_enter_signal(s, SERVICE_FINAL_SIGKILL, false);
+                if (s->exec_context.send_sigkill) {
+                        log_warning("%s stopping timed out (2). Killing.", u->meta.id);
+                        service_enter_signal(s, SERVICE_FINAL_SIGKILL, false);
+                } else {
+                        log_warning("%s stopping timed out (2). Skipping SIGKILL. Entering failed mode.", u->meta.id);
+                        service_enter_dead(s, false, true);
+                }
+
                 break;
 
         case SERVICE_FINAL_SIGKILL:
@@ -2851,67 +2886,9 @@ static int service_enumerate(Manager *m) {
         Unit *service;
         Iterator j;
         int r;
-#ifdef TARGET_ARCH
-        Unit *previous = NULL;
-        char *arch_daemons = NULL;
-        char *arch_daemons_stripped = NULL;
-        char **arch_daemons_split = NULL;
-#endif
 
         assert(m);
 
-#ifdef TARGET_ARCH
-        if ((r = parse_env_file("/etc/rc.conf", NEWLINE,
-                                "DAEMONS", &arch_daemons,
-                                NULL)) < 0) {
-
-                if (r != -ENOENT)
-                        log_warning("Failed to read /etc/rc.conf: %s", strerror(-r));
-
-        } else if (arch_daemons) {
-                if (!(arch_daemons_stripped = strchr(arch_daemons, '(')))
-                        arch_daemons_stripped = arch_daemons;
-                else
-                        arch_daemons_stripped++; /* strip start paren */
-
-                arch_daemons_stripped[strcspn(arch_daemons_stripped, ")")] = 0; /* strip end paren */
-
-                if (!(arch_daemons_split = strv_split_quoted(arch_daemons_stripped))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                STRV_FOREACH(p, arch_daemons_split) {
-
-                        free(name);
-                        name = NULL;
-
-                        if (**p == '!') /* daemons prefixed with ! are disabled, so ignore them */
-                                continue;
-
-                        if (!(name = sysv_translate_name(*p))) {
-                                r = -ENOMEM;
-                                goto finish;
-                        }
-
-                        if ((r = manager_load_unit_prepare(m, name, NULL, NULL, &service)) < 0) {
-                                log_warning("Failed to prepare unit %s: %s", name, strerror(-r));
-                                continue;
-                        }
-
-                        if ((r = unit_add_two_dependencies_by_name_inverse(service, UNIT_AFTER, UNIT_WANTS, "multi-user.target", NULL, true)) < 0)
-                                goto finish;
-
-                        if (previous)
-                                if ((r = unit_add_dependency(service, UNIT_AFTER, previous, true)) < 0)
-                                        goto finish;
-
-                        if (**p != '@') /* daemons prefixed with @ can be started in the background */
-                                previous = service;
-                }
-        }
-#endif
-
         zero(runlevel_services);
 
         STRV_FOREACH(p, m->lookup_paths.sysvrcnd_path)
@@ -3049,10 +3026,6 @@ finish:
         free(path);
         free(fpath);
         free(name);
-#ifdef TARGET_ARCH
-        free(arch_daemons);
-        free(arch_daemons_split);
-#endif
 
         for (i = 0; i < ELEMENTSOF(rcnd_table); i++)
                 set_free(runlevel_services[i]);