From 34e9ba669e75fb3b8f481076e75df5c2abb8192b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 13 Aug 2010 18:23:01 +0200 Subject: 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". --- fixme | 2 - man/systemd.service.xml | 4 +- src/dbus-manager.c | 1 - src/service.c | 171 +++++++++++++++++--------- src/service.h | 2 +- test1/permissions.service | 2 +- units/arch/halt.service | 2 +- units/arch/poweroff.service | 2 +- units/arch/reboot.service | 2 +- units/fedora/halt.service | 2 +- units/fedora/killall.service | 2 +- units/fedora/plymouth-quit.service | 2 +- units/fedora/poweroff.service | 2 +- units/fedora/reboot.service | 2 +- units/gentoo/halt.service | 2 +- units/gentoo/killall.service | 2 +- units/gentoo/poweroff.service | 2 +- units/gentoo/reboot.service | 2 +- units/session/exit.service.in | 2 +- units/suse/halt.service | 2 +- units/suse/poweroff.service | 2 +- units/suse/reboot.service | 2 +- units/systemd-update-utmp-runlevel.service.in | 2 +- units/systemd-update-utmp-shutdown.service.in | 2 +- 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 , , - , + , , . @@ -158,7 +158,7 @@ exits. Behaviour of - is similar + is similar to , 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 -- cgit v1.2.3-54-g00ecf