summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2019-08-25 11:20:56 +0200
committerYu Watanabe <watanabe.yu+github@gmail.com>2019-08-28 16:09:54 +0200
commitc968d76a382f905b419cacd23a6b20aa31aca580 (patch)
treeef22cef88423bf54f05b338125f23eeb1183a329
parentcore: introduce unit_fork_and_watch_rm_rf() (diff)
downloadsystemd-c968d76a382f905b419cacd23a6b20aa31aca580.tar.xz
systemd-c968d76a382f905b419cacd23a6b20aa31aca580.zip
core/socket: support "systemctl clean" for socket units
-rw-r--r--src/basic/unit-def.c3
-rw-r--r--src/basic/unit-def.h1
-rw-r--r--src/core/socket.c95
-rw-r--r--src/core/socket.h1
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;