]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/service.c
tree-wide: define iterator inside of the macro
[thirdparty/systemd.git] / src / core / service.c
index 340b655059196d139db1e57470064689198de23f..14c90c26df43ac52844df2a735fdd47941e807b5 100644 (file)
@@ -56,6 +56,7 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
         [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
         [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
         [SERVICE_STOP_POST] = UNIT_DEACTIVATING,
+        [SERVICE_FINAL_WATCHDOG] = UNIT_DEACTIVATING,
         [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
         [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
         [SERVICE_FAILED] = UNIT_FAILED,
@@ -79,6 +80,7 @@ static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] =
         [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
         [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
         [SERVICE_STOP_POST] = UNIT_DEACTIVATING,
+        [SERVICE_FINAL_WATCHDOG] = UNIT_DEACTIVATING,
         [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
         [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
         [SERVICE_FAILED] = UNIT_FAILED,
@@ -857,10 +859,14 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
         fprintf(f,
                 "%sRestartSec: %s\n"
                 "%sTimeoutStartSec: %s\n"
-                "%sTimeoutStopSec: %s\n",
+                "%sTimeoutStopSec: %s\n"
+                "%sTimeoutStartFailureMode: %s\n"
+                "%sTimeoutStopFailureMode: %s\n",
                 prefix, format_timespan(buf_restart, sizeof(buf_restart), s->restart_usec, USEC_PER_SEC),
                 prefix, format_timespan(buf_start, sizeof(buf_start), s->timeout_start_usec, USEC_PER_SEC),
-                prefix, format_timespan(buf_stop, sizeof(buf_stop), s->timeout_stop_usec, USEC_PER_SEC));
+                prefix, format_timespan(buf_stop, sizeof(buf_stop), s->timeout_stop_usec, USEC_PER_SEC),
+                prefix, service_timeout_failure_mode_to_string(s->timeout_start_failure_mode),
+                prefix, service_timeout_failure_mode_to_string(s->timeout_stop_failure_mode));
 
         if (s->timeout_abort_set)
                 fprintf(f,
@@ -1028,7 +1034,7 @@ static void service_search_main_pid(Service *s) {
 
         assert(s);
 
-        /* If we know it anyway, don't ever fallback to unreliable
+        /* If we know it anyway, don't ever fall back to unreliable
          * heuristics */
         if (s->main_pid_known)
                 return;
@@ -1072,7 +1078,7 @@ static void service_set_state(Service *s, ServiceState state) {
                     SERVICE_RUNNING,
                     SERVICE_RELOAD,
                     SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                    SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
+                    SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
                     SERVICE_AUTO_RESTART,
                     SERVICE_CLEANING))
                 s->timer_event_source = sd_event_source_unref(s->timer_event_source);
@@ -1081,7 +1087,7 @@ static void service_set_state(Service *s, ServiceState state) {
                     SERVICE_START, SERVICE_START_POST,
                     SERVICE_RUNNING, SERVICE_RELOAD,
                     SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                    SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
+                    SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
                 service_unwatch_main_pid(s);
                 s->main_command = NULL;
         }
@@ -1090,7 +1096,7 @@ static void service_set_state(Service *s, ServiceState state) {
                     SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
                     SERVICE_RELOAD,
                     SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                    SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
+                    SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
                     SERVICE_CLEANING)) {
                 service_unwatch_control_pid(s);
                 s->control_command = NULL;
@@ -1106,7 +1112,7 @@ static void service_set_state(Service *s, ServiceState state) {
                     SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
                     SERVICE_RUNNING, SERVICE_RELOAD,
                     SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                    SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
+                    SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
             !(state == SERVICE_DEAD && UNIT(s)->job))
                 service_close_socket_fd(s);
 
@@ -1154,6 +1160,7 @@ static usec_t service_coldplug_timeout(Service *s) {
                 return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_stop_usec);
 
         case SERVICE_STOP_WATCHDOG:
+        case SERVICE_FINAL_WATCHDOG:
                 return usec_add(UNIT(s)->state_change_timestamp.monotonic, service_timeout_abort_usec(s));
 
         case SERVICE_AUTO_RESTART:
@@ -1187,7 +1194,7 @@ static int service_coldplug(Unit *u) {
                     SERVICE_START, SERVICE_START_POST,
                     SERVICE_RUNNING, SERVICE_RELOAD,
                     SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                    SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
+                    SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
                 r = unit_watch_pid(UNIT(s), s->main_pid, false);
                 if (r < 0)
                         return r;
@@ -1199,7 +1206,7 @@ static int service_coldplug(Unit *u) {
                    SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
                    SERVICE_RELOAD,
                    SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                   SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
+                   SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
                    SERVICE_CLEANING)) {
                 r = unit_watch_pid(UNIT(s), s->control_pid, false);
                 if (r < 0)
@@ -1266,13 +1273,12 @@ static int service_collect_fds(
 
                 rn_socket_fds = 1;
         } else {
-                Iterator i;
                 void *v;
                 Unit *u;
 
                 /* Pass all our configured sockets for singleton services */
 
-                HASHMAP_FOREACH_KEY(v, u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
+                HASHMAP_FOREACH_KEY(v, u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY]) {
                         _cleanup_free_ int *cfds = NULL;
                         Socket *sock;
                         int cn_fds;
@@ -1435,17 +1441,15 @@ static int service_spawn(
                 pid_t *_pid) {
 
         _cleanup_(exec_params_clear) ExecParameters exec_params = {
-                .flags      = flags,
-                .stdin_fd   = -1,
-                .stdout_fd  = -1,
-                .stderr_fd  = -1,
-                .exec_fd    = -1,
+                .flags     = flags,
+                .stdin_fd  = -1,
+                .stdout_fd = -1,
+                .stderr_fd = -1,
+                .exec_fd   = -1,
         };
-        _cleanup_strv_free_ char **final_env = NULL, **our_env = NULL, **fd_names = NULL;
         _cleanup_(sd_event_source_unrefp) sd_event_source *exec_fd_source = NULL;
-        size_t n_socket_fds = 0, n_storage_fds = 0, n_env = 0;
-        _cleanup_close_ int exec_fd = -1;
-        _cleanup_free_ int *fds = NULL;
+        _cleanup_strv_free_ char **final_env = NULL, **our_env = NULL;
+        size_t n_env = 0;
         pid_t pid;
         int r;
 
@@ -1470,17 +1474,21 @@ static int service_spawn(
             s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
             s->exec_context.std_error == EXEC_OUTPUT_SOCKET) {
 
-                r = service_collect_fds(s, &fds, &fd_names, &n_socket_fds, &n_storage_fds);
+                r = service_collect_fds(s,
+                                        &exec_params.fds,
+                                        &exec_params.fd_names,
+                                        &exec_params.n_socket_fds,
+                                        &exec_params.n_storage_fds);
                 if (r < 0)
                         return r;
 
-                log_unit_debug(UNIT(s), "Passing %zu fds to service", n_socket_fds + n_storage_fds);
+                log_unit_debug(UNIT(s), "Passing %zu fds to service", exec_params.n_socket_fds + exec_params.n_storage_fds);
         }
 
         if (!FLAGS_SET(flags, EXEC_IS_CONTROL) && s->type == SERVICE_EXEC) {
                 assert(!s->exec_fd_event_source);
 
-                r = service_allocate_exec_fd(s, &exec_fd_source, &exec_fd);
+                r = service_allocate_exec_fd(s, &exec_fd_source, &exec_params.exec_fd);
                 if (r < 0)
                         return r;
         }
@@ -1520,7 +1528,6 @@ static int service_spawn(
 
                 if (getpeername(s->socket_fd, &sa.sa, &salen) >= 0 &&
                     IN_SET(sa.sa.sa_family, AF_INET, AF_INET6, AF_VSOCK)) {
-
                         _cleanup_free_ char *addr = NULL;
                         char *t;
                         unsigned port;
@@ -1575,10 +1582,6 @@ static int service_spawn(
                  MANAGER_IS_SYSTEM(UNIT(s)->manager) && unit_has_name(UNIT(s), SPECIAL_DBUS_SERVICE));
 
         strv_free_and_replace(exec_params.environment, final_env);
-        exec_params.fds = fds;
-        exec_params.fd_names = fd_names;
-        exec_params.n_socket_fds = n_socket_fds;
-        exec_params.n_storage_fds = n_storage_fds;
         exec_params.watchdog_usec = service_get_watchdog_usec(s);
         exec_params.selinux_context_net = s->socket_fd_selinux_context_net;
         if (s->type == SERVICE_IDLE)
@@ -1586,7 +1589,6 @@ static int service_spawn(
         exec_params.stdin_fd = s->stdin_fd;
         exec_params.stdout_fd = s->stdout_fd;
         exec_params.stderr_fd = s->stderr_fd;
-        exec_params.exec_fd = exec_fd;
 
         r = exec_spawn(UNIT(s),
                        c,
@@ -1696,10 +1698,10 @@ static bool service_shall_restart(Service *s, const char **reason) {
                 return s->result == SERVICE_SUCCESS;
 
         case SERVICE_RESTART_ON_FAILURE:
-                return s->result != SERVICE_SUCCESS;
+                return !IN_SET(s->result, SERVICE_SUCCESS, SERVICE_SKIP_CONDITION);
 
         case SERVICE_RESTART_ON_ABNORMAL:
-                return !IN_SET(s->result, SERVICE_SUCCESS, SERVICE_FAILURE_EXIT_CODE);
+                return !IN_SET(s->result, SERVICE_SUCCESS, SERVICE_FAILURE_EXIT_CODE, SERVICE_SKIP_CONDITION);
 
         case SERVICE_RESTART_ON_WATCHDOG:
                 return s->result == SERVICE_FAILURE_WATCHDOG;
@@ -1798,7 +1800,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
         s->exec_runtime = exec_runtime_unref(s->exec_runtime, true);
 
         /* Also, remove the runtime directory */
-        unit_destroy_runtime_directory(UNIT(s), &s->exec_context);
+        unit_destroy_runtime_data(UNIT(s), &s->exec_context);
 
         /* Get rid of the IPC bits of the user */
         unit_unref_uid_gid(UNIT(s), true);
@@ -1859,6 +1861,7 @@ static int state_to_kill_operation(Service *s, ServiceState state) {
         switch (state) {
 
         case SERVICE_STOP_WATCHDOG:
+        case SERVICE_FINAL_WATCHDOG:
                 return KILL_WATCHDOG;
 
         case SERVICE_STOP_SIGTERM:
@@ -1879,7 +1882,7 @@ static int state_to_kill_operation(Service *s, ServiceState state) {
 }
 
 static void service_enter_signal(Service *s, ServiceState state, ServiceResult f) {
-        int r;
+        int kill_operation, r;
 
         assert(s);
 
@@ -1893,10 +1896,11 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
          * died now */
         (void) unit_enqueue_rewatch_pids(UNIT(s));
 
+        kill_operation = state_to_kill_operation(s, state);
         r = unit_kill_context(
                         UNIT(s),
                         &s->kill_context,
-                        state_to_kill_operation(s, state),
+                        kill_operation,
                         s->main_pid,
                         s->control_pid,
                         s->main_pid_alien);
@@ -1905,7 +1909,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
 
         if (r > 0) {
                 r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC),
-                                      state == SERVICE_STOP_WATCHDOG ? service_timeout_abort_usec(s) : s->timeout_stop_usec));
+                                      kill_operation == KILL_WATCHDOG ? service_timeout_abort_usec(s) : s->timeout_stop_usec));
                 if (r < 0)
                         goto fail;
 
@@ -1914,7 +1918,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
                 service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_SUCCESS);
         else if (IN_SET(state, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL))
                 service_enter_stop_post(s, SERVICE_SUCCESS);
-        else if (state == SERVICE_FINAL_SIGTERM && s->kill_context.send_sigkill)
+        else if (IN_SET(state, SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM) && s->kill_context.send_sigkill)
                 service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_SUCCESS);
         else
                 service_enter_dead(s, SERVICE_SUCCESS, true);
@@ -2123,9 +2127,9 @@ static void service_enter_start(Service *s) {
 
         if (!c) {
                 if (s->type != SERVICE_ONESHOT) {
-                        /* There's no command line configured for the main command? Hmm, that is strange. This can only
-                         * happen if the configuration changes at runtime. In this case, let's enter a failure
-                         * state. */
+                        /* There's no command line configured for the main command? Hmm, that is strange.
+                         * This can only happen if the configuration changes at runtime. In this case,
+                         * let's enter a failure state. */
                         log_unit_error(UNIT(s), "There's no 'start' task anymore we could start.");
                         r = -ENXIO;
                         goto fail;
@@ -2151,7 +2155,7 @@ static void service_enter_start(Service *s) {
         r = service_spawn(s,
                           c,
                           timeout,
-                          EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG,
+                          EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG|EXEC_WRITE_CREDENTIALS,
                           &pid);
         if (r < 0)
                 goto fail;
@@ -2444,7 +2448,7 @@ static int service_start(Unit *u) {
          * please! */
         if (IN_SET(s->state,
                    SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                   SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_CLEANING))
+                   SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_CLEANING))
                 return -EAGAIN;
 
         /* Already on it! */
@@ -2515,7 +2519,7 @@ static int service_stop(Unit *u) {
         /* Already on it */
         if (IN_SET(s->state,
                    SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                   SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))
+                   SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))
                 return 0;
 
         /* A restart will be scheduled or is in progress. */
@@ -3321,6 +3325,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
                 break;
 
         case SERVICE_STOP_POST:
+        case SERVICE_FINAL_WATCHDOG:
         case SERVICE_FINAL_SIGTERM:
         case SERVICE_FINAL_SIGKILL:
                 if (main_pid_good(s) <= 0 && control_pid_good(s) <= 0)
@@ -3521,6 +3526,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
 
                                 break;
 
+                        case SERVICE_FINAL_WATCHDOG:
                         case SERVICE_FINAL_SIGTERM:
                         case SERVICE_FINAL_SIGKILL:
 
@@ -3674,6 +3680,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                                         service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
                                 break;
 
+                        case SERVICE_FINAL_WATCHDOG:
                         case SERVICE_FINAL_SIGTERM:
                         case SERVICE_FINAL_SIGKILL:
                                 if (main_pid_good(s) <= 0)
@@ -3720,13 +3727,32 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
         case SERVICE_CONDITION:
         case SERVICE_START_PRE:
         case SERVICE_START:
-                log_unit_warning(UNIT(s), "%s operation timed out. Terminating.", service_state_to_string(s->state));
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
-                break;
-
         case SERVICE_START_POST:
-                log_unit_warning(UNIT(s), "Start-post operation timed out. Stopping.");
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                switch (s->timeout_start_failure_mode) {
+
+                case SERVICE_TIMEOUT_TERMINATE:
+                        log_unit_warning(UNIT(s), "%s operation timed out. Terminating.", service_state_to_string(s->state));
+                        service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                        break;
+
+                case SERVICE_TIMEOUT_ABORT:
+                        log_unit_warning(UNIT(s), "%s operation timed out. Aborting.", service_state_to_string(s->state));
+                        service_enter_signal(s, SERVICE_STOP_WATCHDOG, SERVICE_FAILURE_TIMEOUT);
+                        break;
+
+                case SERVICE_TIMEOUT_KILL:
+                        if (s->kill_context.send_sigkill) {
+                                log_unit_warning(UNIT(s), "%s operation timed out. Killing.", service_state_to_string(s->state));
+                                service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+                        } else {
+                                log_unit_warning(UNIT(s), "%s operation timed out. Skipping SIGKILL.", service_state_to_string(s->state));
+                                service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
+                        }
+                        break;
+
+                default:
+                        assert_not_reached("unknown timeout mode");
+                }
                 break;
 
         case SERVICE_RUNNING:
@@ -3742,17 +3768,48 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
                 break;
 
         case SERVICE_STOP:
-                log_unit_warning(UNIT(s), "Stopping timed out. Terminating.");
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                switch (s->timeout_stop_failure_mode) {
+
+                case SERVICE_TIMEOUT_TERMINATE:
+                        log_unit_warning(UNIT(s), "Stopping timed out. Terminating.");
+                        service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                        break;
+
+                case SERVICE_TIMEOUT_ABORT:
+                        log_unit_warning(UNIT(s), "Stopping timed out. Aborting.");
+                        service_enter_signal(s, SERVICE_STOP_WATCHDOG, SERVICE_FAILURE_TIMEOUT);
+                        break;
+
+                case SERVICE_TIMEOUT_KILL:
+                        if (s->kill_context.send_sigkill) {
+                                log_unit_warning(UNIT(s), "Stopping timed out. Killing.");
+                                service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+                        } else {
+                                log_unit_warning(UNIT(s), "Stopping timed out. Skipping SIGKILL.");
+                                service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
+                        }
+                        break;
+
+                default:
+                        assert_not_reached("unknown timeout mode");
+                }
                 break;
 
         case SERVICE_STOP_WATCHDOG:
-                log_unit_warning(UNIT(s), "State 'stop-watchdog' timed out. Terminating.");
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                if (s->kill_context.send_sigkill) {
+                        log_unit_warning(UNIT(s), "State 'stop-watchdog' timed out. Killing.");
+                        service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+                } else {
+                        log_unit_warning(UNIT(s), "State 'stop-watchdog' timed out. Skipping SIGKILL.");
+                        service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
+                }
                 break;
 
         case SERVICE_STOP_SIGTERM:
-                if (s->kill_context.send_sigkill) {
+                if (s->timeout_stop_failure_mode == SERVICE_TIMEOUT_ABORT) {
+                        log_unit_warning(UNIT(s), "State 'stop-sigterm' timed out. Aborting.");
+                        service_enter_signal(s, SERVICE_STOP_WATCHDOG, SERVICE_FAILURE_TIMEOUT);
+                } else if (s->kill_context.send_sigkill) {
                         log_unit_warning(UNIT(s), "State 'stop-sigterm' timed out. Killing.");
                         service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
                 } else {
@@ -3772,16 +3829,52 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
                 break;
 
         case SERVICE_STOP_POST:
-                log_unit_warning(UNIT(s), "State 'stop-post' timed out. Terminating.");
-                service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                switch (s->timeout_stop_failure_mode) {
+
+                case SERVICE_TIMEOUT_TERMINATE:
+                        log_unit_warning(UNIT(s), "State 'stop-post' timed out. Terminating.");
+                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+                        break;
+
+                case SERVICE_TIMEOUT_ABORT:
+                        log_unit_warning(UNIT(s), "State 'stop-post' timed out. Aborting.");
+                        service_enter_signal(s, SERVICE_FINAL_WATCHDOG, SERVICE_FAILURE_TIMEOUT);
+                        break;
+
+                case SERVICE_TIMEOUT_KILL:
+                        if (s->kill_context.send_sigkill) {
+                                log_unit_warning(UNIT(s), "State 'stop-post' timed out. Killing.");
+                                service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+                        } else {
+                                log_unit_warning(UNIT(s), "State 'stop-post' timed out. Skipping SIGKILL. Entering failed mode.");
+                                service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
+                        }
+                        break;
+
+                default:
+                        assert_not_reached("unknown timeout mode");
+                }
                 break;
 
-        case SERVICE_FINAL_SIGTERM:
+        case SERVICE_FINAL_WATCHDOG:
                 if (s->kill_context.send_sigkill) {
-                        log_unit_warning(UNIT(s), "State 'stop-final-sigterm' timed out. Killing.");
+                        log_unit_warning(UNIT(s), "State 'final-watchdog' timed out. Killing.");
                         service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
                 } else {
-                        log_unit_warning(UNIT(s), "State 'stop-final-sigterm' timed out. Skipping SIGKILL. Entering failed mode.");
+                        log_unit_warning(UNIT(s), "State 'final-watchdog' timed out. Skipping SIGKILL. Entering failed mode.");
+                        service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
+                }
+                break;
+
+        case SERVICE_FINAL_SIGTERM:
+                if (s->timeout_stop_failure_mode == SERVICE_TIMEOUT_ABORT) {
+                        log_unit_warning(UNIT(s), "State 'final-sigterm' timed out. Aborting.");
+                        service_enter_signal(s, SERVICE_FINAL_WATCHDOG, SERVICE_FAILURE_TIMEOUT);
+                } else if (s->kill_context.send_sigkill) {
+                        log_unit_warning(UNIT(s), "State 'final-sigterm' timed out. Killing.");
+                        service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
+                } else {
+                        log_unit_warning(UNIT(s), "State 'final-sigterm' timed out. Skipping SIGKILL. Entering failed mode.");
                         service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
                 }
 
@@ -4263,6 +4356,7 @@ static bool service_needs_console(Unit *u) {
                       SERVICE_STOP_SIGTERM,
                       SERVICE_STOP_SIGKILL,
                       SERVICE_STOP_POST,
+                      SERVICE_FINAL_WATCHDOG,
                       SERVICE_FINAL_SIGTERM,
                       SERVICE_FINAL_SIGKILL);
 }
@@ -4417,6 +4511,14 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = {
 
 DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);
 
+static const char* const service_timeout_failure_mode_table[_SERVICE_TIMEOUT_FAILURE_MODE_MAX] = {
+        [SERVICE_TIMEOUT_TERMINATE] = "terminate",
+        [SERVICE_TIMEOUT_ABORT] = "abort",
+        [SERVICE_TIMEOUT_KILL] = "kill",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_timeout_failure_mode, ServiceTimeoutFailureMode);
+
 const UnitVTable service_vtable = {
         .object_size = sizeof(Service),
         .exec_context_offset = offsetof(Service, exec_context),