ff2b41
From 8c9d6639a22d32734d950db37bfb852a1464c621 Mon Sep 17 00:00:00 2001
ff2b41
From: Lennart Poettering <lennart@poettering.net>
ff2b41
Date: Mon, 10 Oct 2016 22:07:30 +0200
ff2b41
Subject: [PATCH] core: when determining whether a process exit status is
ff2b41
 clean, consider whether it is a command or a daemon
ff2b41
ff2b41
SIGTERM should be considered a clean exit code for daemons (i.e. long-running
ff2b41
processes, as a daemon without SIGTERM handler may be shut down without issues
ff2b41
via SIGTERM still) while it should not be considered a clean exit code for
ff2b41
commands (i.e. short-running processes).
ff2b41
ff2b41
Let's add two different clean checking modes for this, and use the right one at
ff2b41
the appropriate places.
ff2b41
ff2b41
Fixes: #4275
ff2b41
(cherry picked from commit 1f0958f640b87175cd547c1e69084cfe54a22e9d)
ff2b41
ff2b41
Resolves: #1560417
ff2b41
---
ff2b41
 src/core/busname.c          |  2 +-
ff2b41
 src/core/mount.c            |  2 +-
ff2b41
 src/core/service.c          |  2 +-
ff2b41
 src/core/socket.c           |  2 +-
ff2b41
 src/core/swap.c             |  2 +-
ff2b41
 src/remount-fs/remount-fs.c |  2 +-
ff2b41
 src/shared/exit-status.c    | 13 ++++---------
ff2b41
 src/shared/exit-status.h    |  7 ++++++-
ff2b41
 8 files changed, 16 insertions(+), 16 deletions(-)
