X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fservice.c;h=5d82e9b545172516147b59956ac8e386bfd64852;hp=4358a948de92c3fe409f232cddde0c55a42b8539;hb=2e9d6c1251abc0af9aa5bc53610bd522d55be776;hpb=f2b6878955b1f77ea1fa87b502b13d5dbefc57f6 diff --git a/src/core/service.c b/src/core/service.c index 4358a948d..5d82e9b54 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -38,6 +38,7 @@ #include "bus-errors.h" #include "exit-status.h" #include "def.h" +#include "path-util.h" #include "util.h" #include "utf8.h" @@ -109,12 +110,14 @@ static const UnitActiveState state_translation_table[_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->restart_usec = DEFAULT_RESTART_USEC; + s->type = _SERVICE_TYPE_INVALID; s->watchdog_watch.type = WATCH_INVALID; @@ -127,6 +130,9 @@ 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); RATELIMIT_INIT(s->start_limit, 10*USEC_PER_SEC, 5); @@ -721,7 +727,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 +777,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)); @@ -1135,6 +1141,9 @@ static int service_verify(Service *s) { return -EINVAL; } + 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) { log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id); return -EINVAL; @@ -1213,6 +1222,9 @@ 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; + service_fix_output(s); if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0) @@ -1957,7 +1969,7 @@ 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; - r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, pid_set, NULL); + 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)); @@ -2104,7 +2116,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, "control"); + 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; @@ -2180,7 +2192,7 @@ 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, "control"); + cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, true, NULL, "control"); s->control_command_id = SERVICE_EXEC_START_PRE; @@ -2220,6 +2232,8 @@ static void service_enter_restart(Service *s) { if ((r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch)) < 0) goto fail; + + return; } /* Any units that are bound to this service must also be @@ -2422,7 +2436,16 @@ 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 BindTo 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; + } + + 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); @@ -2446,8 +2469,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 */ @@ -2459,9 +2481,9 @@ 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); + service_enter_dead(s, SERVICE_SUCCESS, false); return 0; } @@ -2917,6 +2939,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) { @@ -3667,7 +3694,7 @@ static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusErro r = q; goto finish; } - q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, pid_set, NULL); + 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; @@ -3767,7 +3794,6 @@ const UnitVTable service_vtable = { "Unit\0" "Service\0" "Install\0", - .show_status = true, .init = service_init, .done = service_done, @@ -3813,6 +3839,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.", + }, + }, };