Zbigniew Jędrzejewski-Szmek 62fe94
From 96fb8242cc1ef6b0e28f6c86a4f57950095dd7f1 Mon Sep 17 00:00:00 2001
Zbigniew Jędrzejewski-Szmek 62fe94
From: Lennart Poettering <lennart@poettering.net>
Zbigniew Jędrzejewski-Szmek 62fe94
Date: Thu, 21 Aug 2014 18:50:42 +0200
Zbigniew Jędrzejewski-Szmek 62fe94
Subject: [PATCH] service: allow services of Type=oneshot that specify no
Zbigniew Jędrzejewski-Szmek 62fe94
 ExecStart= commands
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
This is useful for services that simply want to run something on
Zbigniew Jędrzejewski-Szmek 62fe94
shutdown, but not at bootup. They should only set ExecStop= but leave
Zbigniew Jędrzejewski-Szmek 62fe94
ExecStart= unset.
Zbigniew Jędrzejewski-Szmek 62fe94
---
Zbigniew Jędrzejewski-Szmek 62fe94
 man/systemd.service.xml | 44 +++++++++++++++++++++++++++-----------------
Zbigniew Jędrzejewski-Szmek 62fe94
 src/core/service.c      | 39 +++++++++++++++++++++++++++++----------
Zbigniew Jędrzejewski-Szmek 62fe94
 2 files changed, 56 insertions(+), 27 deletions(-)
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
Zbigniew Jędrzejewski-Szmek 62fe94
index 5c4bd6569f..e584a1f006 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/man/systemd.service.xml
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/man/systemd.service.xml
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -139,9 +139,10 @@
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
                                 <para>If set to
Zbigniew Jędrzejewski-Szmek 62fe94
                                 <option>simple</option> (the default
Zbigniew Jędrzejewski-Szmek 62fe94
-                                value if neither
Zbigniew Jędrzejewski-Szmek 62fe94
+                                if neither
Zbigniew Jędrzejewski-Szmek 62fe94
                                 <varname>Type=</varname> nor
Zbigniew Jędrzejewski-Szmek 62fe94
-                                <varname>BusName=</varname> are
Zbigniew Jędrzejewski-Szmek 62fe94
+                                <varname>BusName=</varname>, but
Zbigniew Jędrzejewski-Szmek 62fe94
+                                <varname>ExecStart=</varname> are
Zbigniew Jędrzejewski-Szmek 62fe94
                                 specified), it is expected that the
Zbigniew Jędrzejewski-Szmek 62fe94
                                 process configured with
Zbigniew Jędrzejewski-Szmek 62fe94
                                 <varname>ExecStart=</varname> is the
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -177,13 +178,17 @@
Zbigniew Jędrzejewski-Szmek 62fe94
                                 exits.</para>
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
                                 <para>Behavior of
Zbigniew Jędrzejewski-Szmek 62fe94
-                                <option>oneshot</option> is similar
Zbigniew Jędrzejewski-Szmek 62fe94
-                                to <option>simple</option>; however,
Zbigniew Jędrzejewski-Szmek 62fe94
-                                it is expected that the process has to
Zbigniew Jędrzejewski-Szmek 62fe94
+                                <option>oneshot</option> is similar to
Zbigniew Jędrzejewski-Szmek 62fe94
+                                <option>simple</option>; however, it
Zbigniew Jędrzejewski-Szmek 62fe94
+                                is expected that the process has to
Zbigniew Jędrzejewski-Szmek 62fe94
                                 exit before systemd starts follow-up
Zbigniew Jędrzejewski-Szmek 62fe94
                                 units. <varname>RemainAfterExit=</varname>
Zbigniew Jędrzejewski-Szmek 62fe94
                                 is particularly useful for this type
Zbigniew Jędrzejewski-Szmek 62fe94
-                                of service.</para>
Zbigniew Jędrzejewski-Szmek 62fe94
+                                of service. This is the implied
Zbigniew Jędrzejewski-Szmek 62fe94
+                                default if neither
Zbigniew Jędrzejewski-Szmek 62fe94
+                                <varname>Type=</varname> or
Zbigniew Jędrzejewski-Szmek 62fe94
+                                <varname>ExecStart=</varname> are
Zbigniew Jędrzejewski-Szmek 62fe94
+                                specified.</para>
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
                                 <para>Behavior of
