Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion init.d/s6-svscan.in
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ command_args="$RC_SVCDIR"
command_background=yes
pidfile=/var/run/s6-svscan.pid
umask=022
# notify=fd:4 # when notify=fd is fixed, uncomment here and add -d4 in svscanboot
notify=fd:4

depend() {
need localmount
Expand Down
24 changes: 17 additions & 7 deletions s6-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,23 +97,33 @@ timeout_kill means no SIGKILL will be sent.

## How it works internally, starting with 0.63

If the `command` variable is empty *and* there is a user-provided
service directory in `/var/svc.d` with the same name as the service
being called, then everything works as it did previously: the
`/var/svc.d/foo` service directory is linked into the scan directory,
and that's it: you are in full manual control of your service directory.
You can still use the `timeout_ready` and `timeout_down` variables to
tune OpenRC's behaviour, but the other variables have no impact.

The rest of this section assumes that the `command` variable is not
empty. In that case, you don't need to provide a service directory in
the s6 format: OpenRC will craft one for you.

The first time start() is called, OpenRC uses all the variables in the
service file to build a service directory for s6: a run script, possibly
a notification-fd file, etc. This service directory is then linked into
service file to build a service directory: a run script, possibly a
notification-fd file, etc. This service directory is then linked into
the scan directory and s6-svscan is told to register it and spawn a
s6-supervise process on it.

This means that all the information needed for your service should be
given, declaratively, in your service file (and your configuration file
if you have one). You do not need to build your service directory
yourself anymore, this is done automatically: in true OpenRC fashion,
the service file is the One True Source of information for running
your service.
if you have one). In true OpenRC fashion, the service file is the One
True Source of information for running your service.

The run script for the s6 service directory is built with in the
execline language, because execline makes script generation easier
than sh. However, the daemon execution itself is still done via
sh -c "$command $command_args $command_args_foreground"
`sh -c "$command $command_args $command_args_foreground"`
for compatibility with other backends. In other words: you can forget
that execline is even there, all the user-facing parts use sh as their
interpreter and it's all you need to worry about.
Expand Down
3 changes: 1 addition & 2 deletions sh/s6-svscanboot.sh.in
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ s6-log -bpd3 -- t s1048576 n10 "$logdir"
EOF
chmod 0755 "$scandir/s6-svscan-log/run"

# when notify=fd is fixed, add -d4 after -X3
exec redirfd -wnb 1 "$scandir/s6-svscan-log/fifo" \
fdmove -c 2 1 \
s6-svscan -X3 -- "$scandir" 0</dev/null 3>/dev/console
s6-svscan -X3 -d4 -- "$scandir" 0</dev/null 3>/dev/console
16 changes: 12 additions & 4 deletions sh/s6.sh
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ _s6_force_stop() {
s6-svunlink -- "$_scandir" "$name"
}

_s6_have_legacy_servicedir() {
test -z "$command" && test -x "/var/svc.d/$name/run"
}

_s6_servicedir_creation_needed() {
local dir="$_servicedirs/$name" conffile="{$RC_SERVICE%/*}/../conf.d/${RC_SERVICE##*/}"
if ! test -e "$dir" ; then
Expand Down Expand Up @@ -163,21 +167,25 @@ _s6_servicedir_create() {

s6_start()
{
local r waitcommand waitname
local servicepath r waitcommand waitname
_s6_set_variables
if ! _s6_sanity_checks ; then
eerror "s6 sanity checks failed, cannot start service"
return 1
fi
if _s6_servicedir_creation_needed ; then
servicepath="$_servicedirs/$name"
if _s6_have_legacy_servicedir ; then
servicepath="/var/svc.d/$name"
ebegin "Starting $name (via user-provided service directory)"
elif _s6_servicedir_creation_needed ; then
ebegin "Starting $name"
_s6_servicedir_create
else
ebegin "Starting $name (using cached service directory)"
fi
if s6-svlink -- "$_scandir" "$_servicedirs/$name" ; then : ; else
if s6-svlink -- "$_scandir" "$servicepath" ; then : ; else
r=$?
eend $r "Failed to s6-svlink $name into $_scandir"
eend $r "Failed to s6-svlink $servicepath into $_scandir"
return $r
fi
if test -n "$timeout_ready" ; then
Expand Down
14 changes: 13 additions & 1 deletion src/start-stop-daemon/start-stop-daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -1130,13 +1130,25 @@ int main(int argc, char **argv)
|| rc_yesno(getenv("EINFO_QUIET")))
dup2(stderr_fd, STDERR_FILENO);

cloexec_fds_from(3);
cloexec_fds_from(3); /* FIXME: this is problematic, see right below */

if (notify.type == NOTIFY_FD) {
if (close(notify.pipe[0]) == -1)
eerrorx("%s: failed to close notify pipe[0]: %s", applet, strerror(errno));
if (dup2(notify.pipe[1], notify.fd) == -1)
eerrorx("%s: failed to initialize notify fd: %s", applet, strerror(errno));

/* if notify.pipe[1] == notify.fd then the FD_CLOEXEC flag is not cleared by dup2,
leading to failure. The workaround here is to clear it manually, but the
real fix is that we should never close/cloexec fds in bulk like this */
if (notify.pipe[1] == notify.fd) {
int flags = fcntl(notify.fd, F_GETFD, 0);
if (flags == -1)
eerrorx("%s: failed to get flags for notify fd: %s", applet, strerror(errno));
if (fcntl(notify.fd, F_SETFD, flags & ~FD_CLOEXEC) == -1)
eerrorx("%s: failed to set flags for notify fd: %s", applet, strerror(errno));
}

}

if (scheduler != NULL) {
Expand Down
Loading