X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=socket.c;h=3b74b5e9f82ab15279b7589331d35f44963023ec;hp=617a49a07509abe2eaf6310bb164d420adc129a3;hb=40531a555ae313543c0fbb80137edbae71eee773;hpb=a90ebccc072efa17313fe68c737b3507247c37dd diff --git a/socket.c b/socket.c index 617a49a07..3b74b5e9f 100644 --- a/socket.c +++ b/socket.c @@ -43,8 +43,8 @@ static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = { [SOCKET_STOP_PRE_SIGTERM] = UNIT_DEACTIVATING, [SOCKET_STOP_PRE_SIGKILL] = UNIT_DEACTIVATING, [SOCKET_STOP_POST] = UNIT_DEACTIVATING, - [SOCKET_STOP_POST_SIGTERM] = UNIT_DEACTIVATING, - [SOCKET_STOP_POST_SIGKILL] = UNIT_DEACTIVATING, + [SOCKET_FINAL_SIGTERM] = UNIT_DEACTIVATING, + [SOCKET_FINAL_SIGKILL] = UNIT_DEACTIVATING, [SOCKET_MAINTAINANCE] = UNIT_INACTIVE, }; @@ -58,11 +58,21 @@ static const char* const state_string_table[_SOCKET_STATE_MAX] = { [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm", [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill", [SOCKET_STOP_POST] = "stop-post", - [SOCKET_STOP_POST_SIGTERM] = "stop-post-sigterm", - [SOCKET_STOP_POST_SIGKILL] = "stop-post-sigkill", + [SOCKET_FINAL_SIGTERM] = "final-sigterm", + [SOCKET_FINAL_SIGKILL] = "final-sigkill", [SOCKET_MAINTAINANCE] = "maintainance" }; +static void socket_unwatch_control_pid(Socket *s) { + assert(s); + + if (s->control_pid <= 0) + return; + + unit_unwatch_pid(UNIT(s), s->control_pid); + s->control_pid = 0; +} + static void socket_done(Unit *u) { Socket *s = SOCKET(u); SocketPort *p; @@ -79,28 +89,24 @@ static void socket_done(Unit *u) { } exec_context_done(&s->exec_context); - exec_command_free_array(s->exec_command, _SOCKET_EXEC_MAX); + exec_command_free_array(s->exec_command, _SOCKET_EXEC_COMMAND_MAX); s->control_command = NULL; - if (s->control_pid > 0) { - unit_unwatch_pid(u, s->control_pid); - s->control_pid = 0; - } + socket_unwatch_control_pid(s); s->service = NULL; free(s->bind_to_device); + s->bind_to_device = NULL; unit_unwatch_timer(u, &s->timer_watch); } -static int socket_init(Unit *u, UnitLoadState *new_state) { +static void socket_init(Unit *u) { Socket *s = SOCKET(u); - char *t; - int r; - /* First, reset everything to the defaults, in case this is a - * reload */ + assert(u); + assert(u->meta.load_state == UNIT_STUB); s->state = 0; s->timer_watch.type = WATCH_INVALID; @@ -112,27 +118,24 @@ static int socket_init(Unit *u, UnitLoadState *new_state) { s->kill_mode = 0; s->failure = false; s->control_pid = 0; + s->service = NULL; exec_context_init(&s->exec_context); +} - if ((r = unit_load_fragment(u, new_state)) < 0) - return r; +static int socket_load(Unit *u) { + Socket *s = SOCKET(u); + int r; - if (*new_state == UNIT_STUB) - return -ENOENT; + assert(u); + assert(u->meta.load_state == UNIT_STUB); - if ((r = unit_load_dropin(unit_follow_merge(u))) < 0) + if ((r = unit_load_fragment_and_dropin(u)) < 0) return r; /* This is a new unit? Then let's add in some extras */ - if (*new_state == UNIT_LOADED) { - - if (!(t = unit_name_change_suffix(unit_id(u), ".service"))) - return -ENOMEM; + if (u->meta.load_state == UNIT_LOADED) { - r = manager_load_unit(u->meta.manager, t, (Unit**) &s->service); - free(t); - - if (r < 0) + if ((r = unit_load_related_unit(u, ".service", (Unit**) &s->service))) return r; if ((r = unit_add_dependency(u, UNIT_BEFORE, UNIT(s->service))) < 0) @@ -163,7 +166,7 @@ static const char* listen_lookup(int type) { static void socket_dump(Unit *u, FILE *f, const char *prefix) { - static const char* const command_table[_SOCKET_EXEC_MAX] = { + static const char* const command_table[_SOCKET_EXEC_COMMAND_MAX] = { [SOCKET_EXEC_START_PRE] = "StartPre", [SOCKET_EXEC_START_POST] = "StartPost", [SOCKET_EXEC_STOP_PRE] = "StopPre", @@ -196,6 +199,11 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { prefix, s->socket_mode, prefix, s->directory_mode); + if (s->control_pid > 0) + fprintf(f, + "%sControl PID: %llu\n", + prefix, (unsigned long long) s->control_pid); + if (s->bind_to_device) fprintf(f, "%sBindToDevice: %s\n", @@ -221,7 +229,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { exec_context_dump(&s->exec_context, f, prefix); - for (c = 0; c < _SOCKET_EXEC_MAX; c++) { + for (c = 0; c < _SOCKET_EXEC_COMMAND_MAX; c++) { if (!s->exec_command[c]) continue; @@ -357,28 +365,12 @@ static void socket_set_state(Socket *s, SocketState state) { state != SOCKET_STOP_PRE_SIGTERM && state != SOCKET_STOP_PRE_SIGKILL && state != SOCKET_STOP_POST && - state != SOCKET_STOP_POST_SIGTERM && - state != SOCKET_STOP_POST_SIGKILL) + state != SOCKET_FINAL_SIGTERM && + state != SOCKET_FINAL_SIGKILL) { unit_unwatch_timer(UNIT(s), &s->timer_watch); - - if (state != SOCKET_START_PRE && - state != SOCKET_START_POST && - state != SOCKET_STOP_PRE && - state != SOCKET_STOP_PRE_SIGTERM && - state != SOCKET_STOP_PRE_SIGKILL && - state != SOCKET_STOP_POST && - state != SOCKET_STOP_POST_SIGTERM && - state != SOCKET_STOP_POST_SIGKILL) - if (s->control_pid > 0) { - unit_unwatch_pid(UNIT(s), s->control_pid); - s->control_pid = 0; - } - - if (state != SOCKET_START_PRE && - state != SOCKET_START_POST && - state != SOCKET_STOP_PRE && - state != SOCKET_STOP_POST) + socket_unwatch_control_pid(s); s->control_command = NULL; + } if (state != SOCKET_START_POST && state != SOCKET_LISTENING && @@ -391,15 +383,13 @@ static void socket_set_state(Socket *s, SocketState state) { if (state != SOCKET_LISTENING) socket_unwatch_fds(s); - if (state == old_state) - return; - - log_debug("%s changed %s → %s", unit_id(UNIT(s)), state_string_table[old_state], state_string_table[state]); + if (state != old_state) + log_debug("%s changed %s → %s", unit_id(UNIT(s)), state_string_table[old_state], state_string_table[state]); unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]); } -static int socket_spawn(Socket *s, ExecCommand *c, bool timeout, pid_t *_pid) { +static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { pid_t pid; int r; @@ -407,17 +397,15 @@ static int socket_spawn(Socket *s, ExecCommand *c, bool timeout, pid_t *_pid) { assert(c); assert(_pid); - if (timeout) { - if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) - goto fail; - } else - unit_unwatch_timer(UNIT(s), &s->timer_watch); + if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) + goto fail; if ((r = exec_spawn(c, &s->exec_context, NULL, 0, true, true, + UNIT(s)->meta.manager->confirm_spawn, UNIT(s)->meta.cgroup_bondings, &pid)) < 0) goto fail; @@ -431,8 +419,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, bool timeout, pid_t *_pid) { return 0; fail: - if (timeout) - unit_unwatch_timer(UNIT(s), &s->timer_watch); + unit_unwatch_timer(UNIT(s), &s->timer_watch); return r; } @@ -446,6 +433,8 @@ static void socket_enter_dead(Socket *s, bool success) { socket_set_state(s, s->failure ? SOCKET_MAINTAINANCE : SOCKET_DEAD); } +static void socket_enter_signal(Socket *s, SocketState state, bool success); + static void socket_enter_stop_post(Socket *s, bool success) { int r; assert(s); @@ -453,35 +442,34 @@ static void socket_enter_stop_post(Socket *s, bool success) { if (!success) s->failure = true; - if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST])) - if ((r = socket_spawn(s, s->control_command, true, &s->control_pid)) < 0) - goto fail; + socket_unwatch_control_pid(s); - socket_set_state(s, SOCKET_STOP_POST); + if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST])) { + if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) + goto fail; - if (!s->control_command) - socket_enter_dead(s, true); + socket_set_state(s, SOCKET_STOP_POST); + } else + socket_enter_signal(s, SOCKET_FINAL_SIGTERM, true); return; fail: log_warning("%s failed to run stop-post executable: %s", unit_id(UNIT(s)), strerror(-r)); - socket_enter_dead(s, false); + socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false); } static void socket_enter_signal(Socket *s, SocketState state, bool success) { int r; + bool sent = false; assert(s); if (!success) s->failure = true; - if (s->control_pid > 0) { - int sig; - bool sent = false; - - sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_POST_SIGTERM) ? SIGTERM : SIGKILL; + if (s->kill_mode != KILL_NONE) { + int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? SIGTERM : SIGKILL; if (s->kill_mode == KILL_CONTROL_GROUP) { @@ -492,17 +480,21 @@ static void socket_enter_signal(Socket *s, SocketState state, bool success) { sent = true; } - if (!sent) + if (!sent && s->control_pid > 0) if (kill(s->kill_mode == KILL_PROCESS ? s->control_pid : -s->control_pid, sig) < 0 && errno != ESRCH) { r = -errno; goto fail; } - } - socket_set_state(s, state); + if (sent) { + if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) + goto fail; - if (s->control_pid <= 0) + socket_set_state(s, state); + } else if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL) + socket_enter_stop_post(s, true); + else socket_enter_dead(s, true); return; @@ -523,13 +515,14 @@ static void socket_enter_stop_pre(Socket *s, bool success) { if (!success) s->failure = true; - if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_PRE])) - if ((r = socket_spawn(s, s->control_command, true, &s->control_pid)) < 0) - goto fail; + socket_unwatch_control_pid(s); - socket_set_state(s, SOCKET_STOP_PRE); + if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_PRE])) { + if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) + goto fail; - if (!s->control_command) + socket_set_state(s, SOCKET_STOP_PRE); + } else socket_enter_stop_post(s, true); return; @@ -564,15 +557,16 @@ static void socket_enter_start_post(Socket *s) { goto fail; } - if ((s->control_command = s->exec_command[SOCKET_EXEC_START_POST])) - if ((r = socket_spawn(s, s->control_command, true, &s->control_pid)) < 0) { + socket_unwatch_control_pid(s); + + if ((s->control_command = s->exec_command[SOCKET_EXEC_START_POST])) { + if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) { log_warning("%s failed to run start-post executable: %s", unit_id(UNIT(s)), strerror(-r)); goto fail; } - socket_set_state(s, SOCKET_START_POST); - - if (!s->control_command) + socket_set_state(s, SOCKET_START_POST); + } else socket_enter_listening(s); return; @@ -585,13 +579,14 @@ static void socket_enter_start_pre(Socket *s) { int r; assert(s); - if ((s->control_command = s->exec_command[SOCKET_EXEC_START_PRE])) - if ((r = socket_spawn(s, s->control_command, true, &s->control_pid)) < 0) - goto fail; + socket_unwatch_control_pid(s); - socket_set_state(s, SOCKET_START_PRE); + if ((s->control_command = s->exec_command[SOCKET_EXEC_START_PRE])) { + if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) + goto fail; - if (!s->control_command) + socket_set_state(s, SOCKET_START_PRE); + } else socket_enter_start_post(s); return; @@ -614,7 +609,7 @@ static void socket_enter_running(Socket *s) { fail: log_warning("%s failed to queue socket startup job: %s", unit_id(UNIT(s)), strerror(-r)); - socket_enter_dead(s, false); + socket_enter_stop_pre(s, false); } static void socket_run_next(Socket *s, bool success) { @@ -627,20 +622,24 @@ static void socket_run_next(Socket *s, bool success) { if (!success) s->failure = true; + socket_unwatch_control_pid(s); + s->control_command = s->control_command->command_next; - if ((r = socket_spawn(s, s->control_command, true, &s->control_pid)) < 0) + if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) goto fail; return; fail: - if (s->state == SOCKET_STOP_PRE) - socket_enter_stop_post(s, false); + log_warning("%s failed to run spawn next executable: %s", unit_id(UNIT(s)), strerror(-r)); + + if (s->state == SOCKET_START_POST) + socket_enter_stop_pre(s, false); else if (s->state == SOCKET_STOP_POST) socket_enter_dead(s, false); else - socket_enter_stop_pre(s, false); + socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false); } static int socket_start(Unit *u) { @@ -654,8 +653,8 @@ static int socket_start(Unit *u) { s->state == SOCKET_STOP_PRE_SIGKILL || s->state == SOCKET_STOP_PRE_SIGTERM || s->state == SOCKET_STOP_POST || - s->state == SOCKET_STOP_POST_SIGTERM || - s->state == SOCKET_STOP_POST_SIGKILL) + s->state == SOCKET_FINAL_SIGTERM || + s->state == SOCKET_FINAL_SIGKILL) return -EAGAIN; if (s->state == SOCKET_START_PRE || @@ -666,6 +665,13 @@ static int socket_start(Unit *u) { if (s->service->meta.load_state != UNIT_LOADED) return -ENOENT; + /* If the service is alredy actvie we cannot start the + * socket */ + if (s->service->state != SERVICE_DEAD && + s->service->state != SERVICE_MAINTAINANCE && + s->service->state != SERVICE_AUTO_RESTART) + return -EBUSY; + assert(s->state == SOCKET_DEAD || s->state == SOCKET_MAINTAINANCE); s->failure = false; @@ -684,6 +690,15 @@ static int socket_stop(Unit *u) { s->state == SOCKET_START_POST) return -EAGAIN; + /* Already on it */ + if (s->state == SOCKET_STOP_PRE || + s->state == SOCKET_STOP_PRE_SIGTERM || + s->state == SOCKET_STOP_PRE_SIGKILL || + s->state == SOCKET_STOP_POST || + s->state == SOCKET_FINAL_SIGTERM || + s->state == SOCKET_FINAL_SIGTERM) + return 0; + assert(s->state == SOCKET_LISTENING || s->state == SOCKET_RUNNING); socket_enter_stop_pre(s, true); @@ -727,9 +742,8 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) { log_debug("%s control process exited, code=%s status=%i", unit_id(u), sigchld_code_to_string(code), status); - if (s->control_command->command_next && - (success || (s->state == SOCKET_STOP_PRE || s->state == SOCKET_STOP_POST))) { - log_debug("%s running next command for the state %s", unit_id(u), state_string_table[s->state]); + if (s->control_command->command_next && success) { + log_debug("%s running next command for state %s", unit_id(u), state_string_table[s->state]); socket_run_next(s, success); } else { /* No further commands for this step, so let's figure @@ -743,7 +757,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) { if (success) socket_enter_start_post(s); else - socket_enter_stop_pre(s, false); + socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false); break; case SOCKET_START_POST: @@ -760,8 +774,8 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) { break; case SOCKET_STOP_POST: - case SOCKET_STOP_POST_SIGTERM: - case SOCKET_STOP_POST_SIGKILL: + case SOCKET_FINAL_SIGTERM: + case SOCKET_FINAL_SIGKILL: socket_enter_dead(s, success); break; @@ -776,14 +790,16 @@ static void socket_timer_event(Unit *u, uint64_t elapsed, Watch *w) { assert(s); assert(elapsed == 1); - assert(w == &s->timer_watch); switch (s->state) { case SOCKET_START_PRE: + log_warning("%s starting timed out. Terminating.", unit_id(u)); + socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false); + case SOCKET_START_POST: - log_warning("%s operation timed out. Stopping.", unit_id(u)); + log_warning("%s starting timed out. Stopping.", unit_id(u)); socket_enter_stop_pre(s, false); break; @@ -804,15 +820,15 @@ static void socket_timer_event(Unit *u, uint64_t elapsed, Watch *w) { case SOCKET_STOP_POST: log_warning("%s stopping timed out (2). Terminating.", unit_id(u)); - socket_enter_signal(s, SOCKET_STOP_POST_SIGTERM, false); + socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false); break; - case SOCKET_STOP_POST_SIGTERM: + case SOCKET_FINAL_SIGTERM: log_warning("%s stopping timed out (2). Killing.", unit_id(u)); - socket_enter_signal(s, SOCKET_STOP_POST_SIGKILL, false); + socket_enter_signal(s, SOCKET_FINAL_SIGKILL, false); break; - case SOCKET_STOP_POST_SIGKILL: + case SOCKET_FINAL_SIGKILL: log_warning("%s still around after SIGKILL (2). Entering maintainance mode.", unit_id(u)); socket_enter_dead(s, false); break; @@ -869,6 +885,7 @@ const UnitVTable socket_vtable = { .suffix = ".socket", .init = socket_init, + .load = socket_load, .done = socket_done, .dump = socket_dump,