7e7c9f
From b1135a4f292a4bc193bcef768898d06f8b732215 Mon Sep 17 00:00:00 2001
7e7c9f
From: Anita Zhang <the.anitazha@gmail.com>
7e7c9f
Date: Sat, 25 Jan 2020 16:46:16 +0100
7e7c9f
Subject: [PATCH] core: transition to FINAL_SIGTERM state after ExecStopPost=
7e7c9f
7e7c9f
Fixes #14566
7e7c9f
7e7c9f
(cherry picked from commit c1566ef0d22ed786b9ecf4c476e53b8a91e67578)
7e7c9f
7e7c9f
Resolves: #1766477
7e7c9f
---
7e7c9f
 src/core/service.c                    | 10 +++
7e7c9f
 test/TEST-47-ISSUE-14566/Makefile     |  1 +
7e7c9f
 test/TEST-47-ISSUE-14566/repro.sh     |  5 ++
7e7c9f
 test/TEST-47-ISSUE-14566/test.sh      | 91 +++++++++++++++++++++++++++
7e7c9f
 test/TEST-47-ISSUE-14566/testsuite.sh | 21 +++++++
7e7c9f
 5 files changed, 128 insertions(+)
7e7c9f
 create mode 120000 test/TEST-47-ISSUE-14566/Makefile
7e7c9f
 create mode 100755 test/TEST-47-ISSUE-14566/repro.sh
7e7c9f
 create mode 100755 test/TEST-47-ISSUE-14566/test.sh
7e7c9f
 create mode 100755 test/TEST-47-ISSUE-14566/testsuite.sh
7e7c9f
7e7c9f
diff --git a/src/core/service.c b/src/core/service.c
7e7c9f
index e32cdf4594..7f0e6df412 100644
7e7c9f
--- a/src/core/service.c
7e7c9f
+++ b/src/core/service.c
7e7c9f
@@ -2751,6 +2751,12 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
7e7c9f
                                 break;
7e7c9f
 
7e7c9f
                         case SERVICE_STOP_POST:
7e7c9f
+
7e7c9f
+                                if (control_pid_good(s) <= 0)
7e7c9f
+                                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
7e7c9f
+
7e7c9f
+                                break;
7e7c9f
+
7e7c9f
                         case SERVICE_FINAL_SIGTERM:
7e7c9f
                         case SERVICE_FINAL_SIGKILL:
7e7c9f
 
7e7c9f
@@ -2894,6 +2900,10 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
7e7c9f
                                 break;
7e7c9f
 
7e7c9f
                         case SERVICE_STOP_POST:
7e7c9f
+                                if (main_pid_good(s) <= 0)
7e7c9f
+                                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
7e7c9f
+                                break;
7e7c9f
+
7e7c9f
                         case SERVICE_FINAL_SIGTERM:
7e7c9f
                         case SERVICE_FINAL_SIGKILL:
7e7c9f
                                 if (main_pid_good(s) <= 0)
