X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fservice.c;h=3ebe60e46e12c41e2316037a22c7f5f89edd33be;hb=dc8e15c206ace4f9b424ea6c114a2bc7ee127eab;hp=6a230e50c83e320e0c9d917f04b5ee39bcd9e9fd;hpb=0b5d26f95dd0aceb051f334c109a90e356b38c90;p=elogind.git diff --git a/src/service.c b/src/service.c index 6a230e50c..3ebe60e46 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, @@ -178,11 +181,11 @@ static void service_close_socket_fd(Service *s) { static void service_connection_unref(Service *s) { assert(s); - if (!s->socket) + if (!s->accept_socket) return; - socket_connection_unref(s->socket); - s->socket = NULL; + socket_connection_unref(s->accept_socket); + s->accept_socket = NULL; } static void service_done(Unit *u) { @@ -222,6 +225,8 @@ static void service_done(Unit *u) { service_close_socket_fd(s); service_connection_unref(s); + set_free(s->configured_sockets); + unit_unwatch_timer(u, &s->timer_watch); } @@ -250,7 +255,7 @@ static char *sysv_translate_name(const char *name) { return r; } -static int sysv_translate_facility(const char *name, char **_r) { +static int sysv_translate_facility(const char *name, const char *filename, char **_r) { /* We silently ignore the $ prefix here. According to the LSB * spec it simply indicates whether something is a @@ -289,28 +294,39 @@ static int sysv_translate_facility(const char *name, char **_r) { unsigned i; char *r; + const char *n; - for (i = 0; i < ELEMENTSOF(table); i += 2) + assert(name); + assert(_r); - if (streq(table[i], name) || - (*name == '$' && streq(table[i], name+1))) { + n = *name == '$' ? name + 1 : name; - if (!table[i+1]) - return 0; + for (i = 0; i < ELEMENTSOF(table); i += 2) { - if (!(r = strdup(table[i+1]))) - return -ENOMEM; + if (!streq(table[i], n)) + continue; - goto finish; - } + if (!table[i+1]) + return 0; + + if (!(r = strdup(table[i+1]))) + return -ENOMEM; + + goto finish; + } /* 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 == '$') - r = unit_name_build(name+1, NULL, ".target"); + /* Facilities starting with $ are most likely targets */ + r = unit_name_build(n, NULL, ".target"); + else if (filename && streq(name, filename)) + /* Names equalling the file name of the services are redundant */ + return 0; else - r = sysv_translate_name(name); + /* Everything else we assume to be normal service names */ + r = sysv_translate_name(n); if (!r) return -ENOMEM; @@ -612,12 +628,7 @@ static int service_load_sysv_path(Service *s, const char *path) { goto finish; } - if (streq(n, file_name_from_path(path))) { - free(n); - continue; - } - - r = sysv_translate_facility(n, &m); + r = sysv_translate_facility(n, file_name_from_path(path), &m); free(n); if (r < 0) @@ -662,12 +673,7 @@ static int service_load_sysv_path(Service *s, const char *path) { goto finish; } - if (streq(n, file_name_from_path(path))) { - free(n); - continue; - } - - r = sysv_translate_facility(n, &m); + r = sysv_translate_facility(n, file_name_from_path(path), &m); free(n); if (r < 0) @@ -787,12 +793,13 @@ 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; s->remain_after_exit = true; - s->restart = SERVICE_ONCE; + s->restart = SERVICE_RESTART_NO; s->exec_context.std_output = (s->meta.manager->sysv_console || s->exec_context.std_input == EXEC_INPUT_TTY) ? EXEC_OUTPUT_TTY : EXEC_OUTPUT_NULL; @@ -922,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); @@ -1015,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; @@ -1101,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); @@ -1176,6 +1232,9 @@ static int service_get_sockets(Service *s, Set **_set) { if (s->socket_fd >= 0) return 0; + if (!set_isempty(s->configured_sockets)) + return 0; + /* Collects all Socket objects that belong to this * service. Note that a service might have multiple sockets * via multiple names. */ @@ -1215,23 +1274,30 @@ fail: static int service_notify_sockets_dead(Service *s) { Iterator i; - Set *set; + Set *set, *free_set = NULL; Socket *sock; int r; assert(s); + /* Notifies all our sockets when we die */ + if (s->socket_fd >= 0) return 0; - /* Notifies all our sockets when we die */ - if ((r = service_get_sockets(s, &set)) < 0) - return r; + if (!set_isempty(s->configured_sockets)) + set = s->configured_sockets; + else { + if ((r = service_get_sockets(s, &free_set)) < 0) + return r; + + set = free_set; + } SET_FOREACH(sock, set, i) socket_notify_service_dead(sock); - set_free(set); + set_free(free_set); return 0; } @@ -1389,7 +1455,7 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) { int r; int *rfds = NULL; unsigned rn_fds = 0; - Set *set; + Set *set, *free_set = NULL; Socket *sock; assert(s); @@ -1399,8 +1465,14 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) { if (s->socket_fd >= 0) return 0; - if ((r = service_get_sockets(s, &set)) < 0) - return r; + if (!set_isempty(s->configured_sockets)) + set = s->configured_sockets; + else { + if ((r = service_get_sockets(s, &free_set)) < 0) + return r; + + set = free_set; + } SET_FOREACH(sock, set, i) { int *cfds; @@ -1437,7 +1509,7 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) { *fds = rfds; *n_fds = rn_fds; - set_free(set); + set_free(free_set); return 0; @@ -1604,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; @@ -2083,14 +2159,6 @@ static int service_start(Unit *u) { return -ECANCELED; } - if ((s->exec_context.std_input == EXEC_INPUT_SOCKET || - s->exec_context.std_output == EXEC_OUTPUT_SOCKET || - s->exec_context.std_error == EXEC_OUTPUT_SOCKET) && - s->socket_fd < 0) { - log_warning("%s can only be started with a per-connection socket.", u->meta.id); - return -EINVAL; - } - s->failure = false; s->main_pid_known = false; s->forbid_restart = false; @@ -2391,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; @@ -2468,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; @@ -2795,6 +2863,7 @@ static int service_enumerate(Manager *m) { STRV_FOREACH(p, arch_daemons_split) { free(name); + name = NULL; if (**p == '!') /* daemons prefixed with ! are disabled, so ignore them */ continue; @@ -3060,7 +3129,7 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock) { s->socket_fd = fd; s->got_socket_fd = true; - s->socket = sock; + s->accept_socket = sock; return 0; } @@ -3097,9 +3166,11 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = { DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState); static const char* const service_restart_table[_SERVICE_RESTART_MAX] = { - [SERVICE_ONCE] = "once", - [SERVICE_RESTART_ON_SUCCESS] = "restart-on-success", - [SERVICE_RESTART_ALWAYS] = "restart-always", + [SERVICE_RESTART_NO] = "no", + [SERVICE_RESTART_ON_SUCCESS] = "on-success", + [SERVICE_RESTART_ON_FAILURE] = "on-failure", + [SERVICE_RESTART_ON_ABORT] = "on-abort", + [SERVICE_RESTART_ALWAYS] = "always" }; DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);