Zbigniew Jędrzejewski-Szmek 62fe94
                                 <option>dbus</option> is similar to
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -313,22 +318,27 @@
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
                                 <para>When <varname>Type</varname> is
Zbigniew Jędrzejewski-Szmek 62fe94
                                 not <option>oneshot</option>, only one
Zbigniew Jędrzejewski-Szmek 62fe94
-                                command may be given. When
Zbigniew Jędrzejewski-Szmek 62fe94
+                                command may and must be given. When
Zbigniew Jędrzejewski-Szmek 62fe94
                                 <varname>Type=oneshot</varname> is
Zbigniew Jędrzejewski-Szmek 62fe94
-                                used, more than one command may be
Zbigniew Jędrzejewski-Szmek 62fe94
-                                specified. Multiple command lines may
Zbigniew Jędrzejewski-Szmek 62fe94
-                                be concatenated in a single directive
Zbigniew Jędrzejewski-Szmek 62fe94
-                                by separating them with semicolons
Zbigniew Jędrzejewski-Szmek 62fe94
-                                (these semicolons must be passed as
Zbigniew Jędrzejewski-Szmek 62fe94
-                                separate words). Alternatively, this
Zbigniew Jędrzejewski-Szmek 62fe94
-                                directive may be specified more than
Zbigniew Jędrzejewski-Szmek 62fe94
-                                once with the same effect.
Zbigniew Jędrzejewski-Szmek 62fe94
-                                Lone semicolons may be escaped as
Zbigniew Jędrzejewski-Szmek 62fe94
+                                used, none or more than one command
Zbigniew Jędrzejewski-Szmek 62fe94
+                                may be specified. Multiple command
Zbigniew Jędrzejewski-Szmek 62fe94
+                                lines may be concatenated in a single
Zbigniew Jędrzejewski-Szmek 62fe94
+                                directive by separating them with
Zbigniew Jędrzejewski-Szmek 62fe94
+                                semicolons (these semicolons must be
Zbigniew Jędrzejewski-Szmek 62fe94
+                                passed as separate
Zbigniew Jędrzejewski-Szmek 62fe94
+                                words). Alternatively, this directive
Zbigniew Jędrzejewski-Szmek 62fe94
+                                may be specified more than once with
Zbigniew Jędrzejewski-Szmek 62fe94
+                                the same effect.  Lone semicolons may
Zbigniew Jędrzejewski-Szmek 62fe94
+                                be escaped as
Zbigniew Jędrzejewski-Szmek 62fe94
                                 <literal>\;</literal>. If the empty
Zbigniew Jędrzejewski-Szmek 62fe94
                                 string is assigned to this option, the
Zbigniew Jędrzejewski-Szmek 62fe94
                                 list of commands to start is reset,
Zbigniew Jędrzejewski-Szmek 62fe94
                                 prior assignments of this option will
Zbigniew Jędrzejewski-Szmek 62fe94
-                                have no effect.</para>
Zbigniew Jędrzejewski-Szmek 62fe94
+                                have no effect. If no
Zbigniew Jędrzejewski-Szmek 62fe94
+                                <varname>ExecStart=</varname> is
Zbigniew Jędrzejewski-Szmek 62fe94
+                                specified, then the service must have
Zbigniew Jędrzejewski-Szmek 62fe94
+                                <varname>RemainAfterExit=yes</varname>
Zbigniew Jędrzejewski-Szmek 62fe94
+                                set.</para>
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
                                 <para>Each command line is split on
