This odd little feature makes it possible to declare run/tasks with a
condition that does not block Finit transitioning from bootstrap to the
next runlevel.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This change allows us to support constructs like this:
RUNDIR=/var/run/somesvc
DAEMON_ARGS=--workdir $RUNDIR --other-args...
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Introduced back in v4.3-rc2, 82cc10be8, the support for automatic
service conditions have had a weird and unintended behavior. Any
change in state (see doc/svc-machine.png) caused Finit to clear
out *all* previously acquired service conditions.
However, when moving between RUNNING and PAUSED states, a service
should not have its conditions cleared. The PAUSED state, seen
also by all conditions moving to FLUX, is only temporary while an
`initctl reload` is processed. If a service has no changes to be
applied it will move back to RUNNING.
Also, we cannot clear the service conditions because other run/task
or services may depend on it and clearing them would cause Finit to
SIGTERM these processes (since they are no longer eligible to run).
This patch not only adds this pre-condition to `cond_clearn()`, it
also clarifies which state (before or after) the particular code
is interested in.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The delayed matcehd works when all run/task/services provide their own
unique identity, but for replacements this is sometimes not the case.
Example from system/10-hotplug.conf.in:
run nowarn conflict:udevd,mdev cgroup.init name:coldplug <service/mdevd/ready> \
[S] mdevd-coldplug -- Cold plugging system
vs
run nowarn conflict:udevd,mdevd cgroup.init name:coldplug if:!mdevd <service/mdev/running> \
[S] @pkglibexecdir@/coldplug -- Cold plugging system
Here they both provide the <run/coldplug/*> conditions, and if the first
is loaded, because we found mdevd, then we should not attempt to load
this one.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The if: statement, introduced in v4.4, allows for discarding run/task/services
that depend on other services, based on that service's name, or condition.
Discarding in this context means unloading from the configuration.
At runtime, however, it has proven quite useful to be able to conditionally
qualify a run/task/service based on a condition. Consider this example from
the Infix operating system:
run name:startup log:prio:user.notice \
[S] <pid/sysrepo> confd -b --load startup-config -- Loading startup-config
run name:failure log:prio:user.critical if:<usr/fail-startup> \
[S] <pid/sysrepo> confd --load failure-config -- Loading failure-config
The two run statements reside in the same .conf file so Finit runs them in true
sequence. If loading the file `startup-config` fails confd sets the condition
usr/fail-startup, thus allowing the next run statement to load `failure-config`.
Notice the difference between <pid/sysrepo> condition and if:<usr/fail-startup>.
The former is a condition for starting and the latter is a condition to check if
a run/task/service is qualified to even be considerered. The best comparison is
with the [runlevel] option, it too is used to qualify.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Drop complete() logic, waiting for run tasks to finish, from the
service_start() funciton to the general service_monitor(). This
refactor frees up the main loop and allows us to answer any API
calls from initctl even from the run task itself.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The code refactored in this commit has long been an eyesore. The
hand-over, from the sequential main() function, to the event loop
was clumsy at best and was very difficult to debug.
Instead of using a series of workers we now delegate everything to
the big state machine by introducing a new SM_BOOTSRTAP_WAIT_STATE.
Both the runparts and rc.local scripts now run in the background, no
longer blocking the event loop from responding to initctl calls. To
ensure they run at the same point in time two things have been done:
1. A new <int/bootstrap> condition has been added which triggers
runparts, which now is a regular task created by conf_init()
2. /etc/rc.local is started from SM_RUNLEVEL_WAIT_STATE when we
transition from runlevel S to any other runlevel.
Fixes#356
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The execvp() call always fails with -1, so only logging exit code when
collecting the PID is not enough. When debugging the user needs to see
the errno from execvp(), e.g., "No such file or directory", when the
command was missing the absolute path to the executable.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Related to 6f0d448 in that we check if the kernel knows about this
process before we try to stop it. If it's already dead we clean up
and return.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This turns out to be the root-cause of #227. Finit is waiting forever
for proceeses to stop at shutdown/reboot, while a subreaper has already
collected the PID, or Finit for some reason did not collect the PID.
When the process timeout calls service_kill() we now check if the kernel
actually knows of this process or not. If it's already been collected,
we can notify Finit of this by calling service_monitor() to clean up the
'svc' and in turn call sm_step() to finalize the state transition.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
These changes add a new svc_block_t type: SVC_BLOCK_CONFLICT so a user
can more clearly see why a run/task/service has not been started by
Finit. The reason for the block is by default logged, which can be
escaped by using the `nowarn` flag.
Also, when the conflict is resolved, allow the service to start.
With these changes, the system/hotplug.conf should work better and
cause less questions about "strange" log messages.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
In 91a9c83 a regression was introduced that affects the way Finit stops
a supervised process and its process group.
Instead of sending SIGTERM to the process, delegating the responsibility
to that process to inform any children it may have, Finit as of 91a9c83
sends SIGTERM to the entire process group. For SIGKILL this is fine,
SIGKILL only runs as cleanup and as a last ditch effort if the process
doesn't respond to SIGTERM.
This regression, introduced in v3.2, directly affects services like
avahi-autoipd that have forked off children that it needs to tell to
exit cleanly before it returns. With the patch in question these
children are never allowed to complete, which in turn causes lingering
169.254 link-local addresses on interfaces.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Due to an old design decision runlevel S was encoded internally as '0',
meaning it was the same as halt/poweroff. If you want to run scripts at
system shutdown this was less then ideal since it meant your scripts
also ran at bootstrap.
This change is quite invasive. It introduces INIT_LEVEL (10) as the
value for runlevel S, meaning all code that parses and/or evaluates
anything for runlevel 0/S was affected and had to be reworked.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The logger redirection process was sometimes in the init group instead
of the system/<svc>/ group. This was due to the parent PID being moved
after the logger was forked.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
When we've started a run task, regardless of its exit status, we must
mark it as not dirty to prevent it from being endlessly restarted.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Post audit, concensus is to drop if: and always do post-eval of all
ifdef: statements. Also, rename ifdef: to if: for completeness.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Conditional loading of stanza depending on ident is already loaded. The
if: checks as in-band while ifdef: checks out-of-band, i.e., post eval.
The optional leading '!' negates the comparison, if NOT foo then ...
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This changes the semantics of Finit a bit by checking for the command to
run when registering it, skipping commands that cannot be found in the
absolute path provided in the command, or in $PATH.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Starting a service like this works fine:
service [2345789] env:-/etc/default/nginx nginx -g 'daemon off;'
However, on `initctl reload` the previous argument was lost while
parsing the end of the new one. So the comparison always resulted
in a 'diff' causing the service to be unnecessarily restarted.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The TTY and log configuration is overloaded using a union in svc_t, so
we cannot "reset" the log attribute on reload. In fact, a TTY should
never be allowed to have a tty:anything set, so change the parser to
ignore log options for ttys.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This issue was found when the test pre-post-serv.sh suddnely started
failing, unclear how it could ever have worked before considering the
nature of this patch.
The trick here is when reloading a service like this:
service env:/etc/env serv -np -e foo:bar
into this:
service pre:/bin/pre.sh serv -np
In the second the env: has been removed and pre: added. But with Finit
prior to this patch, env: was kept leading to unintended behavior. The
same goes for the other options included in this patch.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
No need for special handling of s6 services, we now have the new
service_notify_reconf() function that is called on init reload.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The sysklogd logger is capable of logging the PID of the actual service,
rather than just the logger tool itself (which would be a differet PID
every time).
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
When 'initctl reload' is called new "configuration generation" is
started by Finit. This mechanism ensures services reaffirm their
readiness and helps distinguish between their ready before reload
and after.
For native services the pidfile plugin handles this. The s6 style
services are one-shot only, and thus use a static ready condition.
This patch adds support for stepping the configuration generation
of unmodified systemd style services.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The svc_set_state() function not only handles state transitions, it also
makes sure to cancel any outstaing service timeouts. Before the service
readiness support was added, service conditions were simply a single bit
of information, so clearing its conditions before changing states had no
impact. With readiness we have multiple bits of information that are
set as conditions.
When restarting a crashing service we set a timeout to retry restarting,
or ensure the service is now running. This means that the service can
signal READY before RUNNING is reasserted, but the RUNNING state can be
set also by the service state machine, so we need to ensure we do not
re-assert RUNNING if it's already set, and thereby clearing READY.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This fixes `initctl reload` correctly restarting all daemons that have new
command line arguments.
Previously command line arguments changes were only acted upon if the
service was explicitly reloaded `initctl reload myservice`.