service: attempt to execute next main command only for oneshot services (#6619)
authorMichal Sekletar <msekletar@users.noreply.github.com>
Fri, 25 Aug 2017 13:36:10 +0000 (15:36 +0200)
committerEvgeny Vereshchagin <evvers@ya.ru>
Fri, 25 Aug 2017 13:36:10 +0000 (16:36 +0300)
This commit fixes crash described in
https://github.com/systemd/systemd/issues/6533

Multiple ExecStart lines are allowed only for oneshot services
anyway so it doesn't make sense to call service_run_next_main() with
services of type other than SERVICE_ONESHOT.

Referring back to reproducer from the issue, previously we didn't observe
this problem because s->main_command was reset after daemon-reload hence
we never reached the assert statement in service_run_next_main().

Fixes #6533

src/core/service.c
test/test-exec-deserialization.py

index e576f4b..0871912 100644 (file)
@@ -2948,6 +2948,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
 
                 if (s->main_command &&
                     s->main_command->command_next &&
+                    s->type == SERVICE_ONESHOT &&
                     f == SERVICE_SUCCESS) {
 
                         /* There is another command to *
index 39a9e62..c3fe082 100755 (executable)
@@ -178,6 +178,37 @@ class ExecutionResumeTest(unittest.TestCase):
 
         self.assertTrue(not os.path.exists(self.output_file))
 
+    def test_issue_6533(self):
+        unit = "test-issue-6533.service"
+        unitfile_path = "/run/systemd/system/{}".format(unit)
+
+        content = '''
+        [Service]
+        ExecStart=/bin/sleep 5
+        '''
+
+        with open(unitfile_path, 'w') as f:
+            f.write(content)
+
+        self.reload()
+
+        subprocess.check_call(['systemctl', '--job-mode=replace', '--no-block', 'start', unit])
+        time.sleep(2)
+
+        content = '''
+        [Service]
+        ExecStart=/bin/sleep 5
+        ExecStart=/bin/true
+        '''
+
+        with open(unitfile_path, 'w') as f:
+            f.write(content)
+
+        self.reload()
+        time.sleep(5)
+
+        self.assertTrue(subprocess.call("journalctl -b _PID=1  | grep -q 'Freezing execution'", shell=True) != 0)
+
     def tearDown(self):
         for f in [self.output_file, self.unitfile_path]:
             try: