chiark / gitweb /
service: rename Type=finish to Type=oneshot and allow multiple ExecStart= lines for...
authorLennart Poettering <lennart@poettering.net>
Fri, 13 Aug 2010 16:23:01 +0000 (18:23 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 13 Aug 2010 16:23:01 +0000 (18:23 +0200)
In contrast to the other service types oneshot services are usually not
long lasting and there's not necessarily a single clean main process for
them. This change allows multiple ExecStart= lines for this type of
services so that the admin/developer doesn't have to arbitrarily pick on
of various sequential commands as the "main one".

24 files changed:
fixme
man/systemd.service.xml
src/dbus-manager.c
src/service.c
src/service.h
test1/permissions.service
units/arch/halt.service
units/arch/poweroff.service
units/arch/reboot.service
units/fedora/halt.service
units/fedora/killall.service
units/fedora/plymouth-quit.service
units/fedora/poweroff.service
units/fedora/reboot.service
units/gentoo/halt.service
units/gentoo/killall.service
units/gentoo/poweroff.service
units/gentoo/reboot.service
units/session/exit.service.in
units/suse/halt.service
units/suse/poweroff.service
units/suse/reboot.service
units/systemd-update-utmp-runlevel.service.in
units/systemd-update-utmp-shutdown.service.in

diff --git a/fixme b/fixme
index 7df8abe..9d7bbd1 100644 (file)
--- a/fixme
+++ b/fixme
@@ -71,8 +71,6 @@
 
 * be more forgiving when parsing unit files, when encountering incorrect lines with assignments
 
-* ExecStart= mehrfach bei Type=finish
-
 * move runlevel symlinks to /lib
 
 * agetty darf nicht mit emergency.service kollidieren
index 94a21d3..70c1d1e 100644 (file)
                                 start-up type for this service
                                 unit. One of <option>simple</option>,
                                 <option>forking</option>,
-                                <option>finish</option>,
+                                <option>oneshot</option>,
                                 <option>dbus</option>,
                                 <option>notify</option>.</para>
 
                                 exits.</para>
 
                                 <para>Behaviour of
-                                <option>finish</option> is similar
+                                <option>oneshot</option> is similar
                                 to <option>simple</option>, however
                                 it is expected that the process has to
                                 exit before systemd starts follow-up
index dfe8a91..42906ce 100644 (file)
@@ -295,7 +295,6 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
                                     DBUS_TYPE_INVALID))
                         goto oom;
         } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
-                const char *name;
                 Unit *u;
                 uint32_t pid;
 
index a3a23e3..ee95281 100644 (file)
@@ -834,8 +834,9 @@ static int service_verify(Service *s) {
                 return -EINVAL;
         }
 
-        if (s->exec_command[SERVICE_EXEC_START]->command_next) {
-                log_error("%s has more than one ExecStart setting. Refusing.", s->meta.id);
+        if (s->type != SERVICE_ONESHOT &&
+            s->exec_command[SERVICE_EXEC_START]->command_next) {
+                log_error("%s has more than one ExecStart setting, which is only allowed for Type=oneshot services. Refusing.", s->meta.id);
                 return -EINVAL;
         }
 
@@ -1250,7 +1251,7 @@ static int service_coldplug(Unit *u) {
                 if ((s->deserialized_state == SERVICE_START &&
                      (s->type == SERVICE_FORKING ||
                       s->type == SERVICE_DBUS ||
-                      s->type == SERVICE_FINISH ||
+                      s->type == SERVICE_ONESHOT ||
                       s->type == SERVICE_NOTIFY)) ||
                     s->deserialized_state == SERVICE_START_POST ||
                     s->deserialized_state == SERVICE_RUNNING ||
@@ -1711,15 +1712,18 @@ static void service_enter_start(Service *s) {
         assert(s);
 
         assert(s->exec_command[SERVICE_EXEC_START]);
-        assert(!s->exec_command[SERVICE_EXEC_START]->command_next);
+        assert(!s->exec_command[SERVICE_EXEC_START]->command_next || s->type == SERVICE_ONESHOT);
 
         if (s->type == SERVICE_FORKING)
                 service_unwatch_control_pid(s);
         else
                 service_unwatch_main_pid(s);
 
+        s->control_command_id = SERVICE_EXEC_START;
+        s->control_command = s->exec_command[SERVICE_EXEC_START];
+
         if ((r = service_spawn(s,
-                               s->exec_command[SERVICE_EXEC_START],
+                               s->control_command,
                                s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY,
                                true,
                                true,
@@ -1741,17 +1745,14 @@ static void service_enter_start(Service *s) {
                 /* For forking services we wait until the start
                  * process exited. */
 
-                s->control_command_id = SERVICE_EXEC_START;
-                s->control_command = s->exec_command[SERVICE_EXEC_START];
-
                 s->control_pid = pid;
                 service_set_state(s, SERVICE_START);
 
-        } else if (s->type == SERVICE_FINISH ||
+        } else if (s->type == SERVICE_ONESHOT ||
                    s->type == SERVICE_DBUS ||
                    s->type == SERVICE_NOTIFY) {
 
-                /* For finishing services we wait until the start
+                /* For oneshot services we wait until the start
                  * process exited, too, but it is our main process. */
 
                 /* For D-Bus services we know the main pid right away,
@@ -1854,7 +1855,7 @@ fail:
         service_enter_stop(s, false);
 }
 
-static void service_run_next(Service *s, bool success) {
+static void service_run_next_control(Service *s, bool success) {
         int r;
 
         assert(s);
@@ -1864,8 +1865,9 @@ static void service_run_next(Service *s, bool success) {
         if (!success)
                 s->failure = true;
 
-        s->control_command = s->control_command->command_next;
+        assert(s->control_command_id != SERVICE_EXEC_START);
 
+        s->control_command = s->control_command->command_next;
         service_unwatch_control_pid(s);
 
         if ((r = service_spawn(s,
@@ -1883,7 +1885,7 @@ static void service_run_next(Service *s, bool success) {
         return;
 
 fail:
-        log_warning("%s failed to run next task: %s", s->meta.id, strerror(-r));
+        log_warning("%s failed to run next control task: %s", s->meta.id, strerror(-r));
 
         if (s->state == SERVICE_START_PRE)
                 service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
@@ -1895,6 +1897,43 @@ fail:
                 service_enter_stop(s, false);
 }
 
+static void service_run_next_main(Service *s, bool success) {
+        pid_t pid;
+        int r;
+
+        assert(s);
+        assert(s->control_command);
+        assert(s->control_command->command_next);
+
+        if (!success)
+                s->failure = true;
+
+        assert(s->control_command_id == SERVICE_EXEC_START);
+        assert(s->type == SERVICE_ONESHOT);
+
+        s->control_command = s->control_command->command_next;
+        service_unwatch_main_pid(s);
+
+        if ((r = service_spawn(s,
+                               s->control_command,
+                               false,
+                               true,
+                               true,
+                               true,
+                               true,
+                               s->notify_access != NOTIFY_NONE,
+                               &pid)) < 0)
+                goto fail;
+
+        service_set_main_pid(s, pid);
+
+        return;
+
+fail:
+        log_warning("%s failed to run next main task: %s", s->meta.id, strerror(-r));
+        service_enter_stop(s, false);
+}
+
 static int service_start(Unit *u) {
         Service *s = SERVICE(u);
 
@@ -2226,14 +2265,13 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
 
         if (s->main_pid == pid) {
 
-                exec_status_exit(&s->main_exec_status, pid, code, status);
                 s->main_pid = 0;
+                exec_status_exit(&s->main_exec_status, pid, code, status);
 
-                if (s->type != SERVICE_FORKING) {
-                        assert(s->exec_command[SERVICE_EXEC_START]);
-                        s->exec_command[SERVICE_EXEC_START]->exec_status = s->main_exec_status;
+                if (s->type != SERVICE_FORKING && s->control_command) {
+                        s->control_command->exec_status = s->main_exec_status;
 
-                        if (s->exec_command[SERVICE_EXEC_START]->ignore)
+                        if (s->control_command->ignore)
                                 success = true;
                 }
 
@@ -2241,51 +2279,69 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                          "%s: main process exited, code=%s, status=%i", u->meta.id, sigchld_code_to_string(code), status);
                 s->failure = s->failure || !success;
 
-                /* The service exited, so the service is officially
-                 * gone. */
+                if (s->control_command &&
+                    s->control_command->command_next &&
+                    success) {
 
-                switch (s->state) {
+                        /* There is another command to *
+                         * execute, so let's do that. */
 
-                case SERVICE_START_POST:
-                case SERVICE_RELOAD:
-                case SERVICE_STOP:
-                        /* Need to wait until the operation is
-                         * done */
-                        break;
+                        log_debug("%s running next main command for state %s", u->meta.id, service_state_to_string(s->state));
+                        service_run_next_main(s, success);
 
-                case SERVICE_START:
-                        if (s->type == SERVICE_FINISH) {
-                                /* This was our main goal, so let's go on */
-                                if (success)
-                                        service_enter_start_post(s);
-                                else
-                                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
+                } else {
+
+                        /* The service exited, so the service is officially
+                         * gone. */
+
+                        s->control_command = NULL;
+                        s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
+
+                        switch (s->state) {
+
+                        case SERVICE_START_POST:
+                        case SERVICE_RELOAD:
+                        case SERVICE_STOP:
+                                /* Need to wait until the operation is
+                                 * done */
                                 break;
-                        } else {
-                                assert(s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY);
 
-                                /* Fall through */
-                        }
+                        case SERVICE_START:
+                                if (s->type == SERVICE_ONESHOT) {
+                                        /* This was our main goal, so let's go on */
+                                        if (success)
+                                                service_enter_start_post(s);
+                                        else
+                                                service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
+                                        break;
+                                } else {
+                                        assert(s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY);
 
-                case SERVICE_RUNNING:
-                        service_enter_running(s, success);
-                        break;
+                                        /* Fall through */
+                                }
 
-                case SERVICE_STOP_SIGTERM:
-                case SERVICE_STOP_SIGKILL:
+                        case SERVICE_RUNNING:
+                                service_enter_running(s, success);
+                                break;
 
-                        if (!control_pid_good(s))
-                                service_enter_stop_post(s, success);
+                        case SERVICE_STOP_SIGTERM:
+                        case SERVICE_STOP_SIGKILL:
 
-                        /* If there is still a control process, wait for that first */
-                        break;
+                                if (!control_pid_good(s))
+                                        service_enter_stop_post(s, success);
 
-                default:
-                        assert_not_reached("Uh, main process died at wrong time.");
+                                /* If there is still a control process, wait for that first */
+                                break;
+
+                        default:
+                                assert_not_reached("Uh, main process died at wrong time.");
+                        }
                 }
 
         } else if (s->control_pid == pid) {
 
+                s->control_pid = 0;
+
                 if (s->control_command) {
                         exec_status_exit(&s->control_command->exec_status, pid, code, status);
 
@@ -2293,22 +2349,19 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                                 success = true;
                 }
 
-                s->control_pid = 0;
-
-                log_full(success ? LOG_DEBUG : LOG_NOTICE,
+               log_full(success ? LOG_DEBUG : LOG_NOTICE,
                          "%s: control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status);
                 s->failure = s->failure || !success;
 
-                /* If we are shutting things down anyway we
-                 * don't care about failing commands. */
-
-                if (s->control_command && s->control_command->command_next && success) {
+                if (s->control_command &&
+                    s->control_command->command_next &&
+                    success) {
 
                         /* There is another command to *
                          * execute, so let's do that. */
 
-                        log_debug("%s running next command for state %s", u->meta.id, service_state_to_string(s->state));
-                        service_run_next(s, success);
+                        log_debug("%s running next control command for state %s", u->meta.id, service_state_to_string(s->state));
+                        service_run_next_control(s, success);
 
                 } else {
                         /* No further commands for this step, so let's
@@ -2822,7 +2875,7 @@ DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
 static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
         [SERVICE_SIMPLE] = "simple",
         [SERVICE_FORKING] = "forking",
-        [SERVICE_FINISH] = "finish",
+        [SERVICE_ONESHOT] = "oneshot",
         [SERVICE_DBUS] = "dbus",
         [SERVICE_NOTIFY] = "notify"
 };
index 725e213..81401ac 100644 (file)
@@ -58,7 +58,7 @@ typedef enum ServiceRestart {
 typedef enum ServiceType {
         SERVICE_SIMPLE,   /* we fork and go on right-away (i.e. modern socket activated daemons) */
         SERVICE_FORKING,  /* forks by itself (i.e. traditional daemons) */
-        SERVICE_FINISH,   /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
+        SERVICE_ONESHOT,  /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
         SERVICE_DBUS,     /* we fork and wait until a specific D-Bus name appears on the bus */
         SERVICE_NOTIFY,   /* we fork and wait until a daemon sends us a ready message with sd_notify() */
         _SERVICE_TYPE_MAX,
index 4d9b352..cb0664f 100644 (file)
@@ -5,7 +5,7 @@ Description=Permission Enforcement checker
 ExecStart=/usr/bin/id
 ExecStartPost=/usr/bin/env
 ExecStartPost=/bin/sleep 5
-Type=finish
+Type=oneshot
 Capabilities=all= cap_dac_override=eip
 User=nobody
 Group=nobody
index b193526..dbfc228 100644 (file)
@@ -12,7 +12,7 @@ Requires=shutdown.target umount.target
 After=shutdown.target umount.target
 
 [Service]
-Type=finish
+Type=oneshot
 ValidNoProcess=yes
 Environment=RUNLEVEL=0
 ExecStart=/etc/rc.shutdown
index 3d40ba8..bd563ba 100644 (file)
@@ -12,7 +12,7 @@ Requires=shutdown.target umount.target
 After=shutdown.target umount.target
 
 [Service]
-Type=finish
+Type=oneshot
 ValidNoProcess=yes
 Environment=RUNLEVEL=0
 ExecStart=/etc/rc.shutdown
index 37112fe..6bce95d 100644 (file)
@@ -12,7 +12,7 @@ Requires=shutdown.target umount.target
 After=shutdown.target umount.target
 
 [Service]
-Type=finish
+Type=oneshot
 ValidNoProcess=yes
 Environment=RUNLEVEL=6
 ExecStart=/etc/rc.shutdown
index 6e2745e..a6c4786 100644 (file)
@@ -12,7 +12,7 @@ Requires=shutdown.target umount.target killall.service
 After=shutdown.target umount.target killall.service
 
 [Service]
-Type=finish
+Type=oneshot
 ValidNoProcess=yes
 Environment=INIT_HALT=HALT RUNLEVEL=0
 ExecStart=/etc/init.d/halt start
index 3b27375..53c65d4 100644 (file)
@@ -12,7 +12,7 @@ After=shutdown.target
 RefuseManualStart=yes
 
 [Service]
-Type=finish
+Type=oneshot
 ValidNoProcess=yes
 ExecStart=-/etc/init.d/killall start
 StandardOutput=tty
index faf8b4d..869a2ec 100644 (file)
@@ -11,7 +11,7 @@ Before=getty@tty1.service
 
 [Service]
 ExecStart=-/usr/bin/plymouth quit
-Type=finish
+Type=oneshot
 
 [Install]
 WantedBy=multi-user.target
index cd6ec3e..7597f4f 100644 (file)
@@ -12,7 +12,7 @@ Requires=shutdown.target umount.target killall.service
 After=shutdown.target umount.target killall.service
 
 [Service]
-Type=finish
+Type=oneshot
 ValidNoProcess=yes
 Environment=RUNLEVEL=0
 ExecStart=/etc/init.d/halt start
index 01bd463..6120ceb 100644 (file)
@@ -12,7 +12,7 @@ Requires=shutdown.target umount.target killall.service
 After=shutdown.target umount.target killall.service
 
 [Service]
-Type=finish
+Type=oneshot
 ValidNoProcess=yes
 Environment=RUNLEVEL=6
 ExecStart=/etc/init.d/reboot start
index 56c3f2e..826c69f 100644 (file)
@@ -12,7 +12,7 @@ Requires=shutdown.target umount.target killall.service
 After=shutdown.target umount.target killall.service
 
 [Service]
-Type=finish
+Type=oneshot
 ValidNoProcess=yes
 Environment=INIT_HALT=HALT RC_DOWN_HARDDISK=yes
 ExecStart=/etc/init.d/shutdown.sh
index 3f107e3..8b42af8 100644 (file)
@@ -12,7 +12,7 @@ After=shutdown.target
 RefuseManualStart=yes
 
 [Service]
-Type=finish
+Type=oneshot
 ValidNoProcess=yes
 ExecStart=-/etc/init.d/killprocs start
 StandardOutput=tty
index 40126b2..8a5a627 100644 (file)
@@ -12,7 +12,7 @@ Requires=shutdown.target umount.target killall.service
 After=shutdown.target umount.target killall.service
 
 [Service]
-Type=finish
+Type=oneshot
 ValidNoProcess=yes
 Environment=RC_DOWN_HARDDISK=yes
 ExecStart=/etc/init.d/shutdown.sh
index de16655..b5defb1 100644 (file)
@@ -12,7 +12,7 @@ Requires=shutdown.target umount.target killall.service
 After=shutdown.target umount.target killall.service
 
 [Service]
-Type=finish
+Type=oneshot
 ValidNoProcess=yes
 ExecStart=/etc/init.d/reboot.sh
 StandardOutput=tty
index 1f515a7..d098d0d 100644 (file)
@@ -5,5 +5,5 @@ Requires=shutdown.target
 After=shutdown.target
 
 [Service]
-Type=finish
+Type=oneshot
 ExecStart=@SYSTEMCTL@ --session daemon-exit
index 559a51c..32b7dc2 100644 (file)
@@ -12,7 +12,7 @@ Requires=shutdown.target umount.target
 After=shutdown.target umount.target
 
 [Service]
-Type=finish
+Type=oneshot
 ValidNoProcess=yes
 Environment=INIT_HALT=HALT RUNLEVEL=0 COLD_BOOT=1
 ExecStart=/etc/init.d/halt
index f68882c..13b13b0 100644 (file)
@@ -12,7 +12,7 @@ Requires=shutdown.target umount.target
 After=shutdown.target umount.target
 
 [Service]
-Type=finish
+Type=oneshot
 ValidNoProcess=yes
 Environment=COLD_BOOT=1
 ExecStart=/etc/init.d/halt
index 6b2982a..3ee290e 100644 (file)
@@ -12,7 +12,7 @@ Requires=shutdown.target umount.target
 After=shutdown.target umount.target
 
 [Service]
-Type=finish
+Type=oneshot
 ValidNoProcess=yes
 Environment=COLD_BOOT=1
 ExecStart=/etc/init.d/reboot
index 9b7677f..90bb937 100644 (file)
@@ -11,5 +11,5 @@ DefaultDependencies=no
 After=runlevel1.target runlevel2.target runlevel3.target runlevel4.target runlevel5.target auditd.service
 
 [Service]
-Type=finish
+Type=oneshot
 ExecStart=-@rootlibexecdir@/systemd-update-utmp runlevel
index 0551a9b..f5d1342 100644 (file)
@@ -12,5 +12,5 @@ Before=killall.service
 Conflicts=systemd-update-utmp-runlevel.service
 
 [Service]
-Type=finish
+Type=oneshot
 ExecStart=-@rootlibexecdir@/systemd-update-utmp shutdown