summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2010-08-13 18:23:01 +0200
committerLennart Poettering <lennart@poettering.net>2010-08-13 18:23:01 +0200
commit34e9ba669e75fb3b8f481076e75df5c2abb8192b (patch)
tree50027c6f4abe34d67d7309c4d6009131701dee88
parent00b07cb3f3e26511f0627af686aa18652e780177 (diff)
service: rename Type=finish to Type=oneshot and allow multiple ExecStart= lines for oneshot services
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".
-rw-r--r--fixme2
-rw-r--r--man/systemd.service.xml4
-rw-r--r--src/dbus-manager.c1
-rw-r--r--src/service.c171
-rw-r--r--src/service.h2
-rw-r--r--test1/permissions.service2
-rw-r--r--units/arch/halt.service2
-rw-r--r--units/arch/poweroff.service2
-rw-r--r--units/arch/reboot.service2
-rw-r--r--units/fedora/halt.service2
-rw-r--r--units/fedora/killall.service2
-rw-r--r--units/fedora/plymouth-quit.service2
-rw-r--r--units/fedora/poweroff.service2
-rw-r--r--units/fedora/reboot.service2
-rw-r--r--units/gentoo/halt.service2
-rw-r--r--units/gentoo/killall.service2
-rw-r--r--units/gentoo/poweroff.service2
-rw-r--r--units/gentoo/reboot.service2
-rw-r--r--units/session/exit.service.in2
-rw-r--r--units/suse/halt.service2
-rw-r--r--units/suse/poweroff.service2
-rw-r--r--units/suse/reboot.service2
-rw-r--r--units/systemd-update-utmp-runlevel.service.in2
-rw-r--r--units/systemd-update-utmp-shutdown.service.in2
24 files changed, 134 insertions, 84 deletions
diff --git a/fixme b/fixme
index 7df8abe9ec..9d7bbd11c5 100644
--- 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
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index 94a21d3fe3..70c1d1e5fa 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -119,7 +119,7 @@
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>
@@ -158,7 +158,7 @@
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
diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index dfe8a91917..42906ce04f 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -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;
diff --git a/src/service.c b/src/service.c
index a3a23e3271..ee952810fc 100644
--- a/src/service.c
+++ b/src/service.c
@@ -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"
};
diff --git a/src/service.h b/src/service.h
index 725e2135f1..81401ac387 100644
--- a/src/service.h
+++ b/src/service.h
@@ -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,
diff --git a/test1/permissions.service b/test1/permissions.service
index 4d9b352fea..cb0664fa4f 100644
--- a/test1/permissions.service
+++ b/test1/permissions.service
@@ -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
diff --git a/units/arch/halt.service b/units/arch/halt.service
index b1935262f7..dbfc228787 100644
--- a/units/arch/halt.service
+++ b/units/arch/halt.service
@@ -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
diff --git a/units/arch/poweroff.service b/units/arch/poweroff.service
index 3d40ba82c2..bd563ba586 100644
--- a/units/arch/poweroff.service
+++ b/units/arch/poweroff.service
@@ -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
diff --git a/units/arch/reboot.service b/units/arch/reboot.service
index 37112fe9f3..6bce95d8fd 100644
--- a/units/arch/reboot.service
+++ b/units/arch/reboot.service
@@ -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
diff --git a/units/fedora/halt.service b/units/fedora/halt.service
index 6e2745eedd..a6c4786a8b 100644
--- a/units/fedora/halt.service
+++ b/units/fedora/halt.service
@@ -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
diff --git a/units/fedora/killall.service b/units/fedora/killall.service
index 3b27375fe5..53c65d4a3b 100644
--- a/units/fedora/killall.service
+++ b/units/fedora/killall.service
@@ -12,7 +12,7 @@ After=shutdown.target
RefuseManualStart=yes
[Service]
-Type=finish
+Type=oneshot
ValidNoProcess=yes
ExecStart=-/etc/init.d/killall start
StandardOutput=tty
diff --git a/units/fedora/plymouth-quit.service b/units/fedora/plymouth-quit.service
index faf8b4d7a7..869a2ec596 100644
--- a/units/fedora/plymouth-quit.service
+++ b/units/fedora/plymouth-quit.service
@@ -11,7 +11,7 @@ Before=getty@tty1.service
[Service]
ExecStart=-/usr/bin/plymouth quit
-Type=finish
+Type=oneshot
[Install]
WantedBy=multi-user.target
diff --git a/units/fedora/poweroff.service b/units/fedora/poweroff.service
index cd6ec3edc9..7597f4f651 100644
--- a/units/fedora/poweroff.service
+++ b/units/fedora/poweroff.service
@@ -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
diff --git a/units/fedora/reboot.service b/units/fedora/reboot.service
index 01bd46395d..6120ceb821 100644
--- a/units/fedora/reboot.service
+++ b/units/fedora/reboot.service
@@ -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
diff --git a/units/gentoo/halt.service b/units/gentoo/halt.service
index 56c3f2e60e..826c69f061 100644
--- a/units/gentoo/halt.service
+++ b/units/gentoo/halt.service
@@ -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
diff --git a/units/gentoo/killall.service b/units/gentoo/killall.service
index 3f107e3be5..8b42af87b5 100644
--- a/units/gentoo/killall.service
+++ b/units/gentoo/killall.service
@@ -12,7 +12,7 @@ After=shutdown.target
RefuseManualStart=yes
[Service]
-Type=finish
+Type=oneshot
ValidNoProcess=yes
ExecStart=-/etc/init.d/killprocs start
StandardOutput=tty
diff --git a/units/gentoo/poweroff.service b/units/gentoo/poweroff.service
index 40126b211e..8a5a62794f 100644
--- a/units/gentoo/poweroff.service
+++ b/units/gentoo/poweroff.service
@@ -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
diff --git a/units/gentoo/reboot.service b/units/gentoo/reboot.service
index de1665579d..b5defb1680 100644
--- a/units/gentoo/reboot.service
+++ b/units/gentoo/reboot.service
@@ -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
diff --git a/units/session/exit.service.in b/units/session/exit.service.in
index 1f515a75ce..d098d0da50 100644
--- a/units/session/exit.service.in
+++ b/units/session/exit.service.in
@@ -5,5 +5,5 @@ Requires=shutdown.target
After=shutdown.target
[Service]
-Type=finish
+Type=oneshot
ExecStart=@SYSTEMCTL@ --session daemon-exit
diff --git a/units/suse/halt.service b/units/suse/halt.service
index 559a51ce75..32b7dc204a 100644
--- a/units/suse/halt.service
+++ b/units/suse/halt.service
@@ -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
diff --git a/units/suse/poweroff.service b/units/suse/poweroff.service
index f68882c143..13b13b0427 100644
--- a/units/suse/poweroff.service
+++ b/units/suse/poweroff.service
@@ -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
diff --git a/units/suse/reboot.service b/units/suse/reboot.service
index 6b2982a9a0..3ee290e659 100644
--- a/units/suse/reboot.service
+++ b/units/suse/reboot.service
@@ -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
diff --git a/units/systemd-update-utmp-runlevel.service.in b/units/systemd-update-utmp-runlevel.service.in
index 9b7677f3a1..90bb9379e0 100644
--- a/units/systemd-update-utmp-runlevel.service.in
+++ b/units/systemd-update-utmp-runlevel.service.in
@@ -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
diff --git a/units/systemd-update-utmp-shutdown.service.in b/units/systemd-update-utmp-shutdown.service.in
index 0551a9b7e2..f5d1342243 100644
--- a/units/systemd-update-utmp-shutdown.service.in
+++ b/units/systemd-update-utmp-shutdown.service.in
@@ -12,5 +12,5 @@ Before=killall.service
Conflicts=systemd-update-utmp-runlevel.service
[Service]
-Type=finish
+Type=oneshot
ExecStart=-@rootlibexecdir@/systemd-update-utmp shutdown