X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fservice.c;h=efa52778a66f6342a4fa805704dd6012859a2fdb;hp=56c8502500f5c37e3b4667a8c560ae35c84d8531;hb=f73d93a4d9403d44bf3661bf383ac1385e5b5eb6;hpb=3177a49ce9e21df6894cdea4f256d60b8e556c81 diff --git a/src/service.c b/src/service.c index 56c850250..efa52778a 100644 --- a/src/service.c +++ b/src/service.c @@ -95,7 +95,7 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = { [SERVICE_STOP_POST] = UNIT_DEACTIVATING, [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING, [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING, - [SERVICE_MAINTENANCE] = UNIT_MAINTENANCE, + [SERVICE_FAILED] = UNIT_FAILED, [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING }; @@ -574,10 +574,16 @@ static int service_load_sysv_path(Service *s, const char *path) { if (unit_name_to_type(m) == UNIT_SERVICE) r = unit_add_name(u, m); - else if (s->sysv_enabled) - r = unit_add_two_dependencies_by_name_inverse(u, UNIT_AFTER, UNIT_WANTS, m, NULL, true); - else - r = unit_add_dependency_by_name_inverse(u, UNIT_AFTER, m, NULL, true); + else { + r = unit_add_dependency_by_name(u, UNIT_BEFORE, m, NULL, true); + + if (s->sysv_enabled) { + int k; + + if ((k = unit_add_dependency_by_name_inverse(u, UNIT_WANTS, m, NULL, true)) < 0) + r = k; + } + } if (r < 0) log_error("[%s:%u] Failed to add LSB Provides name %s, ignoring: %s", path, line, m, strerror(-r)); @@ -1197,7 +1203,7 @@ static void service_set_state(Service *s, ServiceState state) { state == SERVICE_STOP_POST || state == SERVICE_FINAL_SIGTERM || state == SERVICE_FINAL_SIGKILL || - state == SERVICE_MAINTENANCE || + state == SERVICE_FAILED || state == SERVICE_AUTO_RESTART) service_notify_sockets_dead(s); @@ -1521,7 +1527,7 @@ static void service_enter_dead(Service *s, bool success, bool allow_restart) { service_set_state(s, SERVICE_AUTO_RESTART); } else - service_set_state(s, s->failure ? SERVICE_MAINTENANCE : SERVICE_DEAD); + service_set_state(s, s->failure ? SERVICE_FAILED : SERVICE_DEAD); s->forbid_restart = false; @@ -1570,7 +1576,8 @@ fail: static void service_enter_signal(Service *s, ServiceState state, bool success) { int r; - bool sent = false; + Set *pid_set = NULL; + bool wait_for_exit = false; assert(s); @@ -1580,38 +1587,53 @@ static void service_enter_signal(Service *s, ServiceState state, bool success) { 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->exec_context.kill_mode == KILL_CONTROL_GROUP) { + if (s->main_pid > 0) { + if (kill(s->exec_context.kill_mode == KILL_PROCESS_GROUP ? + -s->main_pid : + s->main_pid, sig) < 0 && errno != ESRCH) - if ((r = cgroup_bonding_kill_list(s->meta.cgroup_bondings, sig)) < 0) { - if (r != -EAGAIN && r != -ESRCH) - goto fail; - } else - sent = true; + log_warning("Failed to kill main process %li: %m", (long) s->main_pid); + else + wait_for_exit = true; } - if (!sent) { - r = 0; + if (s->control_pid > 0) { + if (kill(s->exec_context.kill_mode == KILL_PROCESS_GROUP ? + -s->control_pid : + s->control_pid, sig) < 0 && errno != ESRCH) - if (s->main_pid > 0) { - if (kill(s->exec_context.kill_mode == KILL_PROCESS ? s->main_pid : -s->main_pid, sig) < 0 && errno != ESRCH) - r = -errno; - else - sent = true; - } + log_warning("Failed to kill control process %li: %m", (long) s->control_pid); + else + wait_for_exit = true; + } - if (s->control_pid > 0) { - if (kill(s->exec_context.kill_mode == KILL_PROCESS ? s->control_pid : -s->control_pid, sig) < 0 && errno != ESRCH) - r = -errno; - else - sent = true; - } + if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) { - if (r < 0) + if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) { + r = -ENOMEM; goto fail; + } + + /* Exclude the main/control pids from being killed via the cgroup */ + if (s->main_pid > 0) + if ((r = set_put(pid_set, LONG_TO_PTR(s->main_pid))) < 0) + goto fail; + + if (s->control_pid > 0) + if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) + goto fail; + + if ((r = cgroup_bonding_kill_list(s->meta.cgroup_bondings, sig, pid_set)) < 0) { + if (r != -EAGAIN && r != -ESRCH && r != -ENOENT) + log_warning("Failed to kill control group: %s", strerror(-r)); + } else if (r > 0) + wait_for_exit = true; + + set_free(pid_set); } } - if (sent && (s->main_pid > 0 || s->control_pid > 0)) { + if (wait_for_exit) { if (s->timeout_usec > 0) if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) goto fail; @@ -1631,6 +1653,9 @@ fail: service_enter_stop_post(s, false); else service_enter_dead(s, false, true); + + if (pid_set) + set_free(pid_set); } static void service_enter_stop(Service *s, bool success) { @@ -1822,7 +1847,7 @@ static void service_enter_restart(Service *s) { service_enter_dead(s, true, false); - if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s), JOB_FAIL, false, NULL, NULL)) < 0) + if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s), JOB_FAIL, false, &error, NULL)) < 0) goto fail; log_debug("%s scheduled restart job.", s->meta.id); @@ -1966,7 +1991,7 @@ static int service_start(Unit *u) { s->state == SERVICE_START_POST) return 0; - assert(s->state == SERVICE_DEAD || s->state == SERVICE_MAINTENANCE || s->state == SERVICE_AUTO_RESTART); + assert(s->state == SERVICE_DEAD || s->state == SERVICE_FAILED || s->state == SERVICE_AUTO_RESTART); /* Make sure we don't enter a busy loop of some kind. */ if (!ratelimit_test(&s->ratelimit)) { @@ -2520,7 +2545,7 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) { break; case SERVICE_FINAL_SIGKILL: - log_warning("%s still around after SIGKILL (2). Entering maintenance mode.", u->meta.id); + log_warning("%s still around after SIGKILL (2). Entering failed mode.", u->meta.id); service_enter_dead(s, false, true); break; @@ -2553,6 +2578,20 @@ static void service_cgroup_notify_event(Unit *u) { service_enter_running(s, true); break; + case SERVICE_STOP_SIGTERM: + case SERVICE_STOP_SIGKILL: + if (main_pid_good(s) <= 0 && !control_pid_good(s)) + service_enter_stop_post(s, true); + + break; + + case SERVICE_FINAL_SIGTERM: + case SERVICE_FINAL_SIGKILL: + if (main_pid_good(s) <= 0 && !control_pid_good(s)) + service_enter_dead(s, true, true); + + break; + default: ; } @@ -2632,10 +2671,15 @@ static int service_enumerate(Manager *m) { unsigned i; DIR *d = NULL; char *path = NULL, *fpath = NULL, *name = NULL; + Set *runlevel_services[ELEMENTSOF(rcnd_table)], *shutdown_services = NULL; + Unit *service; + Iterator j; int r; assert(m); + zero(runlevel_services); + STRV_FOREACH(p, m->lookup_paths.sysvrcnd_path) for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) { struct dirent *de; @@ -2658,7 +2702,6 @@ static int service_enumerate(Manager *m) { } while ((de = readdir(d))) { - Unit *service; int a, b; if (ignore_file(de->d_name)) @@ -2702,54 +2745,70 @@ static int service_enumerate(Manager *m) { continue; } - if (de->d_name[0] == 'S' && - (rcnd_table[i].type == RUNLEVEL_UP || rcnd_table[i].type == RUNLEVEL_SYSINIT)) { - SERVICE(service)->sysv_start_priority = - MAX(a*10 + b, SERVICE(service)->sysv_start_priority); - SERVICE(service)->sysv_enabled = true; - } + if (de->d_name[0] == 'S') { - manager_dispatch_load_queue(m); - service = unit_follow_merge(service); + if (rcnd_table[i].type == RUNLEVEL_UP || rcnd_table[i].type == RUNLEVEL_SYSINIT) { + SERVICE(service)->sysv_start_priority = + MAX(a*10 + b, SERVICE(service)->sysv_start_priority); - /* If this is a native service, rely - * on native ways to pull in a - * service, don't pull it in via sysv - * rcN.d links. */ - if (service->meta.fragment_path) - continue; + SERVICE(service)->sysv_enabled = true; + } - if (de->d_name[0] == 'S') { + if ((r = set_ensure_allocated(&runlevel_services[i], trivial_hash_func, trivial_compare_func)) < 0) + goto finish; - if ((r = unit_add_two_dependencies_by_name_inverse(service, UNIT_AFTER, UNIT_WANTS, rcnd_table[i].target, NULL, true)) < 0) + if ((r = set_put(runlevel_services[i], service)) < 0) goto finish; } else if (de->d_name[0] == 'K' && (rcnd_table[i].type == RUNLEVEL_DOWN || rcnd_table[i].type == RUNLEVEL_SYSINIT)) { - /* We honour K links only for - * halt/reboot. For the normal - * runlevels we assume the - * stop jobs will be - * implicitly added by the - * core logic. Also, we don't - * really distuingish here - * between the runlevels 0 and - * 6 and just add them to the - * special shutdown target. On - * SUSE the boot.d/ runlevel - * is also used for shutdown, - * so we add links for that - * too to the shutdown - * target.*/ - - if ((r = unit_add_two_dependencies_by_name_inverse(service, UNIT_AFTER, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true)) < 0) + if ((r = set_ensure_allocated(&shutdown_services, trivial_hash_func, trivial_compare_func)) < 0) + goto finish; + + if ((r = set_put(shutdown_services, service)) < 0) goto finish; } } } + /* Now we loaded all stubs and are aware of the lowest + start-up priority for all services, not let's actually load + the services, this will also tell us which services are + actually native now */ + manager_dispatch_load_queue(m); + + /* If this is a native service, rely on native ways to pull in + * a service, don't pull it in via sysv rcN.d links. */ + for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) + SET_FOREACH(service, runlevel_services[i], j) { + service = unit_follow_merge(service); + + if (service->meta.fragment_path) + continue; + + if ((r = unit_add_two_dependencies_by_name_inverse(service, UNIT_AFTER, UNIT_WANTS, rcnd_table[i].target, NULL, true)) < 0) + goto finish; + } + + /* We honour K links only for halt/reboot. For the normal + * runlevels we assume the stop jobs will be implicitly added + * by the core logic. Also, we don't really distuingish here + * between the runlevels 0 and 6 and just add them to the + * special shutdown target. On SUSE the boot.d/ runlevel is + * also used for shutdown, so we add links for that too to the + * shutdown target.*/ + SET_FOREACH(service, shutdown_services, j) { + service = unit_follow_merge(service); + + if (service->meta.fragment_path) + continue; + + if ((r = unit_add_two_dependencies_by_name_inverse(service, UNIT_AFTER, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true)) < 0) + goto finish; + } + r = 0; finish: @@ -2757,6 +2816,10 @@ finish: free(fpath); free(name); + for (i = 0; i < ELEMENTSOF(rcnd_table); i++) + set_free(runlevel_services[i]); + set_free(shutdown_services); + if (d) closedir(d); @@ -2853,12 +2916,12 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock) { return 0; } -static void service_reset_maintenance(Unit *u) { +static void service_reset_failed(Unit *u) { Service *s = SERVICE(u); assert(s); - if (s->state == SERVICE_MAINTENANCE) + if (s->state == SERVICE_FAILED) service_set_state(s, SERVICE_DEAD); s->failure = false; @@ -2878,7 +2941,7 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = { [SERVICE_STOP_POST] = "stop-post", [SERVICE_FINAL_SIGTERM] = "final-sigterm", [SERVICE_FINAL_SIGKILL] = "final-sigkill", - [SERVICE_MAINTENANCE] = "maintenance", + [SERVICE_FAILED] = "failed", [SERVICE_AUTO_RESTART] = "auto-restart", }; @@ -2951,7 +3014,7 @@ const UnitVTable service_vtable = { .sigchld_event = service_sigchld_event, .timer_event = service_timer_event, - .reset_maintenance = service_reset_maintenance, + .reset_failed = service_reset_failed, .cgroup_notify_empty = service_cgroup_notify_event, .notify_message = service_notify_message,