X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fcore%2Fservice.c;h=6a27e8f67d4826b9d9f750ebb81010e35e073fcc;hb=25fa306ed58b0b7fe30ca9be37c66a7b3b2de70e;hp=223e4b3a414b64153c7d0611b01dcecc487b2df5;hpb=2928b0a863091f8f291fddb168988711afd389ef;p=elogind.git diff --git a/src/core/service.c b/src/core/service.c index 223e4b3a4..6a27e8f67 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -45,6 +45,7 @@ #include "fileio.h" #include "bus-error.h" #include "bus-util.h" +#include "bus-kernel.h" static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = { [SERVICE_DEAD] = UNIT_INACTIVE, @@ -55,6 +56,7 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = { [SERVICE_EXITED] = UNIT_ACTIVE, [SERVICE_RELOAD] = UNIT_RELOADING, [SERVICE_STOP] = UNIT_DEACTIVATING, + [SERVICE_STOP_SIGABRT] = UNIT_DEACTIVATING, [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING, [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING, [SERVICE_STOP_POST] = UNIT_DEACTIVATING, @@ -75,6 +77,7 @@ static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] = [SERVICE_EXITED] = UNIT_ACTIVE, [SERVICE_RELOAD] = UNIT_RELOADING, [SERVICE_STOP] = UNIT_DEACTIVATING, + [SERVICE_STOP_SIGABRT] = UNIT_DEACTIVATING, [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING, [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING, [SERVICE_STOP_POST] = UNIT_DEACTIVATING, @@ -102,6 +105,7 @@ static void service_init(Unit *u) { s->restart_usec = u->manager->default_restart_usec; s->type = _SERVICE_TYPE_INVALID; s->socket_fd = -1; + s->bus_endpoint_fd = -1; s->guess_main_pid = true; RATELIMIT_INIT(s->start_limit, u->manager->default_start_limit_interval, u->manager->default_start_limit_burst); @@ -273,6 +277,7 @@ static void service_done(Unit *u) { s->bus_name = NULL; } + s->bus_endpoint_fd = safe_close(s->bus_endpoint_fd); service_close_socket_fd(s); service_connection_unref(s); @@ -660,7 +665,7 @@ static void service_set_state(Service *s, ServiceState state) { SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD, SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, - SERVICE_STOP_POST, + SERVICE_STOP_SIGABRT, SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_AUTO_RESTART)) s->timer_event_source = sd_event_source_unref(s->timer_event_source); @@ -669,7 +674,7 @@ static void service_set_state(Service *s, ServiceState state) { SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, - SERVICE_STOP_POST, + SERVICE_STOP_SIGABRT, SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { service_unwatch_main_pid(s); s->main_command = NULL; @@ -679,7 +684,7 @@ static void service_set_state(Service *s, ServiceState state) { SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD, SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, - SERVICE_STOP_POST, + SERVICE_STOP_SIGABRT, SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { service_unwatch_control_pid(s); s->control_command = NULL; @@ -693,7 +698,7 @@ static void service_set_state(Service *s, ServiceState state) { SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, - SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) && + SERVICE_STOP_SIGABRT, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) && !(state == SERVICE_DEAD && UNIT(s)->job)) { service_close_socket_fd(s); service_connection_unref(s); @@ -747,7 +752,7 @@ static int service_coldplug(Unit *u) { SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD, SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, - SERVICE_STOP_POST, + SERVICE_STOP_SIGABRT, SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { usec_t k; @@ -776,7 +781,7 @@ static int service_coldplug(Unit *u) { SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, - SERVICE_STOP_POST, + SERVICE_STOP_SIGABRT, SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) { r = unit_watch_pid(UNIT(s), s->main_pid); if (r < 0) @@ -788,7 +793,7 @@ static int service_coldplug(Unit *u) { SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD, SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, - SERVICE_STOP_POST, + SERVICE_STOP_SIGABRT, SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { r = unit_watch_pid(UNIT(s), s->control_pid); if (r < 0) @@ -880,7 +885,6 @@ static int service_spawn( bool apply_permissions, bool apply_chroot, bool apply_tty_stdin, - bool set_notify_socket, bool is_control, pid_t *_pid) { @@ -889,9 +893,17 @@ static int service_spawn( int *fds = NULL; _cleanup_free_ int *fdsbuf = NULL; unsigned n_fds = 0, n_env = 0; + _cleanup_free_ char *bus_endpoint_path = NULL; _cleanup_strv_free_ char **argv = NULL, **final_env = NULL, **our_env = NULL; const char *path; + ExecParameters exec_params = { + .apply_permissions = apply_permissions, + .apply_chroot = apply_chroot, + .apply_tty_stdin = apply_tty_stdin, + .bus_endpoint_fd = -1, + .selinux_context_net = s->socket_fd_selinux_context_net + }; assert(s); assert(c); @@ -937,7 +949,7 @@ static int service_spawn( goto fail; } - if (set_notify_socket) + if (is_control ? s->notify_access == NOTIFY_ALL : s->notify_access != NOTIFY_NONE) if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0) { r = -ENOMEM; goto fail; @@ -967,21 +979,38 @@ static int service_spawn( } else path = UNIT(s)->cgroup_path; +#ifdef ENABLE_KDBUS + if (s->exec_context.bus_endpoint) { + r = bus_kernel_create_endpoint(UNIT(s)->manager->running_as == SYSTEMD_SYSTEM ? "system" : "user", + UNIT(s)->id, &bus_endpoint_path); + if (r < 0) + goto fail; + + /* Pass the fd to the exec_params so that the child process can upload the policy. + * Keep a reference to the fd in the service, so the endpoint is kept alive as long + * as the service is running. */ + exec_params.bus_endpoint_fd = s->bus_endpoint_fd = r; + } +#endif + + exec_params.argv = argv; + exec_params.fds = fds; + exec_params.n_fds = n_fds; + exec_params.environment = final_env; + exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn; + exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported; + exec_params.cgroup_path = path; + exec_params.cgroup_delegate = s->cgroup_context.delegate; + exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager); + exec_params.unit_id = UNIT(s)->id; + exec_params.watchdog_usec = s->watchdog_usec; + exec_params.bus_endpoint_path = bus_endpoint_path; + if (s->type == SERVICE_IDLE) + exec_params.idle_pipe = UNIT(s)->manager->idle_pipe; + r = exec_spawn(c, - argv, &s->exec_context, - fds, n_fds, - final_env, - apply_permissions, - apply_chroot, - apply_tty_stdin, - UNIT(s)->manager->confirm_spawn, - UNIT(s)->manager->cgroup_supported, - path, - manager_get_runtime_prefix(UNIT(s)->manager), - UNIT(s)->id, - s->watchdog_usec, - s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL, + &exec_params, s->exec_runtime, &pid); if (r < 0) @@ -1126,7 +1155,6 @@ static void service_enter_stop_post(Service *s, ServiceResult f) { !s->permissions_start_only, !s->root_directory_start_only, true, - false, true, &s->control_pid); if (r < 0) @@ -1156,7 +1184,8 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f r = unit_kill_context( UNIT(s), &s->kill_context, - state != SERVICE_STOP_SIGTERM && state != SERVICE_FINAL_SIGTERM, + (state != SERVICE_STOP_SIGTERM && state != SERVICE_FINAL_SIGTERM && state != SERVICE_STOP_SIGABRT) ? + KILL_KILL : (state == SERVICE_STOP_SIGABRT ? KILL_ABORT : KILL_TERMINATE), s->main_pid, s->control_pid, s->main_pid_alien); @@ -1172,7 +1201,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f } service_set_state(s, state); - } else if (state == SERVICE_STOP_SIGTERM) + } else if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGABRT) service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_SUCCESS); else if (state == SERVICE_STOP_SIGKILL) service_enter_stop_post(s, SERVICE_SUCCESS); @@ -1186,7 +1215,8 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f fail: log_warning_unit(UNIT(s)->id, "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r)); - if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL) + if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL || + state == SERVICE_STOP_SIGABRT) service_enter_stop_post(s, SERVICE_FAILURE_RESOURCES); else service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true); @@ -1200,7 +1230,8 @@ static void service_enter_stop_by_notify(Service *s) { if (s->timeout_stop_usec > 0) service_arm_timer(s, s->timeout_stop_usec); - service_set_state(s, SERVICE_STOP); + /* The service told us it's stopping, so it's as if we SIGTERM'd it. */ + service_set_state(s, SERVICE_STOP_SIGTERM); } static void service_enter_stop(Service *s, ServiceResult f) { @@ -1225,7 +1256,6 @@ static void service_enter_stop(Service *s, ServiceResult f) { !s->permissions_start_only, !s->root_directory_start_only, false, - false, true, &s->control_pid); if (r < 0) @@ -1288,7 +1318,6 @@ static void service_enter_start_post(Service *s) { !s->permissions_start_only, !s->root_directory_start_only, false, - false, true, &s->control_pid); if (r < 0) @@ -1355,7 +1384,6 @@ static void service_enter_start(Service *s) { true, true, true, - s->notify_access != NOTIFY_NONE, false, &pid); if (r < 0) @@ -1421,7 +1449,6 @@ static void service_enter_start_pre(Service *s) { !s->permissions_start_only, !s->root_directory_start_only, true, - false, true, &s->control_pid); if (r < 0) @@ -1502,7 +1529,6 @@ static void service_enter_reload(Service *s) { !s->permissions_start_only, !s->root_directory_start_only, false, - false, true, &s->control_pid); if (r < 0) @@ -1540,7 +1566,6 @@ static void service_run_next_control(Service *s) { !s->root_directory_start_only, s->control_command_id == SERVICE_EXEC_START_PRE || s->control_command_id == SERVICE_EXEC_STOP_POST, - false, true, &s->control_pid); if (r < 0) @@ -1583,7 +1608,6 @@ static void service_run_next_main(Service *s) { true, true, true, - s->notify_access != NOTIFY_NONE, false, &pid); if (r < 0) @@ -1618,6 +1642,7 @@ static int service_start(Unit *u) { /* We cannot fulfill this request right now, try again later * please! */ if (s->state == SERVICE_STOP || + s->state == SERVICE_STOP_SIGABRT || s->state == SERVICE_STOP_SIGTERM || s->state == SERVICE_STOP_SIGKILL || s->state == SERVICE_STOP_POST || @@ -1676,6 +1701,7 @@ static int service_stop(Unit *u) { /* Already on it */ if (s->state == SERVICE_STOP || + s->state == SERVICE_STOP_SIGABRT || s->state == SERVICE_STOP_SIGTERM || s->state == SERVICE_STOP_SIGKILL || s->state == SERVICE_STOP_POST || @@ -1764,6 +1790,15 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { unit_serialize_item_format(u, f, "socket-fd", "%i", copy); } + if (s->bus_endpoint_fd >= 0) { + int copy; + + if ((copy = fdset_put_dup(fds, s->bus_endpoint_fd)) < 0) + return copy; + + unit_serialize_item_format(u, f, "endpoint-fd", "%i", copy); + } + if (s->main_exec_status.pid > 0) { unit_serialize_item_format(u, f, "main-exec-status-pid", PID_FMT, s->main_exec_status.pid); @@ -1873,10 +1908,18 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) log_debug_unit(u->id, "Failed to parse socket-fd value %s", value); else { - asynchronous_close(s->socket_fd); s->socket_fd = fdset_remove(fds, fd); } + } else if (streq(key, "endpoint-fd")) { + int fd; + + if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_debug_unit(u->id, "Failed to parse endpoint-fd value %s", value); + else { + safe_close(s->bus_endpoint_fd); + s->bus_endpoint_fd = fdset_remove(fds, fd); + } } else if (streq(key, "main-exec-status-pid")) { pid_t pid; @@ -2090,6 +2133,7 @@ static void service_notify_cgroup_empty_event(Unit *u) { service_enter_running(s, SERVICE_SUCCESS); break; + case SERVICE_STOP_SIGABRT: case SERVICE_STOP_SIGTERM: case SERVICE_STOP_SIGKILL: @@ -2216,6 +2260,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { service_enter_running(s, f); break; + case SERVICE_STOP_SIGABRT: case SERVICE_STOP_SIGTERM: case SERVICE_STOP_SIGKILL: @@ -2356,6 +2401,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { service_enter_signal(s, SERVICE_STOP_SIGTERM, f); break; + case SERVICE_STOP_SIGABRT: case SERVICE_STOP_SIGTERM: case SERVICE_STOP_SIGKILL: if (main_pid_good(s) <= 0) @@ -2425,6 +2471,12 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT); break; + case SERVICE_STOP_SIGABRT: + log_warning_unit(UNIT(s)->id, + "%s stop-sigabrt timed out. Terminating.", UNIT(s)->id); + service_enter_signal(s, SERVICE_STOP_SIGTERM, s->result); + break; + case SERVICE_STOP_SIGTERM: if (s->kill_context.send_sigkill) { log_warning_unit(UNIT(s)->id, "%s stop-sigterm timed out. Killing.", UNIT(s)->id); @@ -2492,7 +2544,7 @@ static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void log_error_unit(UNIT(s)->id, "%s watchdog timeout (limit %s)!", UNIT(s)->id, format_timespan(t, sizeof(t), s->watchdog_usec, 1)); - service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_WATCHDOG); + service_enter_signal(s, SERVICE_STOP_SIGABRT, SERVICE_FAILURE_WATCHDOG); return 0; } @@ -2693,7 +2745,7 @@ static void service_bus_name_owner_change( /* Try to acquire PID from bus service */ - r = sd_bus_get_owner(u->manager->api_bus, name, SD_BUS_CREDS_PID, &creds); + r = sd_bus_get_name_creds(u->manager->api_bus, name, SD_BUS_CREDS_PID, &creds); if (r >= 0) r = sd_bus_creds_get_pid(creds, &pid); if (r >= 0) { @@ -2705,7 +2757,7 @@ static void service_bus_name_owner_change( } } -int service_set_socket_fd(Service *s, int fd, Socket *sock) { +int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context_net) { _cleanup_free_ char *peer = NULL; int r; @@ -2743,6 +2795,7 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock) { } s->socket_fd = fd; + s->socket_fd_selinux_context_net = selinux_context_net; unit_ref_set(&s->accept_socket, UNIT(sock)); @@ -2778,6 +2831,7 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = { [SERVICE_EXITED] = "exited", [SERVICE_RELOAD] = "reload", [SERVICE_STOP] = "stop", + [SERVICE_STOP_SIGABRT] = "stop-sigabrt", [SERVICE_STOP_SIGTERM] = "stop-sigterm", [SERVICE_STOP_SIGKILL] = "stop-sigkill", [SERVICE_STOP_POST] = "stop-post",