X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fservice.c;h=1c127bdbcb2ffc5c6926d210a63d278ea90078a8;hp=0a6658809e8b612ab468c48566fd9ecf5f24665e;hb=956b78e8e3636bbf04e264ca96128edc2cbf3626;hpb=7f2cddae09fd2579ae24434df577bb5e5a157d86 diff --git a/src/core/service.c b/src/core/service.c index 0a6658809..1c127bdbc 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -130,7 +130,6 @@ static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] = static void service_init(Unit *u) { Service *s = SERVICE(u); - int i; assert(u); assert(u->load_state == UNIT_STUB); @@ -150,9 +149,7 @@ 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); + kill_context_init(&s->kill_context); RATELIMIT_INIT(s->start_limit, 10*USEC_PER_SEC, 5); @@ -567,7 +564,6 @@ static int service_load_sysv_path(Service *s, const char *path) { goto finish; } - zero(st); if (fstat(fileno(f), &st) < 0) { r = -errno; goto finish; @@ -928,7 +924,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; - 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. */ @@ -1164,7 +1160,7 @@ static int service_verify(Service *s) { 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) { + 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; } @@ -1282,6 +1278,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); @@ -1347,6 +1347,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++) { @@ -1963,8 +1964,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) @@ -1980,9 +1981,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; } @@ -2254,10 +2256,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; @@ -2271,6 +2275,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; @@ -2466,11 +2474,12 @@ static int service_start(Unit *u) { /* 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. */ - 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; - } + * 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); @@ -3133,7 +3142,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 { @@ -3158,7 +3167,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 { @@ -3659,7 +3668,7 @@ static void service_reset_failed(Unit *u) { 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; @@ -3686,28 +3695,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; } + } + 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; + if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT) + r = q; } finish: