X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fservice.c;h=6d6c540a725aef480d677f0418f5cb74ac2e8105;hb=6f3525444e177e8413d46c5029a7dced7fb4818d;hp=116e539d951df7303039759645589b54b0e49342;hpb=525ee6f4a1639bcb28198bf9e32b93ca2bfd268b;p=elogind.git diff --git a/src/service.c b/src/service.c index 116e539d9..6d6c540a7 100644 --- a/src/service.c +++ b/src/service.c @@ -39,6 +39,9 @@ #define NEWLINES "\n\r" #ifdef HAVE_SYSV_COMPAT + +#define DEFAULT_SYSV_TIMEOUT_USEC (3*USEC_PER_MINUTE) + typedef enum RunlevelType { RUNLEVEL_UP, RUNLEVEL_DOWN, @@ -313,7 +316,7 @@ 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 an service alias. */ + * out whether something is a target or a service alias. */ if (*name == '$') /* Facilities starting with $ are most likely targets */ @@ -790,7 +793,8 @@ static int service_load_sysv_path(Service *s, const char *path) { /* Don't timeout special services during boot (like fsck) */ s->timeout_usec = 0; - } + } else + s->timeout_usec = DEFAULT_SYSV_TIMEOUT_USEC; /* Special setting for all SysV services */ s->type = SERVICE_FORKING; @@ -925,6 +929,47 @@ static int service_load_sysv(Service *s) { } #endif +static int fsck_fix_order(Service *s) { + Meta *other; + int r; + + assert(s); + + if (s->fsck_passno <= 0) + return 0; + + /* For each pair of services where both have an fsck priority + * we order things based on it. */ + + LIST_FOREACH(units_per_type, other, s->meta.manager->units_per_type[UNIT_SERVICE]) { + Service *t; + UnitDependency d; + + t = (Service*) other; + + if (s == t) + continue; + + if (t->meta.load_state != UNIT_LOADED) + continue; + + if (t->fsck_passno <= 0) + continue; + + if (t->fsck_passno < s->fsck_passno) + d = UNIT_AFTER; + else if (t->fsck_passno > s->fsck_passno) + d = UNIT_BEFORE; + else + continue; + + if (!(r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0) + return r; + } + + return 0; +} + static int service_verify(Service *s) { assert(s); @@ -1018,6 +1063,9 @@ static int service_load(Unit *u) { return r; #endif + if ((r = fsck_fix_order(s)) < 0) + return r; + if (s->bus_name) if ((r = unit_watch_bus_name(u, s->bus_name)) < 0) return r; @@ -1104,22 +1152,27 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) { if (s->sysv_path) fprintf(f, "%sSysV Init Script Path: %s\n" - "%sSysV Init Script has LSB Header: %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_has_lsb), + prefix, yes_no(s->sysv_enabled)); if (s->sysv_start_priority >= 0) fprintf(f, - "%sSysVStartPriority: %i\n" - "%sSysVEnabled: %s\n", - prefix, s->sysv_start_priority, - prefix, yes_no(s->sysv_enabled)); + "%sSysVStartPriority: %i\n", + prefix, s->sysv_start_priority); if (s->sysv_runlevels) fprintf(f, "%sSysVRunLevels: %s\n", prefix, s->sysv_runlevels); #endif + if (s->fsck_passno > 0) + fprintf(f, + "%sFsckPassNo: %i\n", + prefix, s->fsck_passno); + if (s->status_text) fprintf(f, "%sStatus Text: %s\n", prefix, s->status_text); @@ -1623,7 +1676,11 @@ static void service_enter_dead(Service *s, bool success, bool allow_restart) { if (allow_restart && !s->forbid_restart && (s->restart == SERVICE_RESTART_ALWAYS || - (s->restart == SERVICE_RESTART_ON_SUCCESS && !s->failure))) { + (s->restart == SERVICE_RESTART_ON_SUCCESS && !s->failure) || + (s->restart == SERVICE_RESTART_ON_FAILURE && s->failure) || + (s->restart == SERVICE_RESTART_ON_ABORT && s->failure && + (s->main_exec_status.code == CLD_KILLED || + s->main_exec_status.code == CLD_DUMPED)))) { if ((r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch)) < 0) goto fail; @@ -2402,7 +2459,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { if (s->main_pid == pid) { s->main_pid = 0; - exec_status_exit(&s->main_exec_status, pid, code, status); + exec_status_exit(&s->main_exec_status, pid, code, status, s->exec_context.utmp_id); if (s->type != SERVICE_FORKING && s->control_command) { s->control_command->exec_status = s->main_exec_status; @@ -2479,7 +2536,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { s->control_pid = 0; if (s->control_command) { - exec_status_exit(&s->control_command->exec_status, pid, code, status); + exec_status_exit(&s->control_command->exec_status, pid, code, status, s->exec_context.utmp_id); if (s->control_command->ignore) success = true; @@ -3088,6 +3145,62 @@ static void service_reset_failed(Unit *u) { s->failure = false; } +static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) { + Service *s = SERVICE(u); + int r = 0; + Set *pid_set = NULL; + + assert(s); + + if (s->main_pid <= 0 && who == KILL_MAIN) { + dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill"); + return -EINVAL; + } + + if (s->control_pid <= 0 && who == KILL_CONTROL) { + dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill"); + return -ENOENT; + } + + if (s->control_pid > 0) + if (kill(mode == KILL_PROCESS_GROUP ? -s->control_pid : s->control_pid, signo) < 0) + r = -errno; + + if (s->main_pid > 0) + if (kill(mode == KILL_PROCESS_GROUP ? -s->main_pid : s->main_pid, signo) < 0) + r = -errno; + + if (mode == KILL_CONTROL_GROUP) { + int q; + + if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) + 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) { + r = q; + goto finish; + } + + if (s->main_pid > 0) + if ((q = set_put(pid_set, LONG_TO_PTR(s->main_pid))) < 0) { + r = q; + goto finish; + } + + if ((q = cgroup_bonding_kill_list(s->meta.cgroup_bondings, signo, pid_set)) < 0) + if (r != -EAGAIN && r != -ESRCH && r != -ENOENT) + r = q; + } + +finish: + if (pid_set) + set_free(pid_set); + + return r; +} + static const char* const service_state_table[_SERVICE_STATE_MAX] = { [SERVICE_DEAD] = "dead", [SERVICE_START_PRE] = "start-pre", @@ -3111,7 +3224,9 @@ DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState); static const char* const service_restart_table[_SERVICE_RESTART_MAX] = { [SERVICE_RESTART_NO] = "no", [SERVICE_RESTART_ON_SUCCESS] = "on-success", - [SERVICE_RESTART_ALWAYS] = "always", + [SERVICE_RESTART_ON_FAILURE] = "on-failure", + [SERVICE_RESTART_ON_ABORT] = "on-abort", + [SERVICE_RESTART_ALWAYS] = "always" }; DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart); @@ -3163,6 +3278,8 @@ const UnitVTable service_vtable = { .can_reload = service_can_reload, + .kill = service_kill, + .serialize = service_serialize, .deserialize_item = service_deserialize_item,