Zbigniew Jędrzejewski-Szmek 62fe94
                                 whitespace, with the first item being
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/core/service.c b/src/core/service.c
Zbigniew Jędrzejewski-Szmek 62fe94
index 7d6ea73e05..1b864c4c8c 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/core/service.c
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/core/service.c
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -313,14 +313,23 @@ static int service_verify(Service *s) {
Zbigniew Jędrzejewski-Szmek 62fe94
         if (UNIT(s)->load_state != UNIT_LOADED)
Zbigniew Jędrzejewski-Szmek 62fe94
                 return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-        if (!s->exec_command[SERVICE_EXEC_START]) {
Zbigniew Jędrzejewski-Szmek 62fe94
-                log_error_unit(UNIT(s)->id, "%s lacks ExecStart setting. Refusing.", UNIT(s)->id);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!s->exec_command[SERVICE_EXEC_START] && !s->exec_command[SERVICE_EXEC_STOP]) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                log_error_unit(UNIT(s)->id, "%s lacks both ExecStart= and ExecStop= setting. Refusing.", UNIT(s)->id);
Zbigniew Jędrzejewski-Szmek 62fe94
                 return -EINVAL;
Zbigniew Jędrzejewski-Szmek 62fe94
         }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-        if (s->type != SERVICE_ONESHOT &&
Zbigniew Jędrzejewski-Szmek 62fe94
-            s->exec_command[SERVICE_EXEC_START]->command_next) {
Zbigniew Jędrzejewski-Szmek 62fe94
-                log_error_unit(UNIT(s)->id, "%s has more than one ExecStart setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (s->type != SERVICE_ONESHOT && !s->exec_command[SERVICE_EXEC_START]) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                log_error_unit(UNIT(s)->id, "%s has no ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
Zbigniew Jędrzejewski-Szmek 62fe94
+                return -EINVAL;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!s->remain_after_exit && !s->exec_command[SERVICE_EXEC_START]) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                log_error_unit(UNIT(s)->id, "%s has no ExecStart= setting, which is only allowed for RemainAfterExit=yes services. Refusing.", UNIT(s)->id);
Zbigniew Jędrzejewski-Szmek 62fe94
+                return -EINVAL;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (s->type != SERVICE_ONESHOT && s->exec_command[SERVICE_EXEC_START]->command_next) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                log_error_unit(UNIT(s)->id, "%s has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
Zbigniew Jędrzejewski-Szmek 62fe94
                 return -EINVAL;
Zbigniew Jędrzejewski-Szmek 62fe94
         }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -410,8 +419,15 @@ static int service_load(Unit *u) {
Zbigniew Jędrzejewski-Szmek 62fe94
                 if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
                         return r;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-                if (s->type == _SERVICE_TYPE_INVALID)
Zbigniew Jędrzejewski-Szmek 62fe94
-                        s->type = s->bus_name ? SERVICE_DBUS : SERVICE_SIMPLE;
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (s->type == _SERVICE_TYPE_INVALID) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        /* Figure out a type automatically */
Zbigniew Jędrzejewski-Szmek 62fe94
+                        if (s->bus_name)
Zbigniew Jędrzejewski-Szmek 62fe94
+                                s->type = SERVICE_DBUS;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        else if (s->exec_command[SERVICE_EXEC_START])
Zbigniew Jędrzejewski-Szmek 62fe94
+                                s->type = SERVICE_SIMPLE;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        else
Zbigniew Jędrzejewski-Szmek 62fe94
+                                s->type = SERVICE_ONESHOT;
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
                 /* Oneshot services have disabled start timeout by default */
Zbigniew Jędrzejewski-Szmek 62fe94
                 if (s->type == SERVICE_ONESHOT && !s->start_timeout_defined)
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -1309,9 +1325,6 @@ static void service_enter_start(Service *s) {
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         assert(s);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-        assert(s->exec_command[SERVICE_EXEC_START]);
Zbigniew Jędrzejewski-Szmek 62fe94
-        assert(!s->exec_command[SERVICE_EXEC_START]->command_next || s->type == SERVICE_ONESHOT);
Zbigniew Jędrzejewski-Szmek 62fe94
-
Zbigniew Jędrzejewski-Szmek 62fe94
         service_unwatch_control_pid(s);
Zbigniew Jędrzejewski-Szmek 62fe94
         service_unwatch_main_pid(s);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -1332,6 +1345,12 @@ static void service_enter_start(Service *s) {
Zbigniew Jędrzejewski-Szmek 62fe94
                 c = s->main_command = s->exec_command[SERVICE_EXEC_START];
Zbigniew Jędrzejewski-Szmek 62fe94
         }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!c) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                assert(s->type == SERVICE_ONESHOT);
Zbigniew Jędrzejewski-Szmek 62fe94
+                service_enter_start_post(s);
Zbigniew Jędrzejewski-Szmek 62fe94
+                return;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
         r = service_spawn(s,
Zbigniew Jędrzejewski-Szmek 62fe94
                           c,
Zbigniew Jędrzejewski-Szmek 62fe94
                           IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_ONESHOT) ? s->timeout_start_usec : 0,