diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2019-08-25 11:20:56 +0200 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2019-08-28 16:09:54 +0200 |
commit | c968d76a382f905b419cacd23a6b20aa31aca580 (patch) | |
tree | ef22cef88423bf54f05b338125f23eeb1183a329 | |
parent | core: introduce unit_fork_and_watch_rm_rf() (diff) | |
download | systemd-c968d76a382f905b419cacd23a6b20aa31aca580.tar.xz systemd-c968d76a382f905b419cacd23a6b20aa31aca580.zip |
core/socket: support "systemctl clean" for socket units
-rw-r--r-- | src/basic/unit-def.c | 3 | ||||
-rw-r--r-- | src/basic/unit-def.h | 1 | ||||
-rw-r--r-- | src/core/socket.c | 95 | ||||
-rw-r--r-- | src/core/socket.h | 1 |
4 files changed, 93 insertions, 7 deletions
diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c index cc7e953c10..e0928f9c02 100644 --- a/src/basic/unit-def.c +++ b/src/basic/unit-def.c @@ -204,7 +204,8 @@ static const char* const socket_state_table[_SOCKET_STATE_MAX] = { [SOCKET_STOP_POST] = "stop-post", [SOCKET_FINAL_SIGTERM] = "final-sigterm", [SOCKET_FINAL_SIGKILL] = "final-sigkill", - [SOCKET_FAILED] = "failed" + [SOCKET_FAILED] = "failed", + [SOCKET_CLEANING] = "cleaning", }; DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState); diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h index c7b4235bea..9155c500a3 100644 --- a/src/basic/unit-def.h +++ b/src/basic/unit-def.h @@ -147,6 +147,7 @@ typedef enum SocketState { SOCKET_FINAL_SIGTERM, SOCKET_FINAL_SIGKILL, SOCKET_FAILED, + SOCKET_CLEANING, _SOCKET_STATE_MAX, _SOCKET_STATE_INVALID = -1 } SocketState; diff --git a/src/core/socket.c b/src/core/socket.c index 46fe405a17..e6ba60ffa6 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -67,7 +67,8 @@ static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = { [SOCKET_STOP_POST] = UNIT_DEACTIVATING, [SOCKET_FINAL_SIGTERM] = UNIT_DEACTIVATING, [SOCKET_FINAL_SIGKILL] = UNIT_DEACTIVATING, - [SOCKET_FAILED] = UNIT_FAILED + [SOCKET_FAILED] = UNIT_FAILED, + [SOCKET_CLEANING] = UNIT_MAINTENANCE, }; static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); @@ -624,6 +625,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { fprintf(f, "%sSocket State: %s\n" "%sResult: %s\n" + "%sClean Result: %s\n" "%sBindIPv6Only: %s\n" "%sBacklog: %u\n" "%sSocketMode: %04o\n" @@ -642,6 +644,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { "%sSELinuxContextFromNet: %s\n", prefix, socket_state_to_string(s->state), prefix, socket_result_to_string(s->result), + prefix, socket_result_to_string(s->clean_result), prefix, socket_address_bind_ipv6_only_to_string(s->bind_ipv6_only), prefix, s->backlog, prefix, s->socket_mode, @@ -1802,7 +1805,8 @@ static void socket_set_state(Socket *s, SocketState state) { SOCKET_STOP_PRE_SIGKILL, SOCKET_STOP_POST, SOCKET_FINAL_SIGTERM, - SOCKET_FINAL_SIGKILL)) { + SOCKET_FINAL_SIGKILL, + SOCKET_CLEANING)) { s->timer_event_source = sd_event_source_unref(s->timer_event_source); socket_unwatch_control_pid(s); @@ -1820,7 +1824,8 @@ static void socket_set_state(Socket *s, SocketState state) { SOCKET_RUNNING, SOCKET_STOP_PRE, SOCKET_STOP_PRE_SIGTERM, - SOCKET_STOP_PRE_SIGKILL)) + SOCKET_STOP_PRE_SIGKILL, + SOCKET_CLEANING)) socket_close_fds(s); if (state != old_state) @@ -1850,7 +1855,8 @@ static int socket_coldplug(Unit *u) { SOCKET_STOP_PRE_SIGKILL, SOCKET_STOP_POST, SOCKET_FINAL_SIGTERM, - SOCKET_FINAL_SIGKILL)) { + SOCKET_FINAL_SIGKILL, + SOCKET_CLEANING)) { r = unit_watch_pid(UNIT(s), s->control_pid, false); if (r < 0) @@ -1891,7 +1897,7 @@ static int socket_coldplug(Unit *u) { return r; } - if (!IN_SET(s->deserialized_state, SOCKET_DEAD, SOCKET_FAILED)) { + if (!IN_SET(s->deserialized_state, SOCKET_DEAD, SOCKET_FAILED, SOCKET_CLEANING)) { (void) unit_setup_dynamic_creds(u); (void) unit_setup_exec_runtime(u); } @@ -2455,7 +2461,8 @@ static int socket_start(Unit *u) { SOCKET_STOP_PRE_SIGTERM, SOCKET_STOP_POST, SOCKET_FINAL_SIGTERM, - SOCKET_FINAL_SIGKILL)) + SOCKET_FINAL_SIGKILL, + SOCKET_CLEANING)) return -EAGAIN; /* Already on it! */ @@ -2530,6 +2537,12 @@ static int socket_stop(Unit *u) { return -EAGAIN; } + /* If we are currently cleaning, then abort it, brutally. */ + if (s->state == SOCKET_CLEANING) { + socket_enter_signal(s, SOCKET_FINAL_SIGKILL, SOCKET_SUCCESS); + return 0; + } + assert(IN_SET(s->state, SOCKET_LISTENING, SOCKET_RUNNING)); socket_enter_stop_pre(s, SOCKET_SUCCESS); @@ -3073,6 +3086,14 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) { socket_enter_dead(s, f); break; + case SOCKET_CLEANING: + + if (s->clean_result == SOCKET_SUCCESS) + s->clean_result = f; + + socket_enter_dead(s, SOCKET_SUCCESS); + break; + default: assert_not_reached("Uh, control process died at wrong time."); } @@ -3141,6 +3162,15 @@ static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *use socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT); break; + case SOCKET_CLEANING: + log_unit_warning(UNIT(s), "Cleaning timed out. killing."); + + if (s->clean_result == SOCKET_SUCCESS) + s->clean_result = SOCKET_FAILURE_TIMEOUT; + + socket_enter_signal(s, SOCKET_FINAL_SIGKILL, 0); + break; + default: assert_not_reached("Timeout at wrong time."); } @@ -3197,6 +3227,7 @@ static void socket_reset_failed(Unit *u) { socket_set_state(s, SOCKET_DEAD); s->result = SOCKET_SUCCESS; + s->clean_result = SOCKET_SUCCESS; } void socket_connection_unref(Socket *s) { @@ -3291,6 +3322,56 @@ static int socket_control_pid(Unit *u) { return s->control_pid; } +static int socket_clean(Unit *u, ExecCleanMask mask) { + _cleanup_strv_free_ char **l = NULL; + Socket *s = SOCKET(u); + int r; + + assert(s); + assert(mask != 0); + + if (s->state != SOCKET_DEAD) + return -EBUSY; + + r = exec_context_get_clean_directories(&s->exec_context, u->manager->prefix, mask, &l); + if (r < 0) + return r; + + if (strv_isempty(l)) + return -EUNATCH; + + socket_unwatch_control_pid(s); + s->clean_result = SOCKET_SUCCESS; + s->control_command = NULL; + s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID; + + r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->exec_context.timeout_clean_usec)); + if (r < 0) + goto fail; + + r = unit_fork_and_watch_rm_rf(u, l, &s->control_pid); + if (r < 0) + goto fail; + + socket_set_state(s, SOCKET_CLEANING); + + return 0; + +fail: + log_unit_warning_errno(u, r, "Failed to initiate cleaning: %m"); + s->clean_result = SOCKET_FAILURE_RESOURCES; + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + return r; +} + +static int socket_can_clean(Unit *u, ExecCleanMask *ret) { + Socket *s = SOCKET(u); + + assert(s); + + return exec_context_get_clean_mask(&s->exec_context, ret); +} + static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = { [SOCKET_EXEC_START_PRE] = "ExecStartPre", [SOCKET_EXEC_START_CHOWN] = "ExecStartChown", @@ -3343,6 +3424,8 @@ const UnitVTable socket_vtable = { .stop = socket_stop, .kill = socket_kill, + .clean = socket_clean, + .can_clean = socket_can_clean, .get_timeout = socket_get_timeout, diff --git a/src/core/socket.h b/src/core/socket.h index c4e25db1fc..9e0be15ba8 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -103,6 +103,7 @@ struct Socket { mode_t socket_mode; SocketResult result; + SocketResult clean_result; char **symlinks; |