7e7c9f
diff --git a/test/TEST-47-ISSUE-14566/Makefile b/test/TEST-47-ISSUE-14566/Makefile
7e7c9f
new file mode 120000
7e7c9f
index 0000000000..e9f93b1104
7e7c9f
--- /dev/null
7e7c9f
+++ b/test/TEST-47-ISSUE-14566/Makefile
7e7c9f
@@ -0,0 +1 @@
7e7c9f
+../TEST-01-BASIC/Makefile
7e7c9f
\ No newline at end of file
7e7c9f
diff --git a/test/TEST-47-ISSUE-14566/repro.sh b/test/TEST-47-ISSUE-14566/repro.sh
7e7c9f
new file mode 100755
7e7c9f
index 0000000000..5217602257
7e7c9f
--- /dev/null
7e7c9f
+++ b/test/TEST-47-ISSUE-14566/repro.sh
7e7c9f
@@ -0,0 +1,5 @@
7e7c9f
+#!/bin/bash
7e7c9f
+
7e7c9f
+sleep infinity &
7e7c9f
+echo $! > /leakedtestpid
7e7c9f
+wait $!
7e7c9f
diff --git a/test/TEST-47-ISSUE-14566/test.sh b/test/TEST-47-ISSUE-14566/test.sh
7e7c9f
new file mode 100755
7e7c9f
index 0000000000..35d72d17ee
7e7c9f
--- /dev/null
7e7c9f
+++ b/test/TEST-47-ISSUE-14566/test.sh
7e7c9f
@@ -0,0 +1,91 @@
7e7c9f
+#!/bin/bash
7e7c9f
+TEST_DESCRIPTION="Test that KillMode=mixed does not leave left over proccesses with ExecStopPost="
7e7c9f
+. $TEST_BASE_DIR/test-functions
7e7c9f
+
7e7c9f
+check_result_qemu() {
7e7c9f
+    ret=1
7e7c9f
+    mkdir -p $TESTDIR/root
7e7c9f
+    mount ${LOOPDEV}p1 $TESTDIR/root
7e7c9f
+    [[ -e $TESTDIR/root/testok ]] && ret=0
7e7c9f
+    [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
7e7c9f
+    [[ -f $TESTDIR/root/var/log/journal ]] && cp -a $TESTDIR/root/var/log/journal $TESTDIR
7e7c9f
+    umount $TESTDIR/root
7e7c9f
+    [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
7e7c9f
+    ls -l $TESTDIR/journal/*/*.journal
7e7c9f
+    test -s $TESTDIR/failed && ret=$(($ret+1))
7e7c9f
+    return $ret
7e7c9f
+}
7e7c9f
+
7e7c9f
+test_run() {
7e7c9f
+    if run_qemu; then
7e7c9f
+        check_result_qemu || return 1
7e7c9f
+    else
7e7c9f
+        dwarn "can't run QEMU, skipping"
7e7c9f
+    fi
7e7c9f
+    if check_nspawn; then
7e7c9f
+        run_nspawn
7e7c9f
+        check_result_nspawn || return 1
7e7c9f
+    else
7e7c9f
+        dwarn "can't run systemd-nspawn, skipping"
7e7c9f
+    fi
7e7c9f
+    return 0
7e7c9f
+}
7e7c9f
+
7e7c9f
+test_setup() {
7e7c9f
+    create_empty_image
7e7c9f
+    mkdir -p $TESTDIR/root
7e7c9f
+    mount ${LOOPDEV}p1 $TESTDIR/root
7e7c9f
+
7e7c9f
+    (
7e7c9f
+        LOG_LEVEL=5
7e7c9f
+        eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
7e7c9f
+
7e7c9f
+        setup_basic_environment
7e7c9f
+
7e7c9f
+        # mask some services that we do not want to run in these tests
7e7c9f
+        ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
7e7c9f
+        ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
7e7c9f
+        ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service
7e7c9f
+        ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
7e7c9f
+        ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service
7e7c9f
+
7e7c9f
+        # setup the testsuite service
7e7c9f
+        cat >$initdir/etc/systemd/system/testsuite.service <
7e7c9f
+[Unit]
7e7c9f
+Description=Testsuite service
7e7c9f
+
7e7c9f
+[Service]
7e7c9f
+ExecStart=/testsuite.sh
7e7c9f
+Type=oneshot
7e7c9f
+StandardOutput=tty
7e7c9f
+StandardError=tty
7e7c9f
+NotifyAccess=all
7e7c9f
+EOF
7e7c9f
+        cat > $initdir/etc/systemd/system/issue_14566_test.service << EOF
7e7c9f
+[Unit]
7e7c9f
+Description=Issue 14566 Repro
7e7c9f
+
7e7c9f
+[Service]
7e7c9f
+ExecStart=/repro.sh
7e7c9f
+ExecStopPost=/bin/true
7e7c9f
+KillMode=mixed
7e7c9f
+EOF
7e7c9f
+
7e7c9f
+        cp testsuite.sh $initdir/
7e7c9f
+        cp repro.sh $initdir/
7e7c9f
+
7e7c9f
+        setup_testsuite
7e7c9f
+    )
7e7c9f
+    setup_nspawn_root
7e7c9f
+
7e7c9f
+    ddebug "umount $TESTDIR/root"
7e7c9f
+    umount $TESTDIR/root
7e7c9f
+}
7e7c9f
+
7e7c9f
+test_cleanup() {
7e7c9f
+    umount $TESTDIR/root 2>/dev/null
7e7c9f
+    [[ $LOOPDEV ]] && losetup -d $LOOPDEV
7e7c9f
+    return 0
7e7c9f
+}
7e7c9f
+
7e7c9f
+do_test "$@"
7e7c9f
diff --git a/test/TEST-47-ISSUE-14566/testsuite.sh b/test/TEST-47-ISSUE-14566/testsuite.sh
7e7c9f
new file mode 100755
7e7c9f
index 0000000000..6363266713
7e7c9f
--- /dev/null
7e7c9f
+++ b/test/TEST-47-ISSUE-14566/testsuite.sh
7e7c9f
@@ -0,0 +1,21 @@
7e7c9f
+#!/bin/bash
7e7c9f
+set -ex
7e7c9f
+
7e7c9f
+systemd-analyze set-log-level debug
7e7c9f
+
7e7c9f
+systemctl start issue_14566_test
7e7c9f
+systemctl status issue_14566_test
7e7c9f
+
7e7c9f
+leaked_pid=$(cat /leakedtestpid)
7e7c9f
+
7e7c9f
+systemctl stop issue_14566_test
7e7c9f
+
7e7c9f
+# Leaked PID will still be around if we're buggy.
7e7c9f
+# I personally prefer to see 42.
7e7c9f
+ps -p "$leaked_pid" && exit 42
7e7c9f
+
7e7c9f
+systemd-analyze log-level info
7e7c9f
+
7e7c9f
+echo OK > /testok
7e7c9f
+
7e7c9f
+exit 0