X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fservice.c;h=2febdb69d148ffd68e4d412717b56bbcd6dbd2d2;hp=0c29d4aefa2729e66f0f85fe3e0b0fb6d76a848c;hb=23635a8547eac0c05922609f5930badc86faf080;hpb=451b34cc1d74960ee0262eef970a6346ec814f31 diff --git a/src/core/service.c b/src/core/service.c index 0c29d4aef..2febdb69d 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -33,6 +33,7 @@ #include "log.h" #include "strv.h" #include "unit-name.h" +#include "unit-printf.h" #include "dbus-service.h" #include "special.h" #include "bus-errors.h" @@ -130,12 +131,12 @@ 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); - s->timeout_usec = DEFAULT_TIMEOUT_USEC; + s->timeout_start_usec = DEFAULT_TIMEOUT_USEC; + s->timeout_stop_usec = DEFAULT_TIMEOUT_USEC; s->restart_usec = DEFAULT_RESTART_USEC; s->type = _SERVICE_TYPE_INVALID; @@ -150,9 +151,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); @@ -296,6 +295,16 @@ static void service_done(Unit *u) { s->control_command = NULL; s->main_command = NULL; + set_free(s->restart_ignore_status.code); + s->restart_ignore_status.code = NULL; + set_free(s->restart_ignore_status.signal); + s->restart_ignore_status.signal = NULL; + + set_free(s->success_status.code); + s->success_status.code = NULL; + set_free(s->success_status.signal); + s->success_status.signal = NULL; + /* This will leak a process, but at least no memory or any of * our resources */ service_unwatch_main_pid(s); @@ -517,7 +526,7 @@ static ExecCommand *exec_command_new(const char *path, const char *arg1) { return c; } -static int sysv_exec_commands(Service *s) { +static int sysv_exec_commands(Service *s, const bool supports_reload) { ExecCommand *c; assert(s); @@ -534,14 +543,25 @@ static int sysv_exec_commands(Service *s) { return -ENOMEM; exec_command_append_list(s->exec_command+SERVICE_EXEC_STOP, c); - c = exec_command_new(UNIT(s)->source_path, "reload"); - if (!c) - return -ENOMEM; - exec_command_append_list(s->exec_command+SERVICE_EXEC_RELOAD, c); + if (supports_reload) { + c = exec_command_new(UNIT(s)->source_path, "reload"); + if (!c) + return -ENOMEM; + exec_command_append_list(s->exec_command+SERVICE_EXEC_RELOAD, c); + } return 0; } +static bool usage_contains_reload(const char *line) { + return (strcasestr(line, "{reload|") || + strcasestr(line, "{reload}") || + strcasestr(line, "{reload\"") || + strcasestr(line, "|reload|") || + strcasestr(line, "|reload}") || + strcasestr(line, "|reload\"")); +} + static int service_load_sysv_path(Service *s, const char *path) { FILE *f; Unit *u; @@ -551,10 +571,12 @@ static int service_load_sysv_path(Service *s, const char *path) { NORMAL, DESCRIPTION, LSB, - LSB_DESCRIPTION + LSB_DESCRIPTION, + USAGE_CONTINUATION } state = NORMAL; char *short_description = NULL, *long_description = NULL, *chkconfig_description = NULL, *description; struct stat st; + bool supports_reload = false; assert(s); assert(path); @@ -567,7 +589,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; @@ -604,8 +625,23 @@ static int service_load_sysv_path(Service *s, const char *path) { line++; t = strstrip(l); - if (*t != '#') + if (*t != '#') { + /* Try to figure out whether this init script supports + * the reload operation. This heuristic looks for + * "Usage" lines which include the reload option. */ + if ( state == USAGE_CONTINUATION || + (state == NORMAL && strcasestr(t, "usage"))) { + if (usage_contains_reload(t)) { + supports_reload = true; + state = NORMAL; + } else if (t[strlen(t)-1] == '\\') + state = USAGE_CONTINUATION; + else + state = NORMAL; + } + continue; + } if (state == NORMAL && streq(t, "### BEGIN INIT INFO")) { state = LSB; @@ -722,7 +758,7 @@ static int service_load_sysv_path(Service *s, const char *path) { char *d = NULL; if (chkconfig_description) - d = join(chkconfig_description, " ", j, NULL); + d = strjoin(chkconfig_description, " ", j, NULL); else d = strdup(j); @@ -879,7 +915,7 @@ static int service_load_sysv_path(Service *s, const char *path) { char *d = NULL; if (long_description) - d = join(long_description, " ", t, NULL); + d = strjoin(long_description, " ", t, NULL); else d = strdup(j); @@ -898,7 +934,7 @@ static int service_load_sysv_path(Service *s, const char *path) { } } - if ((r = sysv_exec_commands(s)) < 0) + if ((r = sysv_exec_commands(s, supports_reload)) < 0) goto finish; if (s->sysv_runlevels && chars_intersect(RUNLEVELS_BOOT, s->sysv_runlevels) && @@ -918,9 +954,12 @@ static int service_load_sysv_path(Service *s, const char *path) { UNIT(s)->default_dependencies = false; /* Don't timeout special services during boot (like fsck) */ - s->timeout_usec = 0; - } else - s->timeout_usec = DEFAULT_SYSV_TIMEOUT_USEC; + s->timeout_start_usec = 0; + s->timeout_stop_usec = 0; + } else { + s->timeout_start_usec = DEFAULT_SYSV_TIMEOUT_USEC; + s->timeout_stop_usec = DEFAULT_SYSV_TIMEOUT_USEC; + } /* Special setting for all SysV services */ s->type = SERVICE_FORKING; @@ -928,7 +967,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. */ @@ -1001,7 +1040,7 @@ static int service_load_sysv_name(Service *s, const char *name) { char *path; int r; - path = join(*p, "/", name, NULL); + path = strjoin(*p, "/", name, NULL); if (!path) return -ENOMEM; @@ -1023,7 +1062,7 @@ static int service_load_sysv_name(Service *s, const char *name) { if (r >= 0 && UNIT(s)->load_state == UNIT_STUB) { /* Try SUSE style boot.* init scripts */ - path = join(*p, "/boot.", name, NULL); + path = strjoin(*p, "/boot.", name, NULL); if (!path) return -ENOMEM; @@ -1038,7 +1077,7 @@ static int service_load_sysv_name(Service *s, const char *name) { if (r >= 0 && UNIT(s)->load_state == UNIT_STUB) { /* Try Frugalware style rc.* init scripts */ - path = join(*p, "/rc.", name, NULL); + path = strjoin(*p, "/rc.", name, NULL); if (!path) return -ENOMEM; @@ -1150,12 +1189,6 @@ static int service_verify(Service *s) { return -EINVAL; } - if (s->type == SERVICE_ONESHOT && - s->exec_command[SERVICE_EXEC_RELOAD]) { - log_error("%s has an ExecReload setting, which is not allowed for Type=oneshot services. Refusing.", UNIT(s)->id); - return -EINVAL; - } - if (s->type == SERVICE_DBUS && !s->bus_name) { log_error("%s is of type D-Bus but no D-Bus service name has been specified. Refusing.", UNIT(s)->id); return -EINVAL; @@ -1164,7 +1197,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; } @@ -1181,12 +1214,12 @@ static int service_add_default_dependencies(Service *s) { * majority of services. */ /* First, pull in base system */ - if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) { + if (UNIT(s)->manager->running_as == SYSTEMD_SYSTEM) { if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true)) < 0) return r; - } else if (UNIT(s)->manager->running_as == MANAGER_USER) { + } else if (UNIT(s)->manager->running_as == SYSTEMD_USER) { if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SOCKETS_TARGET, NULL, true)) < 0) return r; @@ -1245,9 +1278,9 @@ static int service_load(Unit *u) { if (s->type == _SERVICE_TYPE_INVALID) s->type = s->bus_name ? SERVICE_DBUS : SERVICE_SIMPLE; - /* Oneshot services have disabled timeout by default */ - if (s->type == SERVICE_ONESHOT && !s->timeout_defined) - s->timeout_usec = 0; + /* Oneshot services have disabled start timeout by default */ + if (s->type == SERVICE_ONESHOT && !s->start_timeout_defined) + s->timeout_start_usec = 0; service_fix_output(s); @@ -1282,6 +1315,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 +1384,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++) { @@ -1576,7 +1614,12 @@ static void service_set_state(Service *s, ServiceState state) { cgroup_bonding_trim_list(UNIT(s)->cgroup_bondings, true); if (old_state != state) - log_debug("%s changed %s -> %s", UNIT(s)->id, service_state_to_string(old_state), service_state_to_string(state)); + log_struct(LOG_DEBUG, + "UNIT=%s", UNIT(s)->id, + "MESSAGE=%s changed %s -> %s", UNIT(s)->id, + service_state_to_string(old_state), + service_state_to_string(state), + NULL); unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS); s->reload_result = SERVICE_SUCCESS; @@ -1602,11 +1645,10 @@ static int service_coldplug(Unit *u) { s->deserialized_state == SERVICE_FINAL_SIGTERM || s->deserialized_state == SERVICE_FINAL_SIGKILL || s->deserialized_state == SERVICE_AUTO_RESTART) { - - if (s->deserialized_state == SERVICE_AUTO_RESTART || s->timeout_usec > 0) { + if (s->deserialized_state == SERVICE_AUTO_RESTART || s->timeout_start_usec > 0) { usec_t k; - k = s->deserialized_state == SERVICE_AUTO_RESTART ? s->restart_usec : s->timeout_usec; + k = s->deserialized_state == SERVICE_AUTO_RESTART ? s->restart_usec : s->timeout_start_usec; if ((r = unit_watch_timer(UNIT(s), k, &s->timer_watch)) < 0) return r; @@ -1752,8 +1794,9 @@ static int service_spawn( } } - if (timeout && s->timeout_usec) { - if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) + if (timeout && s->timeout_start_usec) { + r = unit_watch_timer(UNIT(s), s->timeout_start_usec, &s->timer_watch); + if (r < 0) goto fail; } else unit_unwatch_timer(UNIT(s), &s->timer_watch); @@ -1763,7 +1806,8 @@ static int service_spawn( goto fail; } - if (!(our_env = new0(char*, 4))) { + our_env = new0(char*, 5); + if (!our_env) { r = -ENOMEM; goto fail; } @@ -1786,10 +1830,14 @@ static int service_spawn( goto fail; } - if (!(final_env = strv_env_merge(2, - UNIT(s)->manager->environment, - our_env, - NULL))) { + if (s->meta.manager->running_as != SYSTEMD_SYSTEM) + if (asprintf(our_env + n_env++, "MANAGERPID=%lu", (unsigned long) getpid()) < 0) { + r = -ENOMEM; + goto fail; + } + + final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL); + if (!final_env) { r = -ENOMEM; goto fail; } @@ -1813,7 +1861,6 @@ static int service_spawn( if (r < 0) goto fail; - if ((r = unit_watch_pid(UNIT(s), pid)) < 0) /* FIXME: we need to do something here */ goto fail; @@ -1896,7 +1943,12 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) (s->restart == SERVICE_RESTART_ON_SUCCESS && s->result == SERVICE_SUCCESS) || (s->restart == SERVICE_RESTART_ON_FAILURE && s->result != SERVICE_SUCCESS) || (s->restart == SERVICE_RESTART_ON_ABORT && (s->result == SERVICE_FAILURE_SIGNAL || - s->result == SERVICE_FAILURE_CORE_DUMP)))) { + s->result == SERVICE_FAILURE_CORE_DUMP))) && + (s->result != SERVICE_FAILURE_EXIT_CODE || + !set_contains(s->restart_ignore_status.code, INT_TO_PTR(s->main_exec_status.status))) && + (s->result != SERVICE_FAILURE_SIGNAL || + !set_contains(s->restart_ignore_status.signal, INT_TO_PTR(s->main_exec_status.status))) + ) { r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch); if (r < 0) @@ -1963,8 +2015,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 +2032,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; } @@ -2009,9 +2062,11 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f } if (wait_for_exit) { - if (s->timeout_usec > 0) - if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) + if (s->timeout_stop_usec > 0) { + r = unit_watch_timer(UNIT(s), s->timeout_stop_usec, &s->timer_watch); + if (r < 0) goto fail; + } service_set_state(s, state); } else if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL) @@ -2254,10 +2309,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 +2328,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; @@ -2464,20 +2525,21 @@ static int service_start(Unit *u) { return 0; /* A service that will be restarted must be stopped first to - * trigger BindTo and/or OnFailure dependencies. If a user + * 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); /* Make sure we don't enter a busy loop of some kind. */ r = service_start_limit_test(s); if (r < 0) { - service_notify_sockets_dead(s, true); + service_enter_dead(s, SERVICE_FAILURE_START_LIMIT, false); return r; } @@ -2858,7 +2920,8 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { assert(s); assert(pid >= 0); - if (UNIT(s)->fragment_path ? is_clean_exit(code, status) : is_clean_exit_lsb(code, status)) + if (UNIT(s)->fragment_path ? is_clean_exit(code, status, &s->success_status) : + is_clean_exit_lsb(code, status, &s->success_status)) f = SERVICE_SUCCESS; else if (code == CLD_EXITED) f = SERVICE_FAILURE_EXIT_CODE; @@ -2890,8 +2953,16 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { f = SERVICE_SUCCESS; } - log_full(f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE, - "%s: main process exited, code=%s, status=%i", u->id, sigchld_code_to_string(code), status); + log_struct(f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE, + "MESSAGE=%s: main process exited, code=%s, status=%i/%s", + u->id, sigchld_code_to_string(code), status, + strna(code == CLD_EXITED + ? exit_status_to_string(status, EXIT_STATUS_FULL) + : signal_to_string(status)), + "UNIT=%s", u->id, + "EXIT_CODE=%s", sigchld_code_to_string(code), + "EXIT_STATUS=%i", status, + NULL); if (f != SERVICE_SUCCESS) s->result = f; @@ -2929,12 +3000,10 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { else service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); break; - } else { - assert(s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY); - - /* Fall through */ } + /* Fall through */ + case SERVICE_RUNNING: service_enter_running(s, f); break; @@ -3004,7 +3073,9 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { break; case SERVICE_START: - assert(s->type == SERVICE_FORKING); + if (s->type != SERVICE_FORKING) + /* Maybe spurious event due to a reload that changed the type? */ + break; if (f != SERVICE_SUCCESS) { service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); @@ -3133,7 +3204,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 +3229,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 { @@ -3397,7 +3468,7 @@ static int service_enumerate(Manager *m) { assert(m); - if (m->running_as != MANAGER_SYSTEM) + if (m->running_as != SYSTEMD_SYSTEM) return 0; zero(runlevel_services); @@ -3407,7 +3478,7 @@ static int service_enumerate(Manager *m) { struct dirent *de; free(path); - path = join(*p, "/", rcnd_table[i].path, NULL); + path = strjoin(*p, "/", rcnd_table[i].path, NULL); if (!path) { r = -ENOMEM; goto finish; @@ -3442,7 +3513,7 @@ static int service_enumerate(Manager *m) { continue; free(fpath); - fpath = join(path, "/", de->d_name, NULL); + fpath = strjoin(path, "/", de->d_name, NULL); if (!fpath) { r = -ENOMEM; goto finish; @@ -3659,7 +3730,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 +3757,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: @@ -3784,7 +3860,8 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = { [SERVICE_FAILURE_EXIT_CODE] = "exit-code", [SERVICE_FAILURE_SIGNAL] = "signal", [SERVICE_FAILURE_CORE_DUMP] = "core-dump", - [SERVICE_FAILURE_WATCHDOG] = "watchdog" + [SERVICE_FAILURE_WATCHDOG] = "watchdog", + [SERVICE_FAILURE_START_LIMIT] = "start-limit" }; DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult); @@ -3798,8 +3875,9 @@ static const char* const start_limit_action_table[_SERVICE_START_LIMIT_MAX] = { DEFINE_STRING_TABLE_LOOKUP(start_limit_action, StartLimitAction); const UnitVTable service_vtable = { - .suffix = ".service", .object_size = sizeof(Service), + .exec_context_offset = offsetof(Service, exec_context), + .sections = "Unit\0" "Service\0"