ff2b41
ff2b41
diff --git a/src/core/busname.c b/src/core/busname.c
ff2b41
index 97886f1e05..f5553e5418 100644
ff2b41
--- a/src/core/busname.c
ff2b41
+++ b/src/core/busname.c
ff2b41
@@ -849,7 +849,7 @@ static void busname_sigchld_event(Unit *u, pid_t pid, int code, int status) {
ff2b41
 
ff2b41
         n->control_pid = 0;
ff2b41
 
ff2b41
-        if (is_clean_exit(code, status, NULL))
ff2b41
+        if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
ff2b41
                 f = BUSNAME_SUCCESS;
ff2b41
         else if (code == CLD_EXITED)
ff2b41
                 f = BUSNAME_FAILURE_EXIT_CODE;
ff2b41
diff --git a/src/core/mount.c b/src/core/mount.c
ff2b41
index 8a25ebd163..bfbfc10731 100644
ff2b41
--- a/src/core/mount.c
ff2b41
+++ b/src/core/mount.c
ff2b41
@@ -1203,7 +1203,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
ff2b41
 
ff2b41
         m->control_pid = 0;
ff2b41
 
ff2b41
-        if (is_clean_exit(code, status, NULL))
ff2b41
+        if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
ff2b41
                 f = MOUNT_SUCCESS;
ff2b41
         else if (code == CLD_EXITED)
ff2b41
                 f = MOUNT_FAILURE_EXIT_CODE;
ff2b41
diff --git a/src/core/service.c b/src/core/service.c
ff2b41
index 6b61ccac18..f7b859d076 100644
ff2b41
--- a/src/core/service.c
ff2b41
+++ b/src/core/service.c
ff2b41
@@ -2632,7 +2632,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
ff2b41
         assert(s);
ff2b41
         assert(pid >= 0);
ff2b41
 
ff2b41
-        if (UNIT(s)->fragment_path ? is_clean_exit(code, status, &s->success_status) :
ff2b41
+        if (UNIT(s)->fragment_path ? is_clean_exit(code, status, s->type == SERVICE_ONESHOT ? EXIT_CLEAN_COMMAND : EXIT_CLEAN_DAEMON, &s->success_status) :
ff2b41
                                      is_clean_exit_lsb(code, status, &s->success_status))
ff2b41
                 f = SERVICE_SUCCESS;
ff2b41
         else if (code == CLD_EXITED)
ff2b41
diff --git a/src/core/socket.c b/src/core/socket.c
ff2b41
index 8489575de6..1e8ae0a6e5 100644
ff2b41
--- a/src/core/socket.c
ff2b41
+++ b/src/core/socket.c
ff2b41
@@ -2344,7 +2344,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
ff2b41
 
ff2b41
         s->control_pid = 0;
ff2b41
 
ff2b41
-        if (is_clean_exit(code, status, NULL))
ff2b41
+        if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
ff2b41
                 f = SOCKET_SUCCESS;
ff2b41
         else if (code == CLD_EXITED)
ff2b41
                 f = SOCKET_FAILURE_EXIT_CODE;
ff2b41
diff --git a/src/core/swap.c b/src/core/swap.c
ff2b41
index 1f69736aa3..757a8d45c5 100644
ff2b41
--- a/src/core/swap.c
ff2b41
+++ b/src/core/swap.c
ff2b41
@@ -972,7 +972,7 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
ff2b41
 
ff2b41
         s->control_pid = 0;
ff2b41
 
ff2b41
-        if (is_clean_exit(code, status, NULL))
ff2b41
+        if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
ff2b41
                 f = SWAP_SUCCESS;
ff2b41
         else if (code == CLD_EXITED)
ff2b41
                 f = SWAP_FAILURE_EXIT_CODE;
ff2b41
diff --git a/src/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c
ff2b41
index 57b47021e4..db9ae391b8 100644
ff2b41
--- a/src/remount-fs/remount-fs.c
ff2b41
+++ b/src/remount-fs/remount-fs.c
ff2b41
@@ -142,7 +142,7 @@ int main(int argc, char *argv[]) {
ff2b41
 
ff2b41
                 s = hashmap_remove(pids, UINT_TO_PTR(si.si_pid));
ff2b41
                 if (s) {
ff2b41
-                        if (!is_clean_exit(si.si_code, si.si_status, NULL)) {
ff2b41
+                        if (!is_clean_exit(si.si_code, si.si_status, EXIT_CLEAN_COMMAND, NULL)) {
ff2b41
                                 if (si.si_code == CLD_EXITED)
ff2b41
                                         log_error("/bin/mount for %s exited with exit status %i.", s, si.si_status);
ff2b41
                                 else
ff2b41
diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c
ff2b41
index 90c83a47a8..ab09550d7a 100644
ff2b41
--- a/src/shared/exit-status.c
ff2b41
+++ b/src/shared/exit-status.c
ff2b41
@@ -180,22 +180,17 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
ff2b41
         return NULL;
ff2b41
 }
ff2b41
 
ff2b41
-
ff2b41
-bool is_clean_exit(int code, int status, ExitStatusSet *success_status) {
ff2b41
+bool is_clean_exit(int code, int status, ExitClean clean, ExitStatusSet *success_status) {
ff2b41
 
ff2b41
         if (code == CLD_EXITED)
ff2b41
                 return status == 0 ||
ff2b41
                        (success_status &&
ff2b41
                        set_contains(success_status->status, INT_TO_PTR(status)));
ff2b41
 
ff2b41
-        /* If a daemon does not implement handlers for some of the
ff2b41
-         * signals that's not considered an unclean shutdown */
ff2b41
+        /* If a daemon does not implement handlers for some of the signals that's not considered an unclean shutdown */
ff2b41
         if (code == CLD_KILLED)
ff2b41
                 return
ff2b41
-                        status == SIGHUP ||
ff2b41
-                        status == SIGINT ||
ff2b41
-                        status == SIGTERM ||
ff2b41
-                        status == SIGPIPE ||
ff2b41
+                        (clean == EXIT_CLEAN_DAEMON && IN_SET(status, SIGHUP, SIGINT, SIGTERM, SIGPIPE)) ||
ff2b41
                         (success_status &&
ff2b41
                         set_contains(success_status->signal, INT_TO_PTR(status)));
ff2b41
 
ff2b41
@@ -204,7 +199,7 @@ bool is_clean_exit(int code, int status, ExitStatusSet *success_status) {
ff2b41
 
ff2b41
 bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status) {
ff2b41
 
ff2b41
-        if (is_clean_exit(code, status, success_status))
ff2b41
+        if (is_clean_exit(code, status, EXIT_CLEAN_DAEMON, success_status))
ff2b41
                 return true;
ff2b41
 
ff2b41
         return
ff2b41
diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h
ff2b41
index 1d774f25dc..f7953aecb1 100644
ff2b41
--- a/src/shared/exit-status.h
ff2b41
+++ b/src/shared/exit-status.h
ff2b41
@@ -95,7 +95,12 @@ typedef struct ExitStatusSet {
ff2b41
 
ff2b41
 const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) _const_;
ff2b41
 
ff2b41
-bool is_clean_exit(int code, int status, ExitStatusSet *success_status);
ff2b41
+typedef enum ExitClean {
ff2b41
+        EXIT_CLEAN_DAEMON,
ff2b41
+        EXIT_CLEAN_COMMAND,
ff2b41
+} ExitClean;
ff2b41
+
ff2b41
+bool is_clean_exit(int code, int status, ExitClean clean, ExitStatusSet *success_status);
ff2b41
 bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status);
ff2b41
 
ff2b41
 void exit_status_set_free(ExitStatusSet *x);