]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core/socket: support "systemctl clean" for socket units
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 25 Aug 2019 09:20:56 +0000 (18:20 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 28 Aug 2019 14:09:54 +0000 (23:09 +0900)
src/basic/unit-def.c
src/basic/unit-def.h
src/core/socket.c
src/core/socket.h

index cc7e953c10560676f9014703325805933840240f..e0928f9c027a485f71bb2efc225879ad6860bf2a 100644 (file)
@@ -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);
index c7b4235bea7bdbafb47a028c6f06ae9cb7b05c02..9155c500a32175f0606c56885c8797c1b0dc3126 100644 (file)
@@ -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;
index 46fe405a17d7212e12e490065ffc4d122cec9085..e6ba60ffa63840aad4530c00e313669b4a4f9c04 100644 (file)
@@ -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,
 
index c4e25db1fca7133cf96acda75a958e38d7a94b2a..9e0be15ba8d6e5226464ca9fd82b9905a5d75b6f 100644 (file)
@@ -103,6 +103,7 @@ struct Socket {
         mode_t socket_mode;
 
         SocketResult result;
+        SocketResult clean_result;
 
         char **symlinks;