summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--INSTALL6
-rw-r--r--Makefile45
-rwxr-xr-xconfigure26
-rw-r--r--doc/index.html11
-rw-r--r--doc/s6-rc-compile.html118
-rw-r--r--doc/s6-rc-db.html50
-rw-r--r--doc/s6-rc.html12
-rw-r--r--examples/source/00/down1
-rw-r--r--examples/source/devd-log/producer1
-rw-r--r--examples/source/devd/logger1
-rw-r--r--examples/source/dns-cache-log/producer1
-rw-r--r--examples/source/dns-cache/logger1
-rw-r--r--examples/source/dns-server-tcp-4-log/producer1
-rw-r--r--examples/source/dns-server-tcp-4/logger1
-rw-r--r--examples/source/dns-server-udp-log/producer1
-rw-r--r--examples/source/dns-server-udp/logger1
-rw-r--r--examples/source/fdholder-log/producer1
-rw-r--r--examples/source/fdholder/logger1
-rw-r--r--examples/source/hostapd-log/producer1
-rw-r--r--examples/source/hostapd/logger1
-rw-r--r--examples/source/httpd-4-log/producer1
-rw-r--r--examples/source/httpd-4/logger1
-rw-r--r--examples/source/identd-4-log/producer1
-rw-r--r--examples/source/identd-4/logger1
-rw-r--r--examples/source/klogd-log/producer1
-rw-r--r--examples/source/klogd-srv/logger1
-rw-r--r--examples/source/ntpclient-log/producer1
-rw-r--r--examples/source/ntpclient/logger1
-rw-r--r--examples/source/qmail-log/producer1
-rw-r--r--examples/source/qmail/logger1
-rw-r--r--examples/source/qmtpd-4-log/producer1
-rw-r--r--examples/source/qmtpd-4/logger1
-rw-r--r--examples/source/smtpd-4-log/producer1
-rw-r--r--examples/source/smtpd-4/logger1
-rw-r--r--examples/source/sshd-4-log/producer1
-rw-r--r--examples/source/sshd-4/logger1
-rw-r--r--examples/source/syslogd-log/producer1
-rw-r--r--examples/source/syslogd-srv/logger1
-rw-r--r--examples/source/taiclockd-4-log/producer1
-rw-r--r--examples/source/taiclockd-4/logger1
-rw-r--r--examples/source/udhcpc-eth3-log/producer1
-rw-r--r--examples/source/udhcpc-eth3/logger1
-rw-r--r--examples/source/udhcpd-wlan0-log/producer1
-rw-r--r--examples/source/udhcpd-wlan0/logger1
-rw-r--r--package/deps.mak6
-rw-r--r--package/targets.mak15
-rw-r--r--src/include/s6-rc/s6rc-constants.h3
-rw-r--r--src/include/s6-rc/s6rc-db.h6
-rw-r--r--src/libs6rc/deps-lib/s6rc4
-rw-r--r--src/libs6rc/s6rc_db_check_depcycles.c26
-rw-r--r--src/libs6rc/s6rc_db_check_revdeps.c5
-rw-r--r--src/libs6rc/s6rc_db_read.c5
-rw-r--r--src/s6-rc/s6-rc-compile.c660
-rw-r--r--src/s6-rc/s6-rc-db.c58
-rw-r--r--src/s6-rc/s6-rc-update.c101
-rw-r--r--src/s6-rc/s6-rc.c8
-rwxr-xr-xtools/gen-deps.sh14
57 files changed, 809 insertions, 407 deletions
diff --git a/INSTALL b/INSTALL
index 3145866..b2c9d03 100644
--- a/INSTALL
+++ b/INSTALL
@@ -6,9 +6,9 @@ Build Instructions
- A POSIX-compliant C development environment
- GNU make version 4.0 or later
- - skalibs version 2.3.6.0 or later: http://skarnet.org/software/skalibs/
- - execline version 2.1.3.0 or later: http://skarnet.org/software/execline/
- - s6 version 2.2.0.0 or later: http://skarnet.org/software/s6/
+ - skalibs version 2.3.6.1 or later: http://skarnet.org/software/skalibs/
+ - execline version 2.1.3.1 or later: http://skarnet.org/software/execline/
+ - s6 version 2.2.0.1 or later: http://skarnet.org/software/s6/
This software will run on any operating system that implements
POSIX.1-2008, available at:
diff --git a/Makefile b/Makefile
index 7ff52e7..6eba87f 100644
--- a/Makefile
+++ b/Makefile
@@ -18,9 +18,23 @@ STATIC_LIBS :=
SHARED_LIBS :=
INTERNAL_LIBS :=
EXTRA_TARGETS :=
+LIB_DEFS :=
+
+define library_definition =
+LIB$(firstword $(subst =, ,$(1))) := lib$(lastword $(subst =, ,$(1))).$(if $(DO_ALLSTATIC),a,so).xyzzy
+ifdef DO_SHARED
+SHARED_LIBS += lib$(lastword $(subst =, ,$(1))).so.xyzzy
+endif
+ifdef DO_STATIC
+STATIC_LIBS += lib$(lastword $(subst =, ,$(1))).a.xyzzy
+endif
+endef
-include config.mak
include package/targets.mak
+
+$(foreach var,$(LIB_DEFS),$(eval $(call library_definition,$(var))))
+
include package/deps.mak
version_m := $(basename $(version))
@@ -30,8 +44,6 @@ CPPFLAGS_ALL := -iquote src/include-local -Isrc/include $(CPPFLAGS)
CFLAGS_ALL := $(CFLAGS) -pipe -Wall
CFLAGS_SHARED := -fPIC
LDFLAGS_ALL := $(LDFLAGS)
-LDFLAGS_SHARED := -shared
-LDLIBS_ALL := $(LDLIBS)
REALCC = $(CROSS_COMPILE)$(CC)
AR := $(CROSS_COMPILE)ar
RANLIB := $(CROSS_COMPILE)ranlib
@@ -67,11 +79,11 @@ ifneq ($(strip $(ALL_BINS)),)
endif
install: install-dynlib install-libexec install-bin install-sbin install-lib install-include
-install-dynlib: $(SHARED_LIBS:lib%.so=$(DESTDIR)$(dynlibdir)/lib%.so)
+install-dynlib: $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(dynlibdir)/lib%.so)
install-libexec: $(LIBEXEC_TARGETS:%=$(DESTDIR)$(libexecdir)/%)
install-bin: $(BIN_TARGETS:%=$(DESTDIR)$(bindir)/%)
install-sbin: $(SBIN_TARGETS:%=$(DESTDIR)$(sbindir)/%)
-install-lib: $(STATIC_LIBS:lib%.a=$(DESTDIR)$(libdir)/lib%.a)
+install-lib: $(STATIC_LIBS:lib%.a.xyzzy=$(DESTDIR)$(libdir)/lib%.a)
install-include: $(ALL_INCLUDES:src/include/$(package)/%.h=$(DESTDIR)$(includedir)/$(package)/%.h)
install-data: $(ALL_DATA:src/etc/%=$(DESTDIR)$(datadir)/%)
@@ -80,12 +92,12 @@ ifneq ($(exthome),)
update:
exec $(INSTALL) -l $(notdir $(home)) $(DESTDIR)$(exthome)
-global-links: $(DESTDIR)$(exthome) $(SHARED_LIBS:lib%.so=$(DESTDIR)$(sproot)/library.so/lib%.so) $(BIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%) $(SBIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%)
+global-links: $(DESTDIR)$(exthome) $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M)) $(BIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%) $(SBIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%)
$(DESTDIR)$(sproot)/command/%: $(DESTDIR)$(home)/command/%
exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/command/$(<F) $@
-$(DESTDIR)$(sproot)/library.so/lib%.so: $(DESTDIR)$(dynlibdir)/lib%.so
+$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M): $(DESTDIR)$(dynlibdir)/lib%.so.$(version_M)
exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/library.so/$(<F) $@
.PHONY: update global-links
@@ -95,13 +107,12 @@ endif
$(DESTDIR)$(datadir)/%: src/etc/%
exec $(INSTALL) -D -m 644 $< $@
-
-$(DESTDIR)$(dynlibdir)/lib%.so: lib%.so
+$(DESTDIR)$(dynlibdir)/lib%.so: lib%.so.xyzzy
$(INSTALL) -D -m 755 $< $@.$(version) && \
- $(INSTALL) -l $<.$(version) $@.$(version_m) && \
- $(INSTALL) -l $<.$(version_m) $@.$(version_M) && \
- $(INSTALL) -l $<.$(version_M) $@.$(version_l) && \
- exec $(INSTALL) -l $<.$(version_l) $@
+ $(INSTALL) -l $(@F).$(version) $@.$(version_m) && \
+ $(INSTALL) -l $(@F).$(version_m) $@.$(version_M) && \
+ $(INSTALL) -l $(@F).$(version_M) $@.$(version_l) && \
+ exec $(INSTALL) -l $(@F).$(version_l) $@
$(DESTDIR)$(libexecdir)/% $(DESTDIR)$(bindir)/% $(DESTDIR)$(sbindir)/%: % package/modes
exec $(INSTALL) -D -m 600 $< $@
@@ -109,7 +120,7 @@ $(DESTDIR)$(libexecdir)/% $(DESTDIR)$(bindir)/% $(DESTDIR)$(sbindir)/%: % packag
if [ x$$owner != x ] ; then chown -- $$owner $@ ; fi && \
chmod $$mode $@ ; }
-$(DESTDIR)$(libdir)/lib%.a: lib%.a
+$(DESTDIR)$(libdir)/lib%.a: lib%.a.xyzzy
exec $(INSTALL) -D -m 644 $< $@
$(DESTDIR)$(includedir)/$(package)/%.h: src/include/$(package)/%.h
@@ -122,14 +133,14 @@ $(DESTDIR)$(includedir)/$(package)/%.h: src/include/$(package)/%.h
exec $(REALCC) $(CPPFLAGS_ALL) $(CFLAGS_ALL) $(CFLAGS_SHARED) -c -o $@ $<
$(ALL_BINS):
- exec $(REALCC) -o $@ $(CFLAGS_ALL) $(LDFLAGS_ALL) $(LDFLAGS_NOSHARED) $^ $(EXTRA_LIBS) $(LDLIBS_ALL)
+ exec $(REALCC) -o $@ $(CFLAGS_ALL) $(LDFLAGS_ALL) $(LDFLAGS_NOSHARED) $^ $(EXTRA_LIBS) $(LDLIBS)
-lib%.a:
+lib%.a.xyzzy:
exec $(AR) rc $@ $^
exec $(RANLIB) $@
-lib%.so:
- exec $(REALCC) -o $@ $(CFLAGS_ALL) $(CFLAGS_SHARED) $(LDFLAGS_ALL) $(LDFLAGS_SHARED) -Wl,-soname,$@.$(version_l) $^
+lib%.so.xyzzy:
+ exec $(REALCC) -o $@ $(CFLAGS_ALL) $(CFLAGS_SHARED) $(LDFLAGS_ALL) $(LDFLAGS_SHARED) -Wl,-soname,$(patsubst lib%.so.xyzzy,lib%.so.$(version_M),$@) $^ $(EXTRA_LIBS) $(LDLIBS)
.PHONY: it all clean distclean tgz strip install install-dynlib install-bin install-sbin install-lib install-include install-data
diff --git a/configure b/configure
index 5244a37..b1590fa 100755
--- a/configure
+++ b/configure
@@ -124,6 +124,7 @@ CC_AUTO="$CC"
CFLAGS_AUTO="$CFLAGS"
CPPFLAGS_AUTO="-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -O2 $CPPFLAGS"
LDFLAGS_AUTO="$LDFLAGS"
+LDFLAGS_SHARED=-shared
LDFLAGS_NOSHARED=
prefix=
exec_prefix='$prefix'
@@ -245,10 +246,8 @@ if $slashpackage ; then
addincpath="$addincpath -I${sproot}${dep}/include"
vpaths="$vpaths ${sproot}${dep}/library"
addlibspath="$addlibspath -L${sproot}${dep}/library"
- if $allstatic ; then : ; else
- vpathd="$vpathd ${sproot}${dep}/library.so"
- addlibdpath="$addlibdpath -L${sproot}${dep}/library.so"
- fi
+ vpathd="$vpathd ${sproot}${dep}/library.so"
+ addlibdpath="$addlibdpath -L${sproot}${dep}/library.so"
done < package/deps-build
fi
@@ -305,6 +304,15 @@ fi
if $shared ; then
tryldflag LDFLAGS_AUTO -Wl,--hash-style=both
+ tryldflag LDFLAGS_SHARED -Wl,-Bsymbolic
+fi
+
+LDFLAGS_SHARED="${LDFLAGS_SHARED}${addlibdpath}"
+
+if $allstatic ; then
+ LDFLAGS_NOSHARED="${LDFLAGS_NOSHARED}${addlibspath}"
+else
+ LDFLAGS_NOSHARED="${LDFLAGS_NOSHARED}${addlibdpath}"
fi
if test -z "$vpaths" ; then
@@ -316,8 +324,6 @@ if test -z "$vpaths" ; then
fi
CPPFLAGS_AUTO="$CPPFLAGS_AUTO $addincpath"
-LDFLAGS_AUTO="$LDFLAGS_AUTO $addlibspath"
-$allstatic || LDFLAGS_AUTO="$LDFLAGS_AUTO $addlibdpath"
echo "creating config.mak..."
cmdline=$(quote "$0")
@@ -355,17 +361,19 @@ CC := $CC_AUTO
CFLAGS := $CFLAGS_AUTO
CPPFLAGS := $CPPFLAGS_AUTO
LDFLAGS := $LDFLAGS_AUTO
+LDFLAGS_SHARED := $LDFLAGS_SHARED
LDFLAGS_NOSHARED := $LDFLAGS_NOSHARED
CROSS_COMPILE := $cross
-vpath lib%a$vpaths
+vpath lib%.a$vpaths
+vpath lib%.so$vpathd
EOF
if $allstatic ; then
echo ".LIBPATTERNS := lib%.a"
echo "DO_ALLSTATIC := 1"
- vpathd=
+else
+ echo ".LIBPATTERNS := lib%.so"
fi
- echo "vpath lib%.so$vpathd"
if $static ; then
echo "DO_STATIC := 1"
else
diff --git a/doc/index.html b/doc/index.html
index c889800..de0d23d 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -47,11 +47,11 @@ scripts are also run in a controlled environment.
<li> A POSIX-compliant system with a standard C development environment </li>
<li> GNU make, version 4.0 or later </li>
<li> <a href="http://skarnet.org/software/skalibs/">skalibs</a> version
-2.3.6.0 or later </li>
+2.3.6.1 or later </li>
<li> <a href="http://skarnet.org/software/execline/">execline</a> version
-2.1.3.0 or later </li>
+2.1.3.1 or later </li>
<li> <a href="http://skarnet.org/software/s6/">s6</a> version
-2.2.0.0 or later </li>
+2.2.0.1 or later </li>
</ul>
<h3> Licensing </h3>
@@ -92,11 +92,6 @@ the previous versions of s6-rc and the current one. </li>
<h3> Commands </h3>
-<p>
- All these commands exit 111 if they encounter a temporary error, and
-100 if they encounter a permanent error - such as a misuse.
-</p>
-
<h4> Offline tools: creating and managing a compiled service database </h4>
<ul>
diff --git a/doc/s6-rc-compile.html b/doc/s6-rc-compile.html
index a11acfb..44327ba 100644
--- a/doc/s6-rc-compile.html
+++ b/doc/s6-rc-compile.html
@@ -36,7 +36,7 @@ the current service database via
<h2> Interface </h2>
<pre>
- s6-rc-compile [ -v <em>verbosity</em> ] [ -u <em>uids</em> ] [ -g <em>gids</em> ] <em>compiled</em> <em>source...</em>
+ s6-rc-compile [ -v <em>verbosity</em> ] [ -u <em>uids</em> ] [ -g <em>gids</em> ] [ -h <em>fdhuser</em> ] <em>compiled</em> <em>source...</em>
</pre>
<ul>
@@ -46,7 +46,15 @@ it expects to find a valid service definition in <em>service</em>. </li>
<li> s6-rc-compile outputs a compiled version of the service database
into <em>compiled</em>. This database contains information for all the
services declared in every <em>source</em> argument. </li>
- <li> s6-rc-compile exits 0. </li>
+</ul>
+
+<h2> Exit codes </h2>
+
+<ul>
+ <li> 0: success </li>
+ <li> 1: error in a source directory </li>
+ <li> 100: wrong usage </li>
+ <li> 111: system call failed </li>
</ul>
<h2> Options </h2>
@@ -64,6 +72,11 @@ numerical UIDs. </li>
use this database with <a href="s6-rc.html">s6-rc</a> to start and
stop services. <em>gids</em> must be a comma-separated list of
numerical GIDs. </li>
+ <li> <tt>-h&nbsp;<em>fdhuser</em></tt>&nbsp;: arrange for the
+<a href="http://skarnet.org/software/s6/s6-fdholder-daemon.html">s6-fdholder-daemon</a>
+program, which maintains the pipes for the longrun pipelines, to run
+as user <em>fdhuser</em>. By default, it runs as the user owning
+the supervision tree, i.e. most likely <tt>root</tt>. </li>
</ul>
<p>
@@ -85,7 +98,8 @@ duplicated and cannot contain a slash or a newline; they can
contain spaces and tabs, but using anything else than alphanumerical
characters, underscores and dashes is discouraged - the s6-rc programs
will handle weird names just fine, but other tools, especially
-shell scripts, may not.
+shell scripts, may not. Names are also forbidden to use the reserved
+<tt>s6rc-</tt> and <tt>s6-rc-</tt> prefixes.
</p>
<p>
@@ -221,15 +235,16 @@ directory</a>, but there are a few differences:
<li> s6-rc-compile crafts the servicedir itself, based on what it
finds in the service definition directory. It does not copy everything
directly from the definition directory to the servicedir; only two
-subdirectories will be copied as is, <tt>data</tt> and <tt>env</tt>.
+subdirectories will be copied verbatim, <tt>data</tt> and <tt>env</tt>.
So if you want to store service configuration data, to be used
by the run script, in the service directory, make sure it is in a
<tt>data/</tt> or <tt>env/</tt> subdirectory. </li>
<li> Definition directories cannot have a <tt>log</tt> subdirectory -
or if they do, it will be ignored. From s6-rc-compile's point of view,
logged s6 services must actually be defined as <em>two</em> separate
-s6-rc services, one for the producer and one for the logger; there is
-specific syntax to link those two services. </li>
+s6-rc services, one defined as a producer and one defined as a consumer,
+making a pipeline of just two services; see below for more information
+about pipelines. </li>
</ul>
<p>
@@ -243,16 +258,23 @@ files will be copied, or recreated, in the generated
<a href="http://skarnet.org/software/s6/servicedir.html">service directory</a>.
<li> Optional directories named <tt>data</tt> and <tt>env</tt>. These will
be copied verbatim into the generated service directory. </li>
- <li> An optional file named <tt>logger</tt>. If this file exists, then
-<em>service</em> will be flagged as a producer, and the file must
-contain the name of another longrun service <em>servicelog</em>, which will
-be declared as a logger for <em>service</em>. <em>service</em> must also
-be declared as a producer in <em>servicelog</em>'s definition directory. </li>
- <li> An optional file named <tt>producer</tt>. If this file exists, then
-<em>service</em> will be flagged as a logger, and the file must
-contain the name of another longrun service <em>serviceprod</em>, which will
-be declared as a producer for <em>service</em>. <em>service</em> must also
-be declared as a logger in <em>serviceprod</em>'s definition directory. </li>
+ <li> An optional file named <tt>producer-for</tt>. If this file exists, then
+it must contain the name of another longrun service <em>servicelog</em>;
+<em>service</em> is then declared as a producer for <em>servicelog</em>.
+<em>servicelog</em> must also, in its own definition directory,
+be declared as a consumer for <em>service</em>. </li>
+ <li> An optional file named <tt>consumer-for</tt>. If this file exists, then
+it must contain the name of another longrun service <em>serviceprod</em>;
+<em>service</em> is then declared as a consumer for <em>serviceprod</em>.
+<em>serviceprod</em> must also, in its own definition directory,
+be declared as a producer for <em>service</em>. </li>
+ <li> An optional file named <tt>pipeline-name</tt>. If this file exists
+along with a <tt>producer-for</tt> file, and there is no
+<tt>consumer-for</tt> file, then a bundle will automatically be
+created, named with the content of the <tt>pipeline-name</tt> file, and
+containing all the services in the pipeline that starts at <em>service</em>.
+See below for more about pipelining. The <tt>pipeline-name</tt> file
+is ignored if <em>service</em> is not a first producer. </li>
</ul>
<p>
@@ -271,26 +293,60 @@ services that are down.
</p>
<p>
- The <tt>logger</tt> and <tt>producer</tt> files are support for logged services:
-A service defined as a logger for producer <em>p</em> will have its s6 service
-directory set to <em>p</em><tt>/log</tt>. Logged service definitions must be consistent:
+ The <tt>producer-for</tt>, <tt>consumer-for</tt> and <tt>pipeline-name</tt>
+files are used to set up automatic longrun pipelining.
+</p>
+
+<h3> Longrun pipelining </h3>
+
+<p>
+ Users of supervision suites know about logged services: a service acts
+as a producer, and is coupled with another service, its logger; the
+supervision system automatically maintains an open pipe between the
+producer's stdout and the logger's stdin.
+</p>
+
+<p>
+ s6-rc comes with an extension of this mechanism. Rather than only
+allowing two longrun services to be pipelined, it can set up an
+indefinite number of longrun services this way.
</p>
<ul>
- <li> It is impossible to have a both a <tt>logger</tt> and a <tt>producer</tt> file
-in the same definition directory: loggers cannot have loggers, producers cannot have
-producers. </li>
- <li> The logger must be declared in the <tt>logger</tt> file in its producer's
-definition directory, and the producer must be declared in the <tt>producer</tt> file
-in its logger's definition directory. If it sees an inconsistency, s6-rc-compile
-will complain and exit 1. </li>
- <li> The producer will automatically have a dependency to its logger (because,
-as much as systemd would have you believe the opposite, it is
-not safe to start a service while its logger is not up). This means that a
-<a href="s6-rc.html">s6-rc change</a> command to start the service will
-automatically start the logger beforehand if it's not already up. </li>
+ <li> The first producer declares its direct consumer in a <tt>producer-for</tt> file. </li>
+ <li> Intermediate services declare both their direct producer in their
+<tt>consumer-for</tt> file, and their direct consumer in their
+<tt>producer-for</tt> file. </li>
+ <li> The last consumer only declares its direct producer in a <tt>consumer-for</tt> file. </li>
+ <li> The first producer may declare a name for the whole pipeline, in
+its <tt>pipeline-name</tt> file. If it does so, then a bundle is automatically
+created with
+the given name, and it contains all the services in the pipeline (plus the
+automatically generated supporting services that open and store the
+pipes). </li>
</ul>
+<p>
+ s6-rc-compile will detect pipelines, and set up the service directories
+so that every producer's stdout is connected to its consumer's stdin, and
+that the pipes are not broken whenever one element in the chain dies.
+</p>
+
+<p>
+ s6-rc-compile checks for pipeline consistency. It must see a
+<tt>producer-for</tt> file in the producer's definition that is consistent
+with the <tt>consumer-for</tt> file in the consumer's definition. It will
+detect and reject cycles as well as collisions.
+</p>
+
+<p>
+ The pipe linking a producer and a consumer is created by an automatically
+generated oneshot service that both the producer and consumer depend on,
+and stored in a
+<a href="http://skarnet.org/software/s6/s6-fdholder-daemon.html">s6-fdholder-daemon</a>
+instance created by an automatically generated longrun service.
+</p>
+
<h2> A complete example </h2>
<p>
diff --git a/doc/s6-rc-db.html b/doc/s6-rc-db.html
index 280f98a..a60658e 100644
--- a/doc/s6-rc-db.html
+++ b/doc/s6-rc-db.html
@@ -43,7 +43,7 @@ operation.
s6-rc-db [ -l <em>live</em> ] [ -c <em>compiled</em> ] [ -u | -d ] timeout <em>atomicname</em>
s6-rc-db [ -l <em>live</em> ] [ -c <em>compiled</em> ] contents <em>bundlename</em>
s6-rc-db [ -l <em>live</em> ] [ -c <em>compiled</em> ] [ -u | -d ] dependencies <em>servicename</em>
- s6-rc-db [ -l <em>live</em> ] [ -c <em>compiled</em> ] servicedir <em>longrunname</em>
+ s6-rc-db [ -l <em>live</em> ] [ -c <em>compiled</em> ] pipeline <em>longrunname</em>
s6-rc-db [ -l <em>live</em> ] [ -c <em>compiled</em> ] [ -u | -d ] script <em>oneshotname</em>
s6-rc-db [ -l <em>live</em> ] [ -c <em>compiled</em> ] flags <em>atomicname</em>
s6-rc-db [ -l <em>live</em> ] [ -c <em>compiled</em> ] atomics <em>servicename...</em>
@@ -54,9 +54,8 @@ operation.
<li> s6-rc-db expects to find a <em>compiled service database</em>
in <em>compiled</em>; by default it uses the service database
used by the live state in <em>live</em>.
-It reads and parses the compiled database it finds. If the
-database is invalid, it exits 4. </li>
- <li> Depending on the arguments given, it prints the requested
+It reads and parses the compiled database it finds; depending on
+its arguments, it prints the requested
information to stdout, then exits 0. </li>
</ul>
@@ -78,6 +77,17 @@ depending on whether it's about bringing the service up or down,
select the "down" data. This option is ignored when it is irrelevant. </li>
</ul>
+<h2> Exit codes </h2>
+
+<ul>
+ <li> 0: success </li>
+ <li> 3: identifier not found in service database </li>
+ <li> 4: invalid or corrupted service database </li>
+ <li> 5: wrong identifier type for the given command </li>
+ <li> 100: wrong usage </li>
+ <li> 111: system call failed </li>
+</ul>
+
<h2> Subcommands </h2>
<h3> s6-rc-db help </h3>
@@ -134,8 +144,7 @@ dependency tables, or a dependency cycle.
<p>
Prints the type of <em>servicename</em>: <tt>oneshot</tt>, <tt>longrun</tt>
-or <tt>bundle</tt>. Exits 1 if
-<em>servicename</em> is not a valid identifier in the database.
+or <tt>bundle</tt>.
</p>
<h3> s6-rc-db timeout <em>atomicname</em> </h3>
@@ -143,8 +152,8 @@ or <tt>bundle</tt>. Exits 1 if
<p>
Prints the timeout value, in milliseconds, after which bringing
<em>atomicname</em> up or down is considered a failure if the
-called script still has not succeeded. Exits 1 if <em>atomicname</em>
-isn't a valid atomic service. By default, or if the <tt>-u</tt>
+called script still has not succeeded.
+By default, or if the <tt>-u</tt>
option has been given to s6-rc-db, the timeout for <em>up</em> is
printed; the timeout for <em>down</em> is printed instead if the
<tt>-d</tt> option has been given.
@@ -154,14 +163,12 @@ printed; the timeout for <em>down</em> is printed instead if the
<p>
Lists the atomic services represented by bundle <em>bundlename</em>.
-Exits 1 if <em>bundlename</em> is not a valid bundle.
</p>
<h3> s6-rc-db dependencies <em>servicename</em> </h3>
<p>
- Prints the list of direct dependencies for <em>servicename</em>.
-Exits 1 if <em>servicename</em> isn't a valid identifier. If
+ Prints the list of direct dependencies for <em>servicename</em>. If
<em>servicename</em> is a bundle, its set of direct dependencies
is the union of the direct dependencies of all the atomic services
contained in the bundle.
@@ -174,12 +181,13 @@ depend on <em>servicename</em>, or on one of its components if it
is a bundle.
</p>
-<h3> s6-rc-db servicedir <em>longrunname</em> </h3>
+<h3> s6-rc-db pipeline <em>longrunname</em> </h3>
<p>
- Prints the service directory for longrun service <em>longrunname</em>;
-this value is <em>relative to the scandir</em>. Exits 1 if
-<em>longrunname</em> is not a valid longrun.
+ Prints the longrun service pipeline <em>longrunname</em> is a
+part of, one service per line, producers before consumers.
+If <em>longrunname</em> isn't
+part of a pipeline, only <em>longrunname</em> is printed.
</p>
<h3> s6-rc-db script <em>oneshotname</em> </h3>
@@ -190,8 +198,7 @@ an <em>argv</em>, i.e. a Unix command line. Each component of this
command line is
<strong>terminated by a null character</strong>, so to print it in
a human-readable format, pipe the output into something like
-<tt>xargs -0 echo</tt>. The command exits 1 if <em>oneshotname</em>
-is not a valid oneshot.
+<tt>xargs -0 echo</tt>.
</p>
<p>
@@ -203,8 +210,7 @@ is not a valid oneshot.
<p>
Prints a hexadecimal number that is the list of all binary flags
-for atomic service <em>atomicname</em>. Exits 1 if <em>atomicname</em>
-is not a valid atomic service.
+for atomic service <em>atomicname</em>.
</p>
<p>
@@ -219,8 +225,7 @@ future version of s6-rc.
<em>servicename...</em> arguments, i.e. the union of all
atomic services contained in <em>servicename...</em>. Each
argument in <em>servicename...</em> can be an atomic service or
-a bundle. If an argument isn't a valid identifier, the command
-exits 1.
+a bundle.
</p>
<h3> s6-rc-db all-dependencies <em>servicename...</em> </h3>
@@ -232,8 +237,7 @@ dependencies, recursively. In other words: for
<em>servicename...</em> to be up, every single service listed
in the output will need to be up. The output includes the
atomic services represented by the
-<em>servicename...</em> arguments themselves. If one of those
-arguments isn't a valid identifier, the command exits 1.
+<em>servicename...</em> arguments themselves.
</p>
<p>
diff --git a/doc/s6-rc.html b/doc/s6-rc.html
index ae3e469..75dba9a 100644
--- a/doc/s6-rc.html
+++ b/doc/s6-rc.html
@@ -59,6 +59,18 @@ information to stdout, then exits 0; or it performs a machine
state change. </li>
</ul>
+<h2> Exit codes </h2>
+
+<ul>
+ <li> 0: success </li>
+ <li> 1: some of the state transitions could not be performed </li>
+ <li> 2: timed out during state change </li>
+ <li> 3: unknown service name in the arguments </li>
+ <li> 4: invalid service database </li>
+ <li> 100: wrong usage </li>
+ <li> 111: system call failed </li>
+</ul>
+
<h2> Service selection </h2>
<p>
diff --git a/examples/source/00/down b/examples/source/00/down
deleted file mode 100644
index 8b13789..0000000
--- a/examples/source/00/down
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/examples/source/devd-log/producer b/examples/source/devd-log/producer
deleted file mode 100644
index 0b3e805..0000000
--- a/examples/source/devd-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-devd
diff --git a/examples/source/devd/logger b/examples/source/devd/logger
deleted file mode 100644
index 09c60aa..0000000
--- a/examples/source/devd/logger
+++ /dev/null
@@ -1 +0,0 @@
-devd-log
diff --git a/examples/source/dns-cache-log/producer b/examples/source/dns-cache-log/producer
deleted file mode 100644
index d51d8a1..0000000
--- a/examples/source/dns-cache-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-dns-cache
diff --git a/examples/source/dns-cache/logger b/examples/source/dns-cache/logger
deleted file mode 100644
index 54ef42e..0000000
--- a/examples/source/dns-cache/logger
+++ /dev/null
@@ -1 +0,0 @@
-dns-cache-log
diff --git a/examples/source/dns-server-tcp-4-log/producer b/examples/source/dns-server-tcp-4-log/producer
deleted file mode 100644
index eed0fe9..0000000
--- a/examples/source/dns-server-tcp-4-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-dns-server-tcp-4
diff --git a/examples/source/dns-server-tcp-4/logger b/examples/source/dns-server-tcp-4/logger
deleted file mode 100644
index d437be5..0000000
--- a/examples/source/dns-server-tcp-4/logger
+++ /dev/null
@@ -1 +0,0 @@
-dns-server-tcp-4-log
diff --git a/examples/source/dns-server-udp-log/producer b/examples/source/dns-server-udp-log/producer
deleted file mode 100644
index 6517ecf..0000000
--- a/examples/source/dns-server-udp-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-dns-server-udp
diff --git a/examples/source/dns-server-udp/logger b/examples/source/dns-server-udp/logger
deleted file mode 100644
index 81fc8f4..0000000
--- a/examples/source/dns-server-udp/logger
+++ /dev/null
@@ -1 +0,0 @@
-dns-server-udp-log
diff --git a/examples/source/fdholder-log/producer b/examples/source/fdholder-log/producer
deleted file mode 100644
index c9e44ab..0000000
--- a/examples/source/fdholder-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-fdholder
diff --git a/examples/source/fdholder/logger b/examples/source/fdholder/logger
deleted file mode 100644
index 11f1ac2..0000000
--- a/examples/source/fdholder/logger
+++ /dev/null
@@ -1 +0,0 @@
-fdholder-log
diff --git a/examples/source/hostapd-log/producer b/examples/source/hostapd-log/producer
deleted file mode 100644
index f86cc31..0000000
--- a/examples/source/hostapd-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-hostapd
diff --git a/examples/source/hostapd/logger b/examples/source/hostapd/logger
deleted file mode 100644
index b6e1e02..0000000
--- a/examples/source/hostapd/logger
+++ /dev/null
@@ -1 +0,0 @@
-hostapd-log
diff --git a/examples/source/httpd-4-log/producer b/examples/source/httpd-4-log/producer
deleted file mode 100644
index 3dfc041..0000000
--- a/examples/source/httpd-4-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-httpd-4
diff --git a/examples/source/httpd-4/logger b/examples/source/httpd-4/logger
deleted file mode 100644
index 9835bc1..0000000
--- a/examples/source/httpd-4/logger
+++ /dev/null
@@ -1 +0,0 @@
-httpd-4-log
diff --git a/examples/source/identd-4-log/producer b/examples/source/identd-4-log/producer
deleted file mode 100644
index f3a2772..0000000
--- a/examples/source/identd-4-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-identd-4
diff --git a/examples/source/identd-4/logger b/examples/source/identd-4/logger
deleted file mode 100644
index 7b1014d..0000000
--- a/examples/source/identd-4/logger
+++ /dev/null
@@ -1 +0,0 @@
-identd-4-log
diff --git a/examples/source/klogd-log/producer b/examples/source/klogd-log/producer
deleted file mode 100644
index 3a77aac..0000000
--- a/examples/source/klogd-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-klogd-srv
diff --git a/examples/source/klogd-srv/logger b/examples/source/klogd-srv/logger
deleted file mode 100644
index 2f21a8f..0000000
--- a/examples/source/klogd-srv/logger
+++ /dev/null
@@ -1 +0,0 @@
-klogd-log
diff --git a/examples/source/ntpclient-log/producer b/examples/source/ntpclient-log/producer
deleted file mode 100644
index a0f3ade..0000000
--- a/examples/source/ntpclient-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-ntpclient
diff --git a/examples/source/ntpclient/logger b/examples/source/ntpclient/logger
deleted file mode 100644
index c51cd0b..0000000
--- a/examples/source/ntpclient/logger
+++ /dev/null
@@ -1 +0,0 @@
-ntpclient-log
diff --git a/examples/source/qmail-log/producer b/examples/source/qmail-log/producer
deleted file mode 100644
index e9c4b1e..0000000
--- a/examples/source/qmail-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-qmail
diff --git a/examples/source/qmail/logger b/examples/source/qmail/logger
deleted file mode 100644
index db09b5f..0000000
--- a/examples/source/qmail/logger
+++ /dev/null
@@ -1 +0,0 @@
-qmail-log
diff --git a/examples/source/qmtpd-4-log/producer b/examples/source/qmtpd-4-log/producer
deleted file mode 100644
index bf4ce61..0000000
--- a/examples/source/qmtpd-4-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-qmtpd-4
diff --git a/examples/source/qmtpd-4/logger b/examples/source/qmtpd-4/logger
deleted file mode 100644
index fbc3153..0000000
--- a/examples/source/qmtpd-4/logger
+++ /dev/null
@@ -1 +0,0 @@
-qmtpd-4-log
diff --git a/examples/source/smtpd-4-log/producer b/examples/source/smtpd-4-log/producer
deleted file mode 100644
index bff8ca4..0000000
--- a/examples/source/smtpd-4-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-smtpd-4
diff --git a/examples/source/smtpd-4/logger b/examples/source/smtpd-4/logger
deleted file mode 100644
index c6fa24d..0000000
--- a/examples/source/smtpd-4/logger
+++ /dev/null
@@ -1 +0,0 @@
-smtpd-4-log
diff --git a/examples/source/sshd-4-log/producer b/examples/source/sshd-4-log/producer
deleted file mode 100644
index 7d1730e..0000000
--- a/examples/source/sshd-4-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-sshd-4
diff --git a/examples/source/sshd-4/logger b/examples/source/sshd-4/logger
deleted file mode 100644
index f103f82..0000000
--- a/examples/source/sshd-4/logger
+++ /dev/null
@@ -1 +0,0 @@
-sshd-4-log
diff --git a/examples/source/syslogd-log/producer b/examples/source/syslogd-log/producer
deleted file mode 100644
index 93c1661..0000000
--- a/examples/source/syslogd-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-syslogd-srv
diff --git a/examples/source/syslogd-srv/logger b/examples/source/syslogd-srv/logger
deleted file mode 100644
index 75d14f5..0000000
--- a/examples/source/syslogd-srv/logger
+++ /dev/null
@@ -1 +0,0 @@
-syslogd-log
diff --git a/examples/source/taiclockd-4-log/producer b/examples/source/taiclockd-4-log/producer
deleted file mode 100644
index 7684875..0000000
--- a/examples/source/taiclockd-4-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-taiclockd-4
diff --git a/examples/source/taiclockd-4/logger b/examples/source/taiclockd-4/logger
deleted file mode 100644
index 04d85c4..0000000
--- a/examples/source/taiclockd-4/logger
+++ /dev/null
@@ -1 +0,0 @@
-taiclockd-4-log
diff --git a/examples/source/udhcpc-eth3-log/producer b/examples/source/udhcpc-eth3-log/producer
deleted file mode 100644
index 6904444..0000000
--- a/examples/source/udhcpc-eth3-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-udhcpc-eth3
diff --git a/examples/source/udhcpc-eth3/logger b/examples/source/udhcpc-eth3/logger
deleted file mode 100644
index 018297b..0000000
--- a/examples/source/udhcpc-eth3/logger
+++ /dev/null
@@ -1 +0,0 @@
-udhcpc-eth3-log
diff --git a/examples/source/udhcpd-wlan0-log/producer b/examples/source/udhcpd-wlan0-log/producer
deleted file mode 100644
index d336700..0000000
--- a/examples/source/udhcpd-wlan0-log/producer
+++ /dev/null
@@ -1 +0,0 @@
-udhcpd-wlan0
diff --git a/examples/source/udhcpd-wlan0/logger b/examples/source/udhcpd-wlan0/logger
deleted file mode 100644
index f5ac32a..0000000
--- a/examples/source/udhcpd-wlan0/logger
+++ /dev/null
@@ -1 +0,0 @@
-udhcpd-wlan0-log
diff --git a/package/deps.mak b/package/deps.mak
index a5d7b1d..a2a4dc4 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -5,6 +5,7 @@
src/include/s6-rc/s6rc-utils.h: src/include/s6-rc/s6rc-db.h
src/include/s6-rc/s6rc.h: src/include/s6-rc/s6rc-constants.h src/include/s6-rc/s6rc-db.h src/include/s6-rc/s6rc-utils.h
src/libs6rc/s6rc_db_check_depcycles.o src/libs6rc/s6rc_db_check_depcycles.lo: src/libs6rc/s6rc_db_check_depcycles.c src/include/s6-rc/s6rc-db.h
+src/libs6rc/s6rc_db_check_pipelines.o src/libs6rc/s6rc_db_check_pipelines.lo: src/libs6rc/s6rc_db_check_pipelines.c src/include/s6-rc/s6rc-db.h
src/libs6rc/s6rc_db_check_revdeps.o src/libs6rc/s6rc_db_check_revdeps.lo: src/libs6rc/s6rc_db_check_revdeps.c src/include/s6-rc/s6rc-db.h
src/libs6rc/s6rc_db_read.o src/libs6rc/s6rc_db_read.lo: src/libs6rc/s6rc_db_read.c src/include/s6-rc/s6rc-db.h
src/libs6rc/s6rc_db_read_sizes.o src/libs6rc/s6rc_db_read_sizes.lo: src/libs6rc/s6rc_db_read_sizes.c src/include/s6-rc/s6rc-db.h
@@ -17,8 +18,9 @@ src/s6-rc/s6-rc-init.o src/s6-rc/s6-rc-init.lo: src/s6-rc/s6-rc-init.c src/inclu
src/s6-rc/s6-rc-update.o src/s6-rc/s6-rc-update.lo: src/s6-rc/s6-rc-update.c src/include/s6-rc/config.h src/include/s6-rc/s6rc.h
src/s6-rc/s6-rc.o src/s6-rc/s6-rc.lo: src/s6-rc/s6-rc.c src/include/s6-rc/config.h src/include/s6-rc/s6rc.h
-libs6rc.a: src/libs6rc/s6rc_db_check_depcycles.o src/libs6rc/s6rc_db_read.o src/libs6rc/s6rc_db_read_sizes.o src/libs6rc/s6rc_db_read_uint32.o src/libs6rc/s6rc_db_check_revdeps.o src/libs6rc/s6rc_graph_closure.o
-libs6rc.so: src/libs6rc/s6rc_db_check_depcycles.lo src/libs6rc/s6rc_db_read.lo src/libs6rc/s6rc_db_read_sizes.lo src/libs6rc/s6rc_db_read_uint32.lo src/libs6rc/s6rc_db_check_revdeps.lo src/libs6rc/s6rc_graph_closure.lo
+libs6rc.a.xyzzy: src/libs6rc/s6rc_db_check_depcycles.o src/libs6rc/s6rc_db_check_pipelines.o src/libs6rc/s6rc_db_check_revdeps.o src/libs6rc/s6rc_db_read.o src/libs6rc/s6rc_db_read_sizes.o src/libs6rc/s6rc_db_read_uint32.o src/libs6rc/s6rc_graph_closure.o
+libs6rc.so.xyzzy: private EXTRA_LIBS := -lskarnet
+libs6rc.so.xyzzy: src/libs6rc/s6rc_db_check_depcycles.lo src/libs6rc/s6rc_db_check_pipelines.lo src/libs6rc/s6rc_db_check_revdeps.lo src/libs6rc/s6rc_db_read.lo src/libs6rc/s6rc_db_read_sizes.lo src/libs6rc/s6rc_db_read_uint32.lo src/libs6rc/s6rc_graph_closure.lo
s6-rc: private EXTRA_LIBS := ${TAINNOW_LIB}
s6-rc: src/s6-rc/s6-rc.o ${LIBS6RC} -lskarnet
s6-rc-compile: private EXTRA_LIBS :=
diff --git a/package/targets.mak b/package/targets.mak
index 9bcf975..5f50ad4 100644
--- a/package/targets.mak
+++ b/package/targets.mak
@@ -8,19 +8,6 @@ s6-rc-init \
s6-rc \
s6-rc-update
-
LIBEXEC_TARGETS :=
-ifdef DO_ALLSTATIC
-LIBS6RC := libs6rc.a
-else
-LIBS6RC := libs6rc.so
-endif
-
-ifdef DO_SHARED
-SHARED_LIBS := libs6rc.so
-endif
-
-ifdef DO_STATIC
-STATIC_LIBS := libs6rc.a
-endif
+LIB_DEFS := S6RC=s6rc
diff --git a/src/include/s6-rc/s6rc-constants.h b/src/include/s6-rc/s6rc-constants.h
index 92af2a9..87e7053 100644
--- a/src/include/s6-rc/s6rc-constants.h
+++ b/src/include/s6-rc/s6rc-constants.h
@@ -11,4 +11,7 @@
#define S6RC_ONESHOT_RUNNER "s6rc-oneshot-runner"
#define S6RC_ONESHOT_RUNNER_LEN (sizeof S6RC_ONESHOT_RUNNER - 1)
+#define S6RC_FDHOLDER "s6rc-fdholder"
+#define S6RC_FDHOLDER_LEN (sizeof S6RC_FDHOLDER - 1)
+
#endif
diff --git a/src/include/s6-rc/s6rc-db.h b/src/include/s6-rc/s6rc-db.h
index bc516b2..0053af9 100644
--- a/src/include/s6-rc/s6rc-db.h
+++ b/src/include/s6-rc/s6rc-db.h
@@ -4,6 +4,7 @@
#define S6RC_DB_H
#include <skalibs/uint32.h>
+#include <skalibs/diuint32.h>
#include <skalibs/buffer.h>
#define S6RC_DB_BANNER_START "s6rc-db: start\n"
@@ -22,7 +23,7 @@ struct s6rc_oneshot_s
typedef struct s6rc_longrun_s s6rc_longrun_t, *s6rc_longrun_t_ref ;
struct s6rc_longrun_s
{
- uint32 servicedir ;
+ uint32 pipeline[2] ;
} ;
typedef union s6rc_longshot_u s6rc_longshot_t, *s6rc_longshot_t_ref ;
@@ -62,7 +63,8 @@ extern int s6rc_db_read_uint32 (buffer *, uint32 *) ;
extern int s6rc_db_read_sizes (int, s6rc_db_t *) ;
extern int s6rc_db_read (int, s6rc_db_t *) ;
-extern unsigned int s6rc_db_check_depcycles (s6rc_db_t const *, int, unsigned int *) ;
+extern int s6rc_db_check_pipelines (s6rc_db_t const *, diuint32 *) ;
+extern int s6rc_db_check_depcycles (s6rc_db_t const *, int, diuint32 *) ;
extern int s6rc_db_check_revdeps (s6rc_db_t const *) ;
#endif
diff --git a/src/libs6rc/deps-lib/s6rc b/src/libs6rc/deps-lib/s6rc
index 65b562e..194ea43 100644
--- a/src/libs6rc/deps-lib/s6rc
+++ b/src/libs6rc/deps-lib/s6rc
@@ -1,6 +1,8 @@
s6rc_db_check_depcycles.o
+s6rc_db_check_pipelines.o
+s6rc_db_check_revdeps.o
s6rc_db_read.o
s6rc_db_read_sizes.o
s6rc_db_read_uint32.o
-s6rc_db_check_revdeps.o
s6rc_graph_closure.o
+-lskarnet
diff --git a/src/libs6rc/s6rc_db_check_depcycles.c b/src/libs6rc/s6rc_db_check_depcycles.c
index 13dcf7b..db6ed6e 100644
--- a/src/libs6rc/s6rc_db_check_depcycles.c
+++ b/src/libs6rc/s6rc_db_check_depcycles.c
@@ -1,6 +1,7 @@
/* ISC license. */
#include <skalibs/uint32.h>
+#include <skalibs/diuint32.h>
#include <skalibs/bitarray.h>
#include <skalibs/bytestr.h>
#include <s6-rc/s6rc-db.h>
@@ -9,22 +10,22 @@ typedef struct recinfo_s recinfo_t, *recinfo_t_ref ;
struct recinfo_s
{
s6rc_db_t const *db ;
- unsigned int n ;
+ uint32 n ;
unsigned char *gray ;
unsigned char *black ;
unsigned char h : 1 ;
} ;
-static unsigned int s6rc_db_checknocycle_rec (recinfo_t *recinfo, unsigned int i)
+static uint32 s6rc_db_checknocycle_rec (recinfo_t *recinfo, uint32 i)
{
if (!bitarray_peek(recinfo->black, i))
{
- unsigned int j = recinfo->db->services[i].ndeps[recinfo->h] ;
+ uint32 j = recinfo->db->services[i].ndeps[recinfo->h] ;
if (bitarray_peek(recinfo->gray, i)) return i ;
bitarray_set(recinfo->gray, i) ;
while (j--)
{
- register unsigned int r = s6rc_db_checknocycle_rec(recinfo, recinfo->db->deps[recinfo->h * recinfo->db->ndeps + recinfo->db->services[i].deps[recinfo->h] + j]) ;
+ register uint32 r = s6rc_db_checknocycle_rec(recinfo, recinfo->db->deps[recinfo->h * recinfo->db->ndeps + recinfo->db->services[i].deps[recinfo->h] + j]) ;
if (r < recinfo->n) return r ;
}
bitarray_set(recinfo->black, i) ;
@@ -32,19 +33,24 @@ static unsigned int s6rc_db_checknocycle_rec (recinfo_t *recinfo, unsigned int i
return recinfo->n ;
}
-unsigned int s6rc_db_check_depcycles (s6rc_db_t const *db, int h, unsigned int *problem)
+int s6rc_db_check_depcycles (s6rc_db_t const *db, int h, diuint32 *problem)
{
- unsigned int n = db->nshort + db->nlong ;
+ uint32 n = db->nshort + db->nlong ;
+ uint32 i = n ;
unsigned char gray[bitarray_div8(n)] ;
unsigned char black[bitarray_div8(n)] ;
recinfo_t info = { .db = db, .n = n, .gray = gray, .black = black, .h = !!h } ;
- unsigned int i = n ;
byte_zero(gray, bitarray_div8(n)) ;
byte_zero(black, bitarray_div8(n)) ;
while (i--)
{
- register unsigned int r = s6rc_db_checknocycle_rec(&info, i) ;
- if (r < n) return (*problem = r, i) ;
+ register uint32 r = s6rc_db_checknocycle_rec(&info, i) ;
+ if (r < n)
+ {
+ problem->left = i ;
+ problem->right = r ;
+ return 1 ;
+ }
}
- return n ;
+ return 0 ;
}
diff --git a/src/libs6rc/s6rc_db_check_revdeps.c b/src/libs6rc/s6rc_db_check_revdeps.c
index 0cb2845..a4342b1 100644
--- a/src/libs6rc/s6rc_db_check_revdeps.c
+++ b/src/libs6rc/s6rc_db_check_revdeps.c
@@ -1,6 +1,5 @@
/* ISC license. */
-#include <skalibs/uint32.h>
#include <skalibs/bytestr.h>
#include <skalibs/bitarray.h>
#include <s6-rc/s6rc-db.h>
@@ -25,6 +24,6 @@ int s6rc_db_check_revdeps (s6rc_db_t const *db)
while (j--) bitarray_not(matrix + m * db->deps[db->services[i].deps[0] + j], i, 1) ;
}
i = n * m ;
- while (i--) if (*p++) return 0 ;
- return 1 ;
+ while (i--) if (*p++) return 1 ;
+ return 0 ;
}
diff --git a/src/libs6rc/s6rc_db_read.c b/src/libs6rc/s6rc_db_read.c
index 7a38797..50e1f78 100644
--- a/src/libs6rc/s6rc_db_read.c
+++ b/src/libs6rc/s6rc_db_read.c
@@ -90,9 +90,8 @@ static inline int s6rc_db_read_services (buffer *b, s6rc_db_t *db)
#endif
if (i < db->nlong)
{
- if (!s6rc_db_read_uint32(b, &sv->x.longrun.servicedir)) return -1 ;
- DBG(" longrun - servicedir is %u: %s", sv->x.longrun.servicedir, db->string + sv->x.longrun.servicedir) ;
- if (!s6rc_db_check_valid_string(db->string, db->stringlen, sv->x.longrun.servicedir)) return 0 ;
+ if (!s6rc_db_read_uint32(b, &sv->x.longrun.pipeline[0])) return -1 ;
+ if (!s6rc_db_read_uint32(b, &sv->x.longrun.pipeline[1])) return -1 ;
}
else
{
diff --git a/src/s6-rc/s6-rc-compile.c b/src/s6-rc/s6-rc-compile.c
index 1126967..a1ffdee 100644
--- a/src/s6-rc/s6-rc-compile.c
+++ b/src/s6-rc/s6-rc-compile.c
@@ -27,10 +27,12 @@
#include <s6/config.h>
#include <s6-rc/s6rc.h>
-#define USAGE "s6-rc-compile [ -v verbosity ] [ -u okuid,okuid... ] [ -g okgid,okgid... ] destdir sources..."
+#define USAGE "s6-rc-compile [ -v verbosity ] [ -u okuid,okuid... ] [ -g okgid,okgid... ] [ -h fdholder_user ] destdir sources..."
#define dieusage() strerr_dieusage(100, USAGE)
#define dienomem() strerr_dief1x(111, "out of memory") ;
+#define S6RC_INTERNALS "s6-rc-compile internals"
+
#define S6RC_ONESHOT_RUNNER_RUNSCRIPT \
"#!" EXECLINE_SHEBANGPREFIX "execlineb -P\n" \
EXECLINE_EXTBINPREFIX "fdmove -c 2 1\n" \
@@ -40,8 +42,6 @@ S6_EXTBINPREFIX "s6-ipcserverd -1 --\n" \
S6_EXTBINPREFIX "s6-ipcserver-access -v0 -E -l0 -i data/rules --\n" \
S6_EXTBINPREFIX "s6-sudod -t 2000 --\n"
-#define BASE_RULES "servicedirs/" S6RC_ONESHOT_RUNNER "/data/rules/gid"
-
static unsigned int verbosity = 1 ;
static stralloc keep = STRALLOC_ZERO ;
static stralloc data = STRALLOC_ZERO ;
@@ -91,7 +91,6 @@ static avltree names_map = AVLTREE_INIT(8, 3, 8, &names_dtok, &names_cmp, &namei
typedef struct common_s common_t, *common_t_ref ;
struct common_s
{
- unsigned int name ; /* pos in data */
unsigned int kname ; /* pos in keep */
unsigned int ndeps ;
unsigned int depindex ; /* pos in indices */
@@ -103,7 +102,7 @@ typedef struct oneshot_s oneshot_t, *oneshot_t_ref ;
struct oneshot_s
{
common_t common ;
- unsigned int argvindex[2] ; /* pos in data */
+ unsigned int argvindex[2] ; /* pos in keep */
unsigned int argc[2] ;
} ;
@@ -112,9 +111,8 @@ struct longrun_s
{
common_t common ;
char const *srcdir ;
- unsigned int servicedirname ;
- unsigned int logrelated ;
- unsigned char logtype ;
+ unsigned int pipeline[2] ; /* pos in data */
+ unsigned int pipelinename ; /* pos in data */
} ;
typedef struct bundle_s bundle_t, *bundle_t_ref ;
@@ -128,19 +126,19 @@ struct bundle_s
typedef struct before_s before_t, *before_t_ref ;
struct before_s
{
- genalloc indices ; /* uint32 */
+ genalloc indices ; /* unsigned int */
genalloc oneshots ; /* oneshot_t */
genalloc longruns ; /* longrun_t */
genalloc bundles ; /* bundle_t */
unsigned int nargvs ;
- unsigned int maxnamelen ;
+ uint32 specialdeps[2] ;
} ;
-#define BEFORE_ZERO { .indices = GENALLOC_ZERO, .oneshots = GENALLOC_ZERO, .longruns = GENALLOC_ZERO, .bundles = GENALLOC_ZERO, .nargvs = 0 } ;
+#define BEFORE_ZERO { .indices = GENALLOC_ZERO, .oneshots = GENALLOC_ZERO, .longruns = GENALLOC_ZERO, .bundles = GENALLOC_ZERO, .nargvs = 0, .specialdeps = { 0, 0 } } ;
- /* Read all the sources, populate the map and string data */
+ /* Read all the sources, populate the name map */
static char const *typestr (servicetype_t type)
@@ -151,7 +149,7 @@ static char const *typestr (servicetype_t type)
"unknown" ;
}
-static int add_name (before_t *be, char const *srcdir, char const *name, servicetype_t type, unsigned int *pos, unsigned int *kpos)
+static int add_name_nocheck (before_t *be, char const *srcdir, char const *name, servicetype_t type, unsigned int *pos, unsigned int *kpos)
{
unsigned int id ;
@@ -214,20 +212,32 @@ static int add_name (before_t *be, char const *srcdir, char const *name, service
} ;
unsigned int namelen = str_len(name) ;
unsigned int i = genalloc_len(nameinfo_t, &nameinfo) ;
- if (!stralloc_catb(&data, name, namelen + 1)) dienomem() ;
if (type == SVTYPE_ONESHOT || type == SVTYPE_LONGRUN)
if (!stralloc_catb(&keep, name, namelen + 1)) dienomem() ;
+ if (!stralloc_catb(&data, name, namelen + 1)) dienomem() ;
if (!genalloc_append(nameinfo_t, &nameinfo, &info)) dienomem() ;
if (!avltree_insert(&names_map, i)) dienomem() ;
*pos = info.pos ;
*kpos = info.kpos ;
- if (namelen > be->maxnamelen) be->maxnamelen = namelen ;
return 0 ;
}
}
-static inline void add_specials (before_t *be)
+static void check_identifier (char const *srcdir, char const *s)
+{
+ if (!byte_diff(s, 5, "s6rc-") && !byte_diff(s, 6, "s6-rc-"))
+ strerr_dief5x(1, "in ", srcdir, ": identifier ", s, " starts with reserved prefix") ;
+}
+
+static int add_name (before_t *be, char const *srcdir, char const *name, servicetype_t type, unsigned int *pos, unsigned int *kpos)
+{
+ check_identifier(srcdir, name) ;
+ return add_name_nocheck(be, srcdir, name, type, pos, kpos) ;
+}
+
+static unsigned int add_internal_longrun (before_t *be, char const *name)
{
+ unsigned int pos ;
longrun_t service =
{
.common =
@@ -238,14 +248,86 @@ static inline void add_specials (before_t *be)
.timeout = { 0, 0 }
},
.srcdir = 0,
- .servicedirname = keep.len,
- .logrelated = 0,
- .logtype = 0
+ .pipeline = { 0, 0 }
} ;
- add_name(be, "(s6-rc-compile internals)", S6RC_ONESHOT_RUNNER, SVTYPE_LONGRUN, &service.common.name, &service.common.kname) ;
- if (!stralloc_cats(&keep, data.s + service.common.name)
- || !stralloc_0(&keep)) dienomem() ;
+ add_name_nocheck(be, S6RC_INTERNALS, name, SVTYPE_LONGRUN, &pos, &service.common.kname) ;
if (!genalloc_append(longrun_t, &be->longruns, &service)) dienomem() ;
+ return pos ;
+}
+
+static unsigned int add_internal_oneshot (before_t *be, char const *name, char const *ups, unsigned int upn, char const *downs, unsigned int downn)
+{
+ unsigned int pos ;
+ oneshot_t service =
+ {
+ .common =
+ {
+ .ndeps = 2,
+ .depindex = genalloc_len(unsigned int, &be->indices),
+ .annotation_flags = 0,
+ .timeout = { 0, 0 }
+ },
+ .argvindex = { keep.len, keep.len + downn }
+ } ;
+ service.argc[0] = byte_count(downs, downn, '\0') ;
+ service.argc[1] = byte_count(ups, upn, '\0') ;
+ if (!genalloc_catb(unsigned int, &be->indices, be->specialdeps, 2)
+ || !stralloc_catb(&keep, downs, downn)
+ || !stralloc_catb(&keep, ups, upn)) dienomem() ;
+ add_name_nocheck(be, S6RC_INTERNALS, name, SVTYPE_ONESHOT, &pos, &service.common.kname) ;
+ if (!genalloc_append(oneshot_t, &be->oneshots, &service)) dienomem() ;
+ return pos ;
+}
+
+static void add_word (char const *word)
+{
+ if (!stralloc_cats(&satmp, word) || !stralloc_0(&satmp)) dienomem() ;
+}
+
+static unsigned int add_storepipe (before_t *be, char const *name)
+{
+ unsigned int pos, sep, base = satmp.len ;
+ unsigned int namelen = str_len(name) ;
+ char svname[16 + namelen] ;
+ byte_copy(svname, 15, "s6rc-storepipe-") ;
+ byte_copy(svname + 15, namelen + 1, name) ;
+
+ add_word(EXECLINE_EXTBINPREFIX "piperw") ;
+ add_word("0") ;
+ add_word("1") ;
+ add_word(EXECLINE_EXTBINPREFIX "if") ;
+ add_word(" " S6_EXTBINPREFIX "s6-fdholder-store") ;
+ add_word(" ../s6rc-fdholder/s") ;
+ add_word(" pipe:s6rc-r-") ; satmp.len-- ; add_word(name) ;
+ add_word("") ;
+ add_word(EXECLINE_EXTBINPREFIX "if") ;
+ add_word("-nt") ;
+ add_word(" " S6_EXTBINPREFIX "s6-fdholder-store") ;
+ add_word(" -d1") ;
+ add_word(" ./s6rc-fdholder/s") ;
+ add_word(" pipe:s6rc-w-") ; satmp.len-- ; add_word(name) ;
+ add_word("") ;
+ add_word(EXECLINE_EXTBINPREFIX "exit") ;
+ add_word("1") ;
+
+ sep = satmp.len ;
+
+ add_word(EXECLINE_EXTBINPREFIX "foreground") ;
+ add_word(" " S6_EXTBINPREFIX "s6-fdholder-delete") ;
+ add_word(" ../s6rc-fdholder/s") ;
+ add_word(" pipe:s6rc-w-") ; satmp.len-- ; add_word(name) ;
+ add_word("") ;
+ add_word(EXECLINE_EXTBINPREFIX "foreground") ;
+ add_word(" " S6_EXTBINPREFIX "s6-fdholder-delete") ;
+ add_word(" ../s6rc-fdholder/s") ;
+ add_word(" pipe:s6rc-r-") ; satmp.len-- ; add_word(name) ;
+ add_word("") ;
+ add_word(EXECLINE_EXTBINPREFIX "exit") ;
+ add_word("0") ;
+
+ pos = add_internal_oneshot(be, svname, satmp.s + base, sep - base, satmp.s + sep, satmp.len - sep) ;
+ satmp.len = base ;
+ return pos ;
}
static int uint_uniq (unsigned int const *list, unsigned int n, unsigned int pos)
@@ -348,8 +430,9 @@ static uint32 read_timeout (int dirfd, char const *srcdir, char const *name, cha
static void add_common (before_t *be, int dirfd, char const *srcdir, char const *name, common_t *common, servicetype_t svtype)
{
+ unsigned int dummy ;
common->annotation_flags = 0 ;
- add_name(be, srcdir, name, svtype, &common->name, &common->kname) ;
+ add_name(be, srcdir, name, svtype, &dummy, &common->kname) ;
if (!add_namelist(be, dirfd, srcdir, name, "dependencies", &common->depindex, &common->ndeps))
{
if (errno != ENOENT)
@@ -363,19 +446,13 @@ static void add_common (before_t *be, int dirfd, char const *srcdir, char const
static inline void add_oneshot (before_t *be, int dirfd, char const *srcdir, char const *name)
{
- static unsigned int const special_dep = 0 ;
oneshot_t service ;
if (verbosity >= 3) strerr_warni3x(name, " has type ", "oneshot") ;
add_common(be, dirfd, srcdir, name, &service.common, SVTYPE_ONESHOT) ;
read_script(be, dirfd, srcdir, name, "up", &service.argvindex[1], &service.argc[1], 1) ;
read_script(be, dirfd, srcdir, name, "down", &service.argvindex[0], &service.argc[0], 0) ;
- if (uint_uniq(genalloc_s(unsigned int, &be->indices) + service.common.depindex, service.common.ndeps, 0))
- {
- if (!genalloc_append(unsigned int, &be->indices, &special_dep)) dienomem() ;
- service.common.ndeps++ ;
- }
- else if (verbosity)
- strerr_warnw6x(srcdir, "/", name, "/dependencies", " explicitly lists ", S6RC_ONESHOT_RUNNER) ;
+ if (!genalloc_append(unsigned int, &be->indices, &be->specialdeps[0])) dienomem() ;
+ service.common.ndeps++ ;
if (verbosity >= 4)
{
unsigned int i = service.common.ndeps ;
@@ -387,16 +464,15 @@ static inline void add_oneshot (before_t *be, int dirfd, char const *srcdir, cha
strerr_warnt7x("dependency from ", name, " to ", data.s + *p, " (", fmt, ")") ;
p++ ;
}
-
}
if (!genalloc_append(oneshot_t, &be->oneshots, &service)) dienomem() ;
}
static inline void add_longrun (before_t *be, int dirfd, char const *srcdir, char const *name)
{
- longrun_t service = { .srcdir = srcdir } ;
+ longrun_t service = { .srcdir = srcdir, .pipeline = { 0, 0 }, .pipelinename = 0 } ;
+ unsigned int relatedindex, n ;
int fd ;
- unsigned int logindex, n ;
if (verbosity >= 3) strerr_warni3x(name, " has type ", "longrun") ;
add_common(be, dirfd, srcdir, name, &service.common, SVTYPE_LONGRUN) ;
fd = open_readat(dirfd, "run") ;
@@ -415,40 +491,48 @@ static inline void add_longrun (before_t *be, int dirfd, char const *srcdir, cha
strerr_dief4x(1, srcdir, "/", name, "/run is not a regular file") ;
}
close(fd) ;
- if (add_namelist(be, dirfd, srcdir, name, "logger", &logindex, &n))
+ fd = 0 ;
+ if (add_namelist(be, dirfd, srcdir, name, "producer-for", &relatedindex, &n))
{
- register unsigned int const *deps = genalloc_s(unsigned int, &be->indices) + service.common.depindex ;
- register unsigned int i = 0 ;
if (n != 1)
- strerr_dief5x(1, srcdir, "/", name, "/logger", " should only contain one service name") ;
- service.logtype = 1 ;
- service.logrelated = genalloc_s(unsigned int, &be->indices)[logindex] ;
- service.servicedirname = service.common.kname ;
- for (; i < service.common.ndeps ; i++) if (service.logrelated == deps[i]) break ;
- if (i < service.common.ndeps)
- genalloc_setlen(unsigned int, &be->indices, logindex) ;
- else service.common.ndeps++ ;
+ strerr_dief5x(1, srcdir, "/", name, "/producer-for", " should only contain one service name") ;
+ service.pipeline[1] = genalloc_s(unsigned int, &be->indices)[relatedindex] ;
+ {
+ unsigned int dummy ;
+ unsigned int namelen = str_len(data.s + service.pipeline[1]) ;
+ char svname[16 + namelen] ;
+ byte_copy(svname, 15, "s6rc-storepipe-") ;
+ byte_copy(svname + 15, namelen + 1, data.s + service.pipeline[1]) ;
+ add_name_nocheck(be, srcdir, svname, SVTYPE_UNDEFINED, &n, &dummy) ;
+ if (!genalloc_append(unsigned int, &be->indices, &n)) dienomem() ;
+ service.common.ndeps += 2 ;
+ }
if (verbosity >= 3)
- strerr_warni3x(name, " is a producer for ", data.s + service.logrelated) ;
+ strerr_warni3x(name, " is a producer for ", data.s + service.pipeline[1]) ;
+ fd = 1 ;
}
- else if (add_namelist(be, dirfd, srcdir, name, "producer", &logindex, &n))
+ if (add_namelist(be, dirfd, srcdir, name, "consumer-for", &relatedindex, &n))
{
+ unsigned int namelen = str_len(name) ;
+ char svname[16 + namelen] ;
if (n != 1)
- strerr_dief5x(1, srcdir, "/", name, "/producer", " should only contain one service name") ;
- service.logtype = 2 ;
- service.logrelated = genalloc_s(unsigned int, &be->indices)[logindex] ;
- genalloc_setlen(unsigned int, &be->indices, logindex) ;
- service.servicedirname = keep.len ;
- if (!stralloc_cats(&keep, data.s + service.logrelated)
- || !stralloc_catb(&keep, "/log", 5)) dienomem() ;
+ strerr_dief5x(1, srcdir, "/", name, "/consumer-for", " should only contain one service name") ;
+ service.pipeline[0] = genalloc_s(unsigned int, &be->indices)[relatedindex] ;
+ byte_copy(svname, 15, "s6rc-storepipe-") ;
+ byte_copy(svname + 15, namelen + 1, name) ;
if (verbosity >= 3)
- strerr_warni3x(name, " is a logger for ", data.s + service.logrelated) ;
+ strerr_warni3x(name, " is a consumer for ", data.s + service.pipeline[0]) ;
+ n = add_storepipe(be, svname) ;
+ genalloc_s(unsigned int, &be->indices)[relatedindex] = n ;
+ service.common.ndeps++ ;
+ fd = 0 ;
}
- else
+ if (fd && add_namelist(be, dirfd, srcdir, name, "pipeline-name", &relatedindex, &n))
{
- service.logtype = 0 ;
- service.servicedirname = service.common.kname ;
- if (verbosity >= 3) strerr_warni2x(name, " has no logger or producer") ;
+ if (n != 1)
+ strerr_dief5x(1, srcdir, "/", name, "/pipeline-name", " should only contain one name") ;
+ service.pipelinename = genalloc_s(unsigned int, &be->indices)[relatedindex] ;
+ genalloc_setlen(unsigned int, &be->indices, relatedindex) ;
}
if (!genalloc_append(longrun_t, &be->longruns, &service)) dienomem() ;
}
@@ -501,7 +585,8 @@ static inline void add_sources (before_t *be, char const *srcdir)
if (!d) break ;
if (d->d_name[0] == '.') continue ;
if (d->d_name[str_chr(d->d_name, '\n')])
- strerr_dief3x(2, "subdirectory of ", srcdir, " contains a newline character") ;
+ strerr_dief3x(1, "subdirectory of ", srcdir, " contains a newline character") ;
+ check_identifier(srcdir, d->d_name) ;
satmp.len = cur ;
if (!stralloc_catb(&satmp, d->d_name, str_len(d->d_name) + 1)) dienomem() ;
if (stat(satmp.s + start, &st) < 0)
@@ -517,6 +602,48 @@ static inline void add_sources (before_t *be, char const *srcdir)
satmp.len = start ;
}
+static inline void add_pipeline_bundles (before_t *be)
+{
+ longrun_t const *longruns = genalloc_s(longrun_t, &be->longruns) ;
+ unsigned int n = genalloc_len(longrun_t, &be->longruns) ;
+ unsigned int i = n ;
+ while (i--) if (longruns[i].pipelinename)
+ {
+ bundle_t bundle = { .listindex = genalloc_len(unsigned int, &be->indices), .n = 1 } ;
+ unsigned int id ;
+ nameinfo_t const *info ;
+ unsigned int j = i ;
+ if (verbosity >= 3) strerr_warni2x("creating bundle for pipeline ", data.s + longruns[i].pipelinename) ;
+ add_name(be, S6RC_INTERNALS, data.s + longruns[i].pipelinename, SVTYPE_BUNDLE, &bundle.name, &id) ;
+ avltree_search(&names_map, keep.s + longruns[i].common.kname, &id) ;
+ info = genalloc_s(nameinfo_t, &nameinfo) + id ;
+ if (!genalloc_append(unsigned int, &be->indices, &info->pos)) dienomem() ;
+
+ while (longruns[j].pipeline[1])
+ {
+ if (bundle.n >= n)
+ strerr_dief4x(1, "pipeline ", data.s + longruns[i].pipelinename, " is too long: possible loop involving ", keep.s + longruns[j].common.kname) ;
+ avltree_search(&names_map, data.s + longruns[j].pipeline[1], &id) ;
+ info = genalloc_s(nameinfo_t, &nameinfo) + id ;
+ if (info->type != SVTYPE_LONGRUN)
+ strerr_dief5x(1, "longrun service ", keep.s + longruns[j].common.kname, " declares a consumer ", data.s + longruns[j].pipeline[1], " that is not a longrun service") ;
+ if (!genalloc_append(unsigned int, &be->indices, &info->pos)) dienomem() ;
+ j = info->i ;
+ {
+ unsigned int namelen = str_len(data.s + info->pos) ;
+ char svname[16 + namelen] ;
+ byte_copy(svname, 15, "s6rc-storepipe-") ;
+ byte_copy(svname + 15, namelen + 1, data.s + info->pos) ;
+ avltree_search(&names_map, svname, &id) ;
+ info = genalloc_s(nameinfo_t, &nameinfo) + id ;
+ if (!genalloc_append(unsigned int, &be->indices, &info->pos)) dienomem() ;
+ }
+ bundle.n += 2 ;
+ }
+ if (!genalloc_append(bundle_t, &be->bundles, &bundle)) dienomem() ;
+ }
+}
+
/* Resolve all names and dependencies */
@@ -530,7 +657,7 @@ struct bundle_recinfo_s
unsigned int n ;
unsigned int nlong ;
unsigned int nbits ;
- uint32 const *indices ;
+ unsigned int const *indices ;
unsigned char *barray ;
unsigned char *mark ;
unsigned int source ;
@@ -541,7 +668,7 @@ static void resolve_bundle_rec (bundle_recinfo_t *recinfo, unsigned int i)
if (!(recinfo->mark[i] & 2))
{
bundle_t const *me = recinfo->oldb + i ;
- uint32 const *listindex = recinfo->indices + me->listindex ;
+ unsigned int const *listindex = recinfo->indices + me->listindex ;
unsigned int j = 0 ;
if (recinfo->mark[i] & 1)
strerr_dief4x(1, "cyclic bundle definition: resolution of ", data.s + recinfo->oldb[recinfo->source].name, " encountered a cycle involving ", data.s + me->name) ;
@@ -572,7 +699,7 @@ static void resolve_bundle_rec (bundle_recinfo_t *recinfo, unsigned int i)
}
}
-static inline unsigned int resolve_bundles (bundle_t const *oldb, bundle_t *newb, unsigned int nshort, unsigned int nlong, unsigned int nbundles, uint32 const *indices, unsigned char *barray)
+static inline unsigned int resolve_bundles (bundle_t const *oldb, bundle_t *newb, unsigned int nshort, unsigned int nlong, unsigned int nbundles, unsigned int const *indices, unsigned char *barray)
{
unsigned int total = 0, i = 0 ;
unsigned char mark[nbundles] ;
@@ -609,7 +736,7 @@ static inline void flatlist_bundles (bundle_t *bundles, unsigned int nbundles, u
}
}
-static void resolve_deps (common_t const *me, unsigned int nlong, unsigned int n, unsigned int nbits, uint32 const *indices, unsigned char *sarray, unsigned char const *barray)
+static void resolve_deps (common_t const *me, unsigned int nlong, unsigned int n, unsigned int nbits, unsigned int const *indices, unsigned char *sarray, unsigned char const *barray)
{
unsigned int j = 0 ;
for (; j < me->ndeps ; j++)
@@ -626,7 +753,7 @@ static void resolve_deps (common_t const *me, unsigned int nlong, unsigned int n
{
char fmt[UINT_FMT] ;
fmt[uint_fmt(fmt, nlong + p->i)] = 0 ;
- strerr_warnt7x("atomic ", data.s + me->name, " depends on oneshot ", data.s + p->pos, " (", fmt, ")") ;
+ strerr_warnt7x("atomic ", keep.s + me->kname, " depends on oneshot ", data.s + p->pos, " (", fmt, ")") ;
}
break ;
case SVTYPE_LONGRUN :
@@ -635,7 +762,7 @@ static void resolve_deps (common_t const *me, unsigned int nlong, unsigned int n
{
char fmt[UINT_FMT] ;
fmt[uint_fmt(fmt, p->i)] = 0 ;
- strerr_warnt7x("atomic ", data.s + me->name, " depends on longrun ", data.s + p->pos, " (", fmt, ")") ;
+ strerr_warnt7x("atomic ", keep.s + me->kname, " depends on longrun ", data.s + p->pos, " (", fmt, ")") ;
}
break ;
case SVTYPE_BUNDLE :
@@ -644,21 +771,21 @@ static void resolve_deps (common_t const *me, unsigned int nlong, unsigned int n
{
char fmt[UINT_FMT] ;
fmt[uint_fmt(fmt, nlong + p->i)] = 0 ;
- strerr_warnt4x("atomic ", data.s + me->name, " depends on bundle ", data.s + p->pos) ;
+ strerr_warnt4x("atomic ", keep.s + me->kname, " depends on bundle ", data.s + p->pos) ;
}
break ;
default :
- strerr_dief4x(1, "during dependency resolution for service ", data.s + me->name, ": undefined service name ", data.s + p->pos) ;
+ strerr_dief4x(1, "during dependency resolution for service ", keep.s + me->kname, ": undefined service name ", data.s + p->pos) ;
}
}
}
-static inline void check_logger (longrun_t const *longruns, unsigned int i)
+static uint32 resolve_prodcons (longrun_t const *longruns, unsigned int i, int h, uint32 nlong)
{
unsigned int j ;
register nameinfo_t const *p ;
- if (!longruns[i].logtype) return ;
- avltree_search(&names_map, data.s + longruns[i].logrelated, &j) ;
+ if (!longruns[i].pipeline[h]) return nlong ;
+ avltree_search(&names_map, data.s + longruns[i].pipeline[h], &j) ;
p = genalloc_s(nameinfo_t, &nameinfo) + j ;
switch (p->type)
{
@@ -666,21 +793,21 @@ static inline void check_logger (longrun_t const *longruns, unsigned int i)
{
unsigned int k ;
register nameinfo_t const *q ;
- if (longruns[p->i].logtype != 3 - longruns[i].logtype) goto err ;
- avltree_search(&names_map, data.s + longruns[p->i].logrelated, &k) ;
+ avltree_search(&names_map, data.s + longruns[p->i].pipeline[!h], &k) ;
q = genalloc_s(nameinfo_t, &nameinfo) + k ;
if (q->type != SVTYPE_LONGRUN) goto err ;
if (q->i != i) goto err ;
break ;
- err:
- strerr_dief7x(1, "longrun service ", data.s + longruns[i].common.name, " declares a ", longruns[i].logtype == 2 ? "producer" : "logger", " named ", data.s + p->pos, " that does not declare it back ") ;
+ err:
+ strerr_dief7x(1, "longrun service ", keep.s + longruns[i].common.kname, " declares being a ", h ? "producer" : "consumer", " for a service named ", data.s + p->pos, " that does not declare it back ") ;
}
case SVTYPE_ONESHOT :
case SVTYPE_BUNDLE :
- strerr_dief8x(1, "longrun service ", data.s + longruns[i].common.name, " declares a ", longruns[i].logtype == 2 ? "producer" : "logger", " named ", data.s + p->pos, " of type ", p->type == SVTYPE_BUNDLE ? "bundle" : "oneshot") ;
+ strerr_dief8x(1, "longrun service ", keep.s + longruns[i].common.kname, " declares being a ", h ? "producer" : "consumer", " for a service named ", data.s + p->pos, " of type ", p->type == SVTYPE_BUNDLE ? "bundle" : "oneshot") ;
default :
- strerr_dief7x(1, "longrun service ", data.s + longruns[i].common.name, " declares a ", longruns[i].logtype == 2 ? "producer" : "logger", " named ", data.s + p->pos, " that is not defined") ;
+ strerr_dief6x(1, "longrun service ", keep.s + longruns[i].common.kname, " declares being a ", h ? "producer" : "consumer", " for an undefined service: ", data.s + p->pos) ;
}
+ return p->i ;
}
static inline unsigned int ugly_bitarray_vertical_countones (unsigned char const *sarray, unsigned int n, unsigned int i)
@@ -695,7 +822,7 @@ static inline unsigned int resolve_services (s6rc_db_t *db, before_t const *be,
{
oneshot_t const *oneshots = genalloc_s(oneshot_t const, &be->oneshots) ;
longrun_t const *longruns = genalloc_s(longrun_t const, &be->longruns) ;
- uint32 const *indices = genalloc_s(uint32 const, &be->indices) ;
+ unsigned int const *indices = genalloc_s(unsigned int const, &be->indices) ;
unsigned int n = db->nshort + db->nlong ;
unsigned int nbits = bitarray_div8(n) ;
unsigned int total[2] = { 0, 0 } ;
@@ -704,14 +831,14 @@ static inline unsigned int resolve_services (s6rc_db_t *db, before_t const *be,
byte_zero(sarray, nbits * n) ;
for (; i < db->nlong ; i++)
{
+ srcdirs[i] = longruns[i].srcdir ;
db->services[i].name = longruns[i].common.kname ;
db->services[i].flags = longruns[i].common.annotation_flags ;
db->services[i].timeout[0] = longruns[i].common.timeout[0] ;
db->services[i].timeout[1] = longruns[i].common.timeout[1] ;
- db->services[i].x.longrun.servicedir = longruns[i].servicedirname ;
- srcdirs[i] = longruns[i].srcdir ;
+ db->services[i].x.longrun.pipeline[0] = resolve_prodcons(longruns, i, 0, db->nlong) ;
+ db->services[i].x.longrun.pipeline[1] = resolve_prodcons(longruns, i, 1, db->nlong) ;
resolve_deps(&longruns[i].common, db->nlong, n, nbits, indices, sarray + i * nbits, barray) ;
- check_logger(longruns, i) ;
}
for (i = 0 ; i < db->nshort ; i++)
{
@@ -742,7 +869,9 @@ static inline void flatlist_services (s6rc_db_t *db, unsigned char const *sarray
{
unsigned int n = db->nshort + db->nlong ;
unsigned int nbits = bitarray_div8(n) ;
+ diuint32 problem ;
unsigned int i = 0 ;
+ register int r ;
if (verbosity >= 3) strerr_warni1x("converting service dependency array") ;
for (; i < n ; i++)
{
@@ -755,10 +884,18 @@ static inline void flatlist_services (s6rc_db_t *db, unsigned char const *sarray
for (; k < db->services[i].ndeps[1] ; j++)
if (bitarray_peek(sarray + i * nbits, j)) mydeps[k++] = j ;
}
- if (verbosity >= 3) strerr_warni1x("checking for dependency cycles") ;
- nbits = s6rc_db_check_depcycles(db, 1, &i) ;
- if (nbits < n)
- strerr_dief4x(1, "cyclic service definition: resolution of ", db->string + db->services[nbits].name, " encountered a cycle involving ", db->string + db->services[i].name) ;
+
+ if (verbosity >= 3) strerr_warni1x("checking database correctness") ;
+ if (s6rc_db_check_depcycles(db, 1, &problem))
+ strerr_dief4x(1, "cyclic service dependency involving", db->string + db->services[problem.left].name, " and ", db->string + db->services[problem.right].name) ;
+ r = s6rc_db_check_pipelines(db, &problem) ;
+ if (r)
+ {
+ if (r == 1)
+ strerr_dief4x(1, "cyclic longrun pipeline involving", db->string + db->services[problem.left].name, " and ", db->string + db->services[problem.right].name) ;
+ else
+ strerr_dief4x(1, "longrun pipeline collision involving", db->string + db->services[problem.left].name, " and ", db->string + db->services[problem.right].name) ;
+ }
}
@@ -803,6 +940,21 @@ static void auto_file (char const *compiled, char const *file, char const *s, un
}
}
+static void auto_symlink (char const *compiled, char const *name, char const *target)
+{
+ unsigned int clen = str_len(compiled) ;
+ unsigned int flen = str_len(name) ;
+ char fn[clen + flen + 2] ;
+ byte_copy(fn, clen, compiled) ;
+ fn[clen] = '/' ;
+ byte_copy(fn + clen + 1, flen + 1, name) ;
+ if (symlink(target, fn) < 0)
+ {
+ cleanup(compiled) ;
+ strerr_diefu4sys(111, "symlink ", target, " to ", fn) ;
+ }
+}
+
static void auto_rights (char const *compiled, char const *file, mode_t mode)
{
unsigned int clen = str_len(compiled) ;
@@ -837,40 +989,120 @@ static inline void write_sizes (char const *compiled, s6rc_db_t const *db)
auto_file(compiled, "n", pack, 20) ;
}
-static inline void write_specials (char const *compiled, uint64 const *uids, unsigned int uidn, gid_t const *gids, unsigned int gidn)
+static void make_skel (char const *compiled, char const *name, uint64 const *uids, unsigned int uidn, gid_t const *gids, unsigned int gidn)
{
+ unsigned int namelen = str_len(name) ;
unsigned int i = uidn ;
- char fn[sizeof(BASE_RULES) + UINT64_FMT + 6] = BASE_RULES ;
- auto_dir(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER) ;
- auto_file(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER "/notification-fd", "3\n", 2) ;
- auto_file(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER "/run", S6RC_ONESHOT_RUNNER_RUNSCRIPT, sizeof(S6RC_ONESHOT_RUNNER_RUNSCRIPT) - 1) ;
- auto_rights(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER "/run", 0755) ;
- auto_dir(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER "/data") ;
- auto_dir(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER "/data/rules") ;
- if (gidn) auto_dir(compiled, fn) ;
- fn[sizeof(BASE_RULES) - 4] = 'u' ;
+ char fn[UINT64_FMT + namelen + 35] ;
+ byte_copy(fn, 12, "servicedirs/") ;
+ byte_copy(fn + 12, namelen + 1, name) ;
+ auto_dir(compiled, fn) ;
+ byte_copy(fn + 12 + namelen, 17, "/notification-fd") ;
+ auto_file(compiled, fn, "3\n", 2) ;
+ byte_copy(fn + 13 + namelen, 5, "data") ;
+ auto_dir(compiled, fn) ;
+ byte_copy(fn + 17 + namelen, 7, "/rules") ;
+ auto_dir(compiled, fn) ;
+ if (gidn)
+ {
+ byte_copy(fn + 23 + namelen, 5, "/gid") ;
+ auto_dir(compiled, fn) ;
+ }
+ byte_copy(fn + 23 + namelen, 5, "/uid") ;
auto_dir(compiled, fn) ;
- fn[sizeof(BASE_RULES) - 1] = '/' ;
+ fn[27 + namelen] = '/' ;
while (i--)
{
- unsigned int len = uint64_fmt(fn + sizeof(BASE_RULES), uids[i]) ;
- fn[sizeof(BASE_RULES) + len] = 0 ;
+ unsigned int len = uint64_fmt(fn + 28 + namelen, uids[i]) ;
+ fn[28 + namelen + len] = 0 ;
auto_dir(compiled, fn) ;
- byte_copy(fn + sizeof(BASE_RULES) + len, 7, "/allow") ;
+ byte_copy(fn + 28 + namelen + len, 7, "/allow") ;
auto_file(compiled, fn, "", 0) ;
}
- fn[sizeof(BASE_RULES) - 4] = 'g' ;
i = gidn ;
while (i--)
{
- unsigned int len = gid_fmt(fn + sizeof(BASE_RULES), gids[i]) ;
- fn[sizeof(BASE_RULES) + len] = 0 ;
+ unsigned int len = gid_fmt(fn + 28 + namelen, gids[i]) ;
+ fn[28 + namelen + len] = 0 ;
auto_dir(compiled, fn) ;
- byte_copy(fn + sizeof(BASE_RULES) + len, 7, "/allow") ;
+ byte_copy(fn + 28 + namelen + len, 7, "/allow") ;
auto_file(compiled, fn, "", 0) ;
}
}
+static inline void write_oneshot_runner (char const *compiled, uint64 const *uids, unsigned int uidn, gid_t const *gids, unsigned int gidn)
+{
+ make_skel(compiled, S6RC_ONESHOT_RUNNER, uids, uidn, gids, gidn) ;
+ auto_file(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER "/run", S6RC_ONESHOT_RUNNER_RUNSCRIPT, sizeof(S6RC_ONESHOT_RUNNER_RUNSCRIPT) - 1) ;
+ auto_rights(compiled, "servicedirs/" S6RC_ONESHOT_RUNNER "/run", 0755) ;
+}
+
+static inline void write_fdholder (char const *compiled, uint64 const *uids, unsigned int uidn, gid_t const *gids, unsigned int gidn, char const *fdhuser)
+{
+ unsigned int base = satmp.len ;
+ make_skel(compiled, S6RC_FDHOLDER, uids, uidn, gids, gidn) ;
+ {
+ char fn[62 + S6RC_FDHOLDER_LEN + UINT64_FMT] = "servicedirs/" S6RC_FDHOLDER "/data/rules/uid/" ;
+ char fmt[7 + UINT64_FMT] = "../uid/" ;
+ unsigned int i = uint64_fmt(fmt + 7, uids[0]) ;
+ fmt[7 + i] = 0 ;
+ byte_copy(fn + 28 + S6RC_FDHOLDER_LEN, i, fmt + 7) ;
+ byte_copy(fn + 28 + S6RC_FDHOLDER_LEN + i, 5, "/env") ;
+ auto_dir(compiled, fn) ;
+ byte_copy(fn + 32 + S6RC_FDHOLDER_LEN + i, 18, "/S6_FDHOLDER_LIST") ;
+ auto_file(compiled, fn, "\n", 1) ;
+ byte_copy(fn + 45 + S6RC_FDHOLDER_LEN + i, 12, "STORE_REGEX") ;
+ auto_file(compiled, fn, "^pipe:s6rc-\n", 12) ;
+ byte_copy(fn + 45 + S6RC_FDHOLDER_LEN + i, 15, "RETRIEVE_REGEX") ;
+ auto_symlink(compiled, fn, "S6_FDHOLDER_STORE_REGEX") ;
+ byte_copy(fn + 45 + S6RC_FDHOLDER_LEN + i, 8, "SETDUMP") ;
+ auto_file(compiled, fn, "\n", 1) ;
+ fn[45 + S6RC_FDHOLDER_LEN + i] = 'G' ;
+ auto_file(compiled, fn, "\n", 1) ;
+
+ for (i = 1 ; i < uidn ; i++)
+ {
+ unsigned int len = uint64_fmt(fn + 28 + S6RC_FDHOLDER_LEN, uids[i]) ;
+ fn[28 + S6RC_FDHOLDER_LEN + len] = 0 ;
+ auto_symlink(compiled, fn, fmt + 7) ;
+ }
+ fn[24 + S6RC_FDHOLDER_LEN] = 'g' ;
+ i = gidn ;
+ while (i--)
+ {
+ unsigned int len = gid_fmt(fn + 28 + S6RC_FDHOLDER_LEN, gids[i]) ;
+ fn[28 + S6RC_FDHOLDER_LEN + len] = 0 ;
+ auto_symlink(compiled, fn, fmt) ;
+ }
+ }
+
+ if (!stralloc_cats(&satmp,
+ "#!" EXECLINE_SHEBANGPREFIX "execlineb -P\n" \
+ EXECLINE_EXTBINPREFIX "fdmove -c 2 1\n" \
+ EXECLINE_EXTBINPREFIX "fdmove 1 3\n")) dienomem() ;
+ if (fdhuser)
+ {
+ if (!stralloc_cats(&satmp, S6_EXTBINPREFIX "s6-envuidgid -i -- ")
+ || !string_quote(&satmp, fdhuser, str_len(fdhuser))
+ || !stralloc_catb(&satmp, "\n", 1)) dienomem() ;
+ }
+ if (!stralloc_cats(&satmp, S6_EXTBINPREFIX "s6-fdholder-daemon -1 ")) dienomem() ;
+ if (fdhuser)
+ {
+ if (!stralloc_cats(&satmp, "-U ")) dienomem() ;
+ }
+ if (!stralloc_cats(&satmp, "-i data/rules -- s\n")) dienomem() ;
+ auto_file(compiled, "servicedirs/" S6RC_FDHOLDER "/run", satmp.s + base, satmp.len - base) ;
+ satmp.len = base ;
+ auto_rights(compiled, "servicedirs/" S6RC_FDHOLDER "/run", 0755) ;
+}
+
+static inline void write_specials (char const *compiled, uint64 const *uids, unsigned int uidn, gid_t const *gids, unsigned int gidn, char const *fdhuser)
+{
+ write_oneshot_runner(compiled, uids, uidn, gids, gidn) ;
+ write_fdholder(compiled, uids, uidn, gids, gidn, fdhuser) ;
+}
+
static inline void write_resolve (char const *compiled, s6rc_db_t const *db, bundle_t const *bundles, unsigned int nbundles, uint32 const *bdeps)
{
unsigned int clen = str_len(compiled) ;
@@ -975,95 +1207,138 @@ static void dircopy (char const *compiled, char const *srcfn, char const *dstfn)
}
}
-static void write_servicedir (char const *compiled, char const *srcdir, char const *src, char const *dst)
+static int read_uint (char const *file, unsigned int *fd)
{
- unsigned int clen = str_len(compiled) ;
- unsigned int srcdirlen = str_len(srcdir) ;
- unsigned int srclen = str_len(src) ;
- unsigned int dstlen = str_len(dst) ;
- struct stat st ;
- char dstfn[clen + 30 + dstlen] ;
- char srcfn[srcdirlen + srclen + 18] ;
- byte_copy(dstfn, clen, compiled) ;
- byte_copy(dstfn + clen, 13, "/servicedirs/") ;
- byte_copy(dstfn + clen + 13, dstlen + 1, dst) ;
- if (mkdir(dstfn, 0755) < 0)
+ char buf[UINT_FMT + 1] ;
+ register int r = openreadnclose(file, buf, UINT_FMT) ;
+ if (r < 0) return (errno == ENOENT) ? 0 : -1 ;
+ buf[byte_chr(buf, r, '\n')] = 0 ;
+ if (!uint0_scan(buf, fd)) return (errno = EINVAL, -1) ;
+ return 1 ;
+}
+
+static inline void write_run_wrapper (char const *compiled, char const *fn, s6rc_db_t const *db, unsigned int i, unsigned int fd)
+{
+ unsigned int base = satmp.len ;
+ if (!stralloc_cats(&satmp, "#!" EXECLINE_SHEBANGPREFIX "execlineb -P\n")) dienomem() ;
+ if (db->services[i].x.longrun.pipeline[0] < db->nlong)
{
- cleanup(compiled) ;
- strerr_diefu2sys(111, "mkdir ", dstfn) ;
+ if (!stralloc_cats(&satmp, EXECLINE_EXTBINPREFIX "s6-fdholder-retrieve ../s6rc-fdholder/s \"pipe:s6rc-r-")
+ || !string_quote_nodelim(&satmp, db->string + db->services[i].name, str_len(db->string + db->services[i].name))
+ || !stralloc_cats(&satmp, "\"\n")) dienomem() ;
}
- byte_copy(dstfn + clen + 13 + dstlen, 5, "/run") ;
- byte_copy(srcfn, srcdirlen, srcdir) ;
- srcfn[srcdirlen] = '/' ;
- byte_copy(srcfn + srcdirlen + 1, srclen, src) ;
- byte_copy(srcfn + srcdirlen + srclen + 1, 5, "/run") ;
- if (!filecopy(srcfn, dstfn, 0755))
+ if (db->services[i].x.longrun.pipeline[1] < db->nlong)
{
- cleanup(compiled) ;
- strerr_diefu4sys(111, "copy ", srcfn, " to ", dstfn) ;
+ char const *consumername = db->string + db->services[db->services[i].x.longrun.pipeline[1]].name ;
+ if (!stralloc_cats(&satmp, EXECLINE_EXTBINPREFIX "fdmove ")
+ || !stralloc_cats(&satmp, fd == 3 ? "4" : "3")
+ || !stralloc_cats(&satmp, " 0\n"
+ EXECLINE_EXTBINPREFIX "s6-fdholder-retrieve ../s6rc-fdholder/s \"pipe:s6rc-w-")
+ || !string_quote_nodelim(&satmp, consumername, str_len(consumername))
+ || !stralloc_cats(&satmp, "\"\n"
+ EXECLINE_EXTBINPREFIX "fdmove 1 0\n"
+ EXECLINE_EXTBINPREFIX "fdmove 0 ")
+ || !stralloc_cats(&satmp, fd == 3 ? "4" : "3")
+ || !stralloc_cats(&satmp, "\n")) dienomem() ;
}
- byte_copy(dstfn + clen + 14 + dstlen, 7, "finish") ;
- byte_copy(srcfn + srcdirlen + srclen + 2, 7, "finish") ;
- filecopy(srcfn, dstfn, 0755) ;
- byte_copy(dstfn + clen + 14 + dstlen, 15, "timeout-finish") ;
- byte_copy(srcfn + srcdirlen + srclen + 2, 15, "timeout-finish") ;
- filecopy(srcfn, dstfn, 0644) ;
- byte_copy(dstfn + clen + 14 + dstlen, 16, "notification-fd") ;
- byte_copy(srcfn + srcdirlen + srclen + 2, 16, "notification-fd") ;
- filecopy(srcfn, dstfn, 0644) ;
-
- byte_copy(srcfn + srcdirlen + srclen + 4, 7, "setsid") ;
- if (stat(srcfn, &st) < 0)
+ if (!stralloc_cats(&satmp, "./run.user\n")) dienomem() ;
+ auto_file(compiled, fn, satmp.s + base, satmp.len - base) ;
+ satmp.len = base ;
+ auto_rights(compiled, fn, 0755) ;
+}
+
+static inline void write_servicedirs (char const *compiled, s6rc_db_t const *db, char const *const *srcdirs)
+{
+ unsigned int clen = str_len(compiled) ;
+ unsigned int i = 2 ;
+ if (verbosity >= 3) strerr_warni3x("writing ", compiled, "/servicedirs") ;
+ for (; i < db->nlong ; i++)
{
- if (errno != ENOENT)
+ struct stat st ;
+ unsigned int srcdirlen = str_len(srcdirs[i]) ;
+ unsigned int len = str_len(db->string + db->services[i].name) ;
+ unsigned int fd = 0 ;
+ register int r ;
+ char srcfn[srcdirlen + len + 18] ;
+ char dstfn[clen + len + 30] ;
+ byte_copy(dstfn, clen, compiled) ;
+ byte_copy(dstfn + clen, 13, "/servicedirs/") ;
+ byte_copy(dstfn + clen + 13, len + 1, db->string + db->services[i].name) ;
+ if (mkdir(dstfn, 0755) < 0)
{
cleanup(compiled) ;
- strerr_diefu2sys(111, "stat ", srcfn) ;
+ strerr_diefu2sys(111, "mkdir ", dstfn) ;
}
- }
- else
- {
- int fd ;
- byte_copy(dstfn + clen + 16 + dstlen, 7, "setsid") ;
- fd = open_trunc(dstfn) ;
- if (fd < 0)
+ byte_copy(srcfn, srcdirlen, srcdirs[i]) ;
+ srcfn[srcdirlen] = '/' ;
+ byte_copy(srcfn + srcdirlen + 1, len, db->string + db->services[i].name) ;
+ byte_copy(srcfn + srcdirlen + 1 + len, 17, "/notification-fd") ;
+ r = read_uint(srcfn, &fd) ;
+ if (r < 0)
{
cleanup(compiled) ;
- strerr_diefu2sys(111, "touch ", dstfn) ;
+ strerr_diefu2sys(111, "read ", srcfn) ;
+ }
+ if (r)
+ {
+ char fmt[UINT_FMT] ;
+ unsigned int fmtlen = uint_fmt(fmt, fd) ;
+ fmt[fmtlen++] = '\n' ;
+ byte_copy(dstfn + clen + 13 + len, 17, "/notification-fd") ;
+ if (!openwritenclose_unsafe(dstfn, fmt, fmtlen))
+ {
+ cleanup(compiled) ;
+ strerr_diefu2sys(111, "write to ", dstfn) ;
+ }
}
- close(fd) ;
- }
-
- byte_copy(dstfn + clen + 14 + dstlen, 5, "data") ;
- byte_copy(srcfn + srcdirlen + srclen + 2, 5, "data") ;
- dircopy(compiled, srcfn, dstfn) ;
- byte_copy(dstfn + clen + 14 + dstlen, 4, "env") ;
- byte_copy(srcfn + srcdirlen + srclen + 2, 4, "env") ;
- dircopy(compiled, srcfn, dstfn) ;
-}
-static inline void write_servicedirs (char const *compiled, s6rc_db_t const *db, char const *const *srcdirs, unsigned int maxnamelen)
-{
- unsigned int clen = str_len(compiled) ;
- unsigned int i = 1 ;
- char fn[clen + 23 + maxnamelen] ;
- char islogger[db->nlong] ;
- if (verbosity >= 3) strerr_warni3x("writing ", compiled, "/servicedirs") ;
- byte_copy(fn, clen, compiled) ;
- byte_copy(fn + clen, 12, "/servicedirs") ;
- fn[clen+12] = '/' ;
- byte_zero(islogger, db->nlong) ;
- for (; i < db->nlong ; i++)
- {
- char const *servicedirname = db->string + db->services[i].x.longrun.servicedir ;
- islogger[i] = servicedirname[str_chr(servicedirname, '/')] ;
- if (!islogger[i])
- write_servicedir(compiled, srcdirs[i], db->string + db->services[i].name, servicedirname) ;
- }
- for (i = 1 ; i < db->nlong ; i++)
- {
- if (islogger[i])
- write_servicedir(compiled, srcdirs[i], db->string + db->services[i].name, db->string + db->services[i].x.longrun.servicedir) ;
+ byte_copy(dstfn + clen + 13 + len, 5, "/run") ;
+ if (db->services[i].x.longrun.pipeline[0] < db->nlong || db->services[i].x.longrun.pipeline[1] < db->nlong)
+ {
+ write_run_wrapper(compiled, dstfn + clen + 1, db, i, fd) ;
+ byte_copy(dstfn + clen + 17 + len, 6, ".user") ;
+ }
+ byte_copy(srcfn + srcdirlen + 1 + len, 5, "/run") ;
+ if (!filecopy(srcfn, dstfn, 0755))
+ {
+ cleanup(compiled) ;
+ strerr_diefu4sys(111, "copy ", srcfn, " to ", dstfn) ;
+ }
+ byte_copy(dstfn + clen + 14 + len, 7, "finish") ;
+ byte_copy(srcfn + srcdirlen + len + 2, 7, "finish") ;
+ filecopy(srcfn, dstfn, 0755) ;
+ byte_copy(dstfn + clen + 14 + len, 15, "timeout-finish") ;
+ byte_copy(srcfn + srcdirlen + len + 2, 15, "timeout-finish") ;
+ filecopy(srcfn, dstfn, 0644) ;
+
+ byte_copy(srcfn + srcdirlen + len + 4, 7, "setsid") ;
+ if (stat(srcfn, &st) < 0)
+ {
+ if (errno != ENOENT)
+ {
+ cleanup(compiled) ;
+ strerr_diefu2sys(111, "stat ", srcfn) ;
+ }
+ }
+ else
+ {
+ int fd ;
+ byte_copy(dstfn + clen + 16 + len, 7, "setsid") ;
+ fd = open_trunc(dstfn) ;
+ if (fd < 0)
+ {
+ cleanup(compiled) ;
+ strerr_diefu2sys(111, "touch ", dstfn) ;
+ }
+ close(fd) ;
+ }
+
+ byte_copy(dstfn + clen + 14 + len, 5, "data") ;
+ byte_copy(srcfn + srcdirlen + len + 2, 5, "data") ;
+ dircopy(compiled, srcfn, dstfn) ;
+ byte_copy(dstfn + clen + 14 + len, 4, "env") ;
+ byte_copy(srcfn + srcdirlen + len + 2, 4, "env") ;
+ dircopy(compiled, srcfn, dstfn) ;
}
}
@@ -1081,8 +1356,9 @@ static inline int write_service (buffer *b, s6rc_service_t const *sv, int type)
uint32_pack_big(pack + 28, sv->deps[1]) ;
if (type)
{
- uint32_pack_big(pack + 32, sv->x.longrun.servicedir) ;
- m = 36 ;
+ uint32_pack_big(pack + 32, sv->x.longrun.pipeline[0]) ;
+ uint32_pack_big(pack + 36, sv->x.longrun.pipeline[1]) ;
+ m = 40 ;
}
else
{
@@ -1154,21 +1430,23 @@ static inline void write_db (char const *compiled, s6rc_db_t const *db)
strerr_diefu2sys(111, "write to ", dbfn) ;
}
-static inline void write_compiled (char const *compiled, s6rc_db_t const *db, char const *const *srcdirs, bundle_t const *bundles, unsigned int nbundles, uint32 const *bdeps, unsigned int maxnamelen, uint64 const *uids, unsigned int uidn, gid_t const *gids, unsigned int gidn)
+static inline void write_compiled (char const *compiled, s6rc_db_t const *db, char const *const *srcdirs, bundle_t const *bundles, unsigned int nbundles, uint32 const *bdeps, uint64 const *uids, unsigned int uidn, gid_t const *gids, unsigned int gidn, char const *fdhuser)
{
if (verbosity >= 2) strerr_warni2x("writing compiled information to ", compiled) ;
init_compiled(compiled) ;
write_sizes(compiled, db) ;
write_resolve(compiled, db, bundles, nbundles, bdeps) ;
+ stralloc_free(&data) ;
write_db(compiled, db) ;
- write_specials(compiled, uids, uidn, gids, gidn) ;
- write_servicedirs(compiled, db, srcdirs, maxnamelen) ;
+ write_specials(compiled, uids, uidn, gids, gidn, fdhuser) ;
+ write_servicedirs(compiled, db, srcdirs) ;
}
int main (int argc, char const *const *argv)
{
before_t before = BEFORE_ZERO ;
char const *compiled ;
+ char const *fdhuser = 0 ;
unsigned int uidn = 0, gidn = 0 ;
uint64 uids[256] ;
gid_t gids[256] ;
@@ -1177,13 +1455,14 @@ int main (int argc, char const *const *argv)
subgetopt_t l = SUBGETOPT_ZERO ;
for (;;)
{
- register int opt = subgetopt_r(argc, argv, "v:u:g:", &l) ;
+ register int opt = subgetopt_r(argc, argv, "v:u:g:h:", &l) ;
if (opt == -1) break ;
switch (opt)
{
case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ;
case 'u' : if (!uint64_scanlist(uids, 255, l.arg, &uidn)) dieusage() ; break ;
case 'g' : if (!gid_scanlist(gids, 255, l.arg, &gidn)) dieusage() ; break ;
+ case 'h' : fdhuser = l.arg ; break ;
default : dieusage() ;
}
}
@@ -1192,14 +1471,15 @@ int main (int argc, char const *const *argv)
if (argc < 2) dieusage() ;
if (!uidn && !gidn) uids[uidn++] = 0 ;
compiled = *argv++ ;
- add_specials(&before) ;
+ before.specialdeps[0] = add_internal_longrun(&before, S6RC_ONESHOT_RUNNER) ;
+ before.specialdeps[1] = add_internal_longrun(&before, S6RC_FDHOLDER) ;
for (; *argv ; argv++) add_sources(&before, *argv) ;
+ add_pipeline_bundles(&before) ;
{
unsigned int n = genalloc_len(oneshot_t, &before.oneshots) + genalloc_len(longrun_t, &before.longruns) ;
unsigned int nbits = bitarray_div8(n) ;
unsigned int nbundles = genalloc_len(bundle_t, &before.bundles) ;
- unsigned int maxnamelen = before.maxnamelen ;
s6rc_service_t servicesblob[n] ;
s6rc_db_t db =
{
@@ -1214,13 +1494,13 @@ int main (int argc, char const *const *argv)
unsigned char sarray[nbits * n] ;
bundle_t bundles[nbundles] ;
unsigned char barray[nbits * nbundles] ;
- unsigned int nbdeps = resolve_bundles(genalloc_s(bundle_t, &before.bundles), bundles, db.nshort, db.nlong, nbundles, genalloc_s(uint32, &before.indices), barray) ;
+ unsigned int nbdeps = resolve_bundles(genalloc_s(bundle_t, &before.bundles), bundles, db.nshort, db.nlong, nbundles, genalloc_s(unsigned int, &before.indices), barray) ;
uint32 bdeps[nbdeps] ;
genalloc_free(bundle_t, &before.bundles) ;
flatlist_bundles(bundles, nbundles, nbits, barray, bdeps) ;
db.ndeps = resolve_services(&db, &before, srcdirs, sarray, barray) ;
- genalloc_free(uint32, &before.indices) ;
+ genalloc_free(unsigned int, &before.indices) ;
genalloc_free(oneshot_t, &before.oneshots) ;
genalloc_free(longrun_t, &before.longruns) ;
genalloc_free(nameinfo_t, &nameinfo) ;
@@ -1229,7 +1509,7 @@ int main (int argc, char const *const *argv)
uint32 deps[db.ndeps << 1] ;
db.deps = deps ;
flatlist_services(&db, sarray) ;
- write_compiled(compiled, &db, srcdirs, bundles, nbundles, bdeps, maxnamelen, uids, uidn, gids, gidn) ;
+ write_compiled(compiled, &db, srcdirs, bundles, nbundles, bdeps, uids, uidn, gids, gidn, fdhuser) ;
}
}
diff --git a/src/s6-rc/s6-rc-db.c b/src/s6-rc/s6-rc-db.c
index aeaff76..8621b6c 100644
--- a/src/s6-rc/s6-rc-db.c
+++ b/src/s6-rc/s6-rc-db.c
@@ -180,16 +180,6 @@ static void print_timeout (char const *name, int h)
strerr_diefu1sys(111, "write to stdout") ;
}
-static void print_servicedir (char const *name)
-{
- unsigned int n = resolve_service(name) ;
- if (n >= db->nlong)
- strerr_dief5x(5, "in database ", compiled, ": identifier ", name, " does not represent a longrun service") ;
- if (buffer_puts(buffer_1, db->string + db->services[n].x.longrun.servicedir) < 0
- || buffer_putflush(buffer_1, "\n", 1) < 0)
- strerr_diefu1sys(111, "write to stdout") ;
-}
-
static void print_script (char const *name, int h)
{
unsigned int argc ;
@@ -209,6 +199,30 @@ static void print_script (char const *name, int h)
strerr_diefu1sys(111, "write to stdout") ;
}
+static inline void print_pipeline (char const *name)
+{
+ unsigned int n = resolve_service(name) ;
+ if (n >= db->nlong)
+ strerr_dief5x(5, "in database ", compiled, ": identifier ", name, " does not represent a longrun") ;
+ for (;;)
+ {
+ register unsigned int j = db->services[n].x.longrun.pipeline[0] ;
+ if (j >= db->nlong) break ;
+ n = j ;
+ }
+ for (;;)
+ {
+ register unsigned int j = db->services[n].x.longrun.pipeline[1] ;
+ if (buffer_puts(buffer_1, db->string + db->services[n].name) < 0
+ || buffer_put(buffer_1, "\n", 1) < 0)
+ strerr_diefu1sys(111, "write to stdout") ;
+ if (j >= db->nlong) break ;
+ n = j ;
+ }
+ if (buffer_flush(buffer_1))
+ strerr_diefu1sys(111, "write to stdout") ;
+}
+
static inline void print_flags (char const *name)
{
unsigned int n = resolve_service(name) ;
@@ -278,7 +292,7 @@ static inline void print_help (void)
"s6-rc-db [ -u | -d ] timeout atomicname\n"
"s6-rc-db contents bundlename\n"
"s6-rc-db [ -u | -d ] dependencies servicename...\n"
-"s6-rc-db servicedir longrunname\n"
+"s6-rc-db pipeline longrunname\n"
"s6-rc-db [ -u | -d ] script oneshotname\n"
"s6-rc-db flags atomicname\n"
"s6-rc-db atomics servicename...\n"
@@ -305,7 +319,7 @@ static inline unsigned int parse_command (char const *command)
"timeout",
"contents",
"dependencies",
- "servicedir",
+ "pipeline",
"script",
"flags",
"atomics",
@@ -421,11 +435,19 @@ int main (int argc, char const *const *argv)
{
case 1 : /* check */
{
- unsigned int problem, w ;
- if (!s6rc_db_check_revdeps(&dbblob))
+ diuint32 problem ;
+ if (s6rc_db_check_revdeps(&dbblob))
strerr_dief3x(4, "invalid service database in ", compiled, ": direct and reverse dependencies are mismatched") ;
- w = s6rc_db_check_depcycles(&dbblob, 1, &problem) ;
- if (w < n) strerr_dief6x(4, "invalid service database in ", compiled, ": service ", stringblob + serviceblob[w].name, " has a dependency cycle involving ", stringblob + serviceblob[problem].name) ;
+ if (s6rc_db_check_depcycles(&dbblob, 1, &problem))
+ strerr_dief8x(4, "invalid service database in ", compiled, ": dependency ", "cycle", " involving ", stringblob + serviceblob[problem.left].name, " and ", stringblob + serviceblob[problem.right].name) ;
+ r = s6rc_db_check_pipelines(&dbblob, &problem) ;
+ if (r)
+ {
+ if (r == 1)
+ strerr_dief8x(4, "invalid service database in ", compiled, ": pipeline ", "cycle", " involving ", stringblob + serviceblob[problem.left].name, " and ", stringblob + serviceblob[problem.right].name) ;
+ else
+ strerr_dief8x(4, "invalid service database in ", compiled, ": pipeline ", "collision", " involving ", stringblob + serviceblob[problem.left].name, " and ", stringblob + serviceblob[problem.right].name) ;
+ }
break ;
}
case 2 : /* list */
@@ -450,8 +472,8 @@ int main (int argc, char const *const *argv)
case 6 : /* dependencies */
print_union(argv + 1, up, 1, 0) ;
break ;
- case 7 : /* servicedir */
- print_servicedir(argv[1]) ;
+ case 7 : /* pipeline */
+ print_pipeline(argv[1]) ;
break ;
case 8 : /* script */
print_script(argv[1], up) ;
diff --git a/src/s6-rc/s6-rc-update.c b/src/s6-rc/s6-rc-update.c
index 42a84e8..08f719f 100644
--- a/src/s6-rc/s6-rc-update.c
+++ b/src/s6-rc/s6-rc-update.c
@@ -8,8 +8,10 @@
#include <skalibs/uint32.h>
#include <skalibs/uint.h>
#include <skalibs/bytestr.h>
-#include <skalibs/sgetopt.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/buffer.h>
#include <skalibs/strerr2.h>
+#include <skalibs/sgetopt.h>
#include <skalibs/bitarray.h>
#include <skalibs/cdb.h>
#include <skalibs/stralloc.h>
@@ -21,7 +23,7 @@
#include <s6-rc/config.h>
#include <s6-rc/s6rc.h>
-#define USAGE "s6-rc-update [ -n ] [ -v verbosity ] [ -t timeout ] [ -l live ] newdb"
+#define USAGE "s6-rc-update [ -n ] [ -v verbosity ] [ -t timeout ] [ -l live ] [ -f conversion_file ] newdb"
#define dieusage() strerr_dieusage(100, USAGE)
#define dienomem() strerr_diefu1sys(111, "build string") ;
@@ -29,6 +31,11 @@ static char const *live = S6RC_LIVE_BASE ;
static unsigned int livelen = sizeof(S6RC_LIVE_BASE) - 1 ;
static unsigned int verbosity = 1 ;
+
+
+ /* Conversions and transitions */
+
+
static inline void parse_line (stralloc *sa, char const *s, unsigned int slen, unsigned int *newnames, unsigned char *oldstate, cdb_t *oldc, s6rc_db_t const *olddb)
{
unsigned int base = sa->len ;
@@ -60,6 +67,9 @@ static inline void parse_line (stralloc *sa, char const *s, unsigned int slen, u
strerr_diefu3sys(111, "read ", live, "/compiled/resolve.cdb") ;
uint32_unpack_big(pack, &x) ;
if (x >= oldn) strerr_dief3x(4, "invalid database in ", live, "/compiled") ;
+ if (oldstate[x] & 64)
+ strerr_dief3x(6, "service ", olddb->string + olddb->services[x].name, " appears more than once in conversion file") ;
+ oldstate[x] |= 64 ;
cur = base + slen + str_len(sa->s + base + slen) + 1 ;
if (n >= 2 && !str_diff(sa->s + cur, "->"))
{
@@ -80,18 +90,17 @@ static inline void parse_line (stralloc *sa, char const *s, unsigned int slen, u
}
}
-static inline void parse_conversion_file (stralloc *sa, unsigned int *newnames, unsigned char *oldstate, int fdoldc, s6rc_db_t const *olddb)
+static inline void parse_conversion_file (char const *convfile, stralloc *sa, unsigned int *newnames, unsigned char *oldstate, cdb_t *oldc, s6rc_db_t const *olddb)
{
+ int fd = open_readb(convfile) ;
+ char buf[4096] ;
+ buffer b = BUFFER_INIT(&fd_readsv, fd, buf, 4096) ;
unsigned int base = satmp.len ;
- cdb_t oldc = CDB_ZERO ;
- int oldfdres = open_readatb(fdoldc, "resolve.cdb") ;
- if (oldfdres < 0) strerr_diefu3sys(111, "open ", live, "/compiled/resolve.cdb") ;
- if (!cdb_init_map(&oldc, oldfdres, 1))
- strerr_diefu3sys(111, "cdb_init ", live, "/compiled/resolve.cdb") ;
+ if (fd < 0) strerr_diefu2sys(111, "open ", convfile) ;
for (;;)
{
- register int r = skagetln(buffer_0, &satmp, '\n') ;
+ register int r = skagetln(&b, &satmp, '\n') ;
if (!r) break ;
if (r < 0)
{
@@ -99,45 +108,53 @@ static inline void parse_conversion_file (stralloc *sa, unsigned int *newnames,
if (!stralloc_0(&satmp)) dienomem() ;
}
else satmp.s[satmp.len - 1] = 0 ;
- parse_line(sa, satmp.s + base, satmp.len - base, newnames, oldstate, &oldc, olddb) ;
+ parse_line(sa, satmp.s + base, satmp.len - base, newnames, oldstate, oldc, olddb) ;
satmp.len = base ;
}
satmp.len = base ;
+ close(fd) ;
+}
+
+static inline void stuff_with_oldc (unsigned char *oldstate, int fdoldc, s6rc_db_t const *olddb, char const *convfile, unsigned int *nameindex, stralloc *namedata)
+{
+ cdb_t oldc = CDB_ZERO ;
+ int oldfdres = open_readatb(fdoldc, "resolve.cdb") ;
+ if (oldfdres < 0) strerr_diefu3sys(111, "open ", live, "/compiled/resolve.cdb") ;
+ if (!cdb_init_map(&oldc, oldfdres, 1))
+ strerr_diefu3sys(111, "cdb_init ", live, "/compiled/resolve.cdb") ;
+
+ parse_conversion_file(convfile, namedata, nameindex, oldstate, &oldc, olddb) ;
+
cdb_free(&oldc) ;
close(oldfdres) ;
}
-static inline void fill_convtable_and_flags (unsigned char *conversion_table, unsigned char *oldstate, unsigned char *newstate, char const *namedata, unsigned int const *nameindex, int fdnewc, char const *newfn, s6rc_db_t const *olddb, s6rc_db_t const *newdb)
+static inline void fill_convtable_and_flags (unsigned char *conversion_table, unsigned char *oldstate, unsigned char *newstate, char const *namedata, unsigned int const *nameindex, cdb_t *newc, char const *newfn, s6rc_db_t const *olddb, s6rc_db_t const *newdb)
{
unsigned int newn = newdb->nshort + newdb->nlong ;
- cdb_t newc = CDB_ZERO ;
- int newfdres = open_readatb(fdnewc, "resolve.cdb") ;
unsigned int i = olddb->nshort + olddb->nlong ;
- if (newfdres < 0) strerr_diefu3sys(111, "open ", newfn, "/resolve.cdb") ;
- if (!cdb_init_map(&newc, newfdres, 1))
- strerr_diefu3sys(111, "cdb_init ", newfn, "/resolve.cdb") ;
while (i--)
{
char const *newname = oldstate[i] & 16 ? namedata + nameindex[i] : olddb->string + olddb->services[i].name ;
unsigned int len ;
- int r = cdb_find(&newc, newname, str_len(newname)) ;
+ int r = cdb_find(newc, newname, str_len(newname)) ;
if (r < 0) strerr_diefu3sys(111, "read ", newfn, "/resolve.cdb") ;
if (!r)
{
oldstate[i] |= 2 ; /* disappeared -> want down */
continue ;
}
- if (cdb_datalen(&newc) & 3)
+ if (cdb_datalen(newc) & 3)
strerr_dief3x(4, "invalid resolve database in ", newfn, "/resolve.cdb") ;
- len = cdb_datalen(&newc) >> 2 ;
+ len = cdb_datalen(newc) >> 2 ;
if (len > newn)
strerr_dief3x(4, "invalid resolve database in ", newfn, "/resolve.cdb") ;
{
- char pack[cdb_datalen(&newc) + 1] ;
+ char pack[cdb_datalen(newc) + 1] ;
char const *p = pack ;
- if (cdb_read(&newc, pack, cdb_datalen(&newc), cdb_datapos(&newc)) < 0)
+ if (cdb_read(newc, pack, cdb_datalen(newc), cdb_datapos(newc)) < 0)
strerr_diefu3sys(111, "read ", newfn, "/resolve.cdb") ;
if (len == 1) oldstate[i] |= 8 ; /* atomic or singleton bundle */
while (len--)
@@ -154,6 +171,18 @@ static inline void fill_convtable_and_flags (unsigned char *conversion_table, un
}
}
+}
+
+static inline void stuff_with_newc (int fdnewc, char const *newfn, unsigned char *conversion_table, unsigned char *oldstate, unsigned char *newstate, char const *namedata, unsigned int const *nameindex, s6rc_db_t const *olddb, s6rc_db_t const *newdb)
+{
+ cdb_t newc = CDB_ZERO ;
+ int newfdres = open_readatb(fdnewc, "resolve.cdb") ;
+ if (newfdres < 0) strerr_diefu3sys(111, "open ", newfn, "/compiled/resolve.cdb") ;
+ if (!cdb_init_map(&newc, newfdres, 1))
+ strerr_diefu3sys(111, "cdb_init ", newfn, "/compiled/resolve.cdb") ;
+
+ fill_convtable_and_flags(conversion_table, oldstate, newstate, namedata, nameindex, &newc, newfn, olddb, newdb) ;
+
cdb_free(&newc) ;
close(newfdres) ;
}
@@ -183,17 +212,20 @@ static inline void adjust_newalreadyup (unsigned char const *oldstate, unsigned
}
}
-static void compute_transitions (unsigned char *oldstate, int fdoldc, s6rc_db_t const *olddb, unsigned char *newstate, int fdnewc, char const *newfn, s6rc_db_t const *newdb)
+static void compute_transitions (char const *convfile, unsigned char *oldstate, int fdoldc, s6rc_db_t const *olddb, unsigned char *newstate, int fdnewc, char const *newfn, s6rc_db_t const *newdb)
{
unsigned int oldn = olddb->nshort + olddb->nlong ;
unsigned int newn = newdb->nshort + newdb->nlong ;
unsigned char conversion_table[oldn * bitarray_div8(newn)] ;
+ unsigned int oldpairings[olddb->nlong] ;
+ unsigned int newpairings[newdb->nlong] ;
byte_zero(conversion_table, oldn * bitarray_div8(newn)) ;
{
stralloc namedata = STRALLOC_ZERO ;
unsigned int nameindex[oldn] ;
- parse_conversion_file(&namedata, nameindex, oldstate, fdoldc, olddb) ;
- fill_convtable_and_flags(conversion_table, oldstate, newstate, namedata.s, nameindex, fdnewc, newfn, olddb, newdb) ;
+
+ stuff_with_oldc(oldstate, fdoldc, olddb, convfile, nameindex, &namedata) ;
+ stuff_with_newc(fdnewc, newfn, conversion_table, oldstate, newstate, namedata.s, nameindex, olddb, newdb) ;
stralloc_free(&namedata) ;
}
adjust_newwantup(oldstate, oldn, newstate, newn, conversion_table) ;
@@ -201,6 +233,11 @@ static void compute_transitions (unsigned char *oldstate, int fdoldc, s6rc_db_t
adjust_newalreadyup(oldstate, oldn, newstate, newn, conversion_table) ;
}
+
+
+ /* Service directory replacement */
+
+
static int safe_servicedir_update (char const *dst, char const *src, int h)
{
unsigned int dstlen = str_len(dst) ;
@@ -252,8 +289,9 @@ static int safe_servicedir_update (char const *dst, char const *src, int h)
byte_copy(dstfn + dstlen + 1, 4, "run") ;
if (!hiercopy(srcfn, dstfn)) goto err ;
byte_copy(srcfn + srclen + 1, 4, "run") ;
- byte_copy(dstfn + dstlen + 1, 4, "finish") ;
- hiercopy(srcfn, dstfn) ;
+ byte_copy(dstfn + dstlen + 1, 7, "finish") ;
+ byte_copy(tmpfn + dstlen + 1, 11, "finish.new") ;
+ if (hiercopy(srcfn, tmpfn) && rename(tmpfn, dstfn) < 0) goto err ;
if (h)
{
byte_copy(dstfn + dstlen + 1, 5, "down") ;
@@ -302,6 +340,11 @@ static inline void update_servicedirs (unsigned char const *oldstate, unsigned i
{
}
+
+
+ /* The update itself. */
+
+
static inline void update_state_and_compiled (unsigned char const *newstate, unsigned int newn, char const *newcompiled)
{
char fn[livelen + 14] ;
@@ -346,6 +389,7 @@ static void fill_tfmt (char *tfmt, tain_t const *deadline)
int main (int argc, char const *const *argv, char const *const *envp)
{
+ char const *convfile = "/dev/null" ;
tain_t deadline ;
int dryrun = 0 ;
PROG = "s6-rc-update" ;
@@ -355,7 +399,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
subgetopt_t l = SUBGETOPT_ZERO ;
for (;;)
{
- register int opt = subgetopt_r(argc, argv, "v:t:nl:", &l) ;
+ register int opt = subgetopt_r(argc, argv, "v:t:nl:f:", &l) ;
if (opt == -1) break ;
switch (opt)
{
@@ -363,6 +407,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
case 'n' : dryrun = 1 ; break ;
case 'l' : live = l.arg ; livelen = str_len(live) ; break ;
+ case 'f' : convfile = l.arg ; break ;
default : dieusage() ;
}
}
@@ -464,7 +509,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
/* Read the conversion file and compute what to do */
if (verbosity >= 2) strerr_warni1x("computing state adjustments") ;
- compute_transitions(oldstate, fdoldc, &olddb, newstate, fdnewc, argv[0], &newdb) ;
+ compute_transitions(convfile, oldstate, fdoldc, &olddb, newstate, fdnewc, argv[0], &newdb) ;
tain_now_g() ;
if (!tain_future(&deadline)) strerr_dief1x(1, "timed out") ;
diff --git a/src/s6-rc/s6-rc.c b/src/s6-rc/s6-rc.c
index 2cb4caa..db30690 100644
--- a/src/s6-rc/s6-rc.c
+++ b/src/s6-rc/s6-rc.c
@@ -121,7 +121,7 @@ static pid_t start_oneshot (unsigned int i, int h)
static pid_t start_longrun (unsigned int i, int h)
{
- unsigned int svdlen = str_len(db->string + db->services[i].x.longrun.servicedir) ;
+ unsigned int svdlen = str_len(db->string + db->services[i].name) ;
unsigned int m = 0 ;
char fmt[UINT32_FMT] ;
char vfmt[UINT_FMT] ;
@@ -129,7 +129,7 @@ static pid_t start_longrun (unsigned int i, int h)
char const *newargv[7 + !!dryrun[0] * 6] ;
byte_copy(servicefn, livelen, live) ;
byte_copy(servicefn + livelen, 9, "/scandir/") ;
- byte_copy(servicefn + livelen + 9, svdlen, db->string + db->services[i].x.longrun.servicedir) ;
+ byte_copy(servicefn + livelen + 9, svdlen, db->string + db->services[i].name) ;
if (h)
{
byte_copy(servicefn + livelen + 9 + svdlen, 17, "/notification-fd") ;
@@ -166,11 +166,11 @@ static void success_longrun (unsigned int i, int h)
{
if (!dryrun[0])
{
- unsigned int svdlen = str_len(db->string + db->services[i].x.longrun.servicedir) ;
+ unsigned int svdlen = str_len(db->string + db->services[i].name) ;
char fn[livelen + svdlen + 15] ;
byte_copy(fn, livelen, live) ;
byte_copy(fn + livelen, 9, "/scandir/") ;
- byte_copy(fn + livelen + 9, svdlen, db->string + db->services[i].x.longrun.servicedir) ;
+ byte_copy(fn + livelen + 9, svdlen, db->string + db->services[i].name) ;
byte_copy(fn + livelen + 9 + svdlen, 6, "/down") ;
if (h)
{
diff --git a/tools/gen-deps.sh b/tools/gen-deps.sh
index 4615f28..f8cf5ee 100755
--- a/tools/gen-deps.sh
+++ b/tools/gen-deps.sh
@@ -57,11 +57,17 @@ echo
for dir in $(ls -1 src | grep -v ^include) ; do
for file in $(ls -1 src/$dir/deps-lib) ; do
deps=
+ libs=
while read dep ; do
- deps="$deps src/$dir/$dep"
+ if echo $dep | grep -q -e ^-l -e '^\${.*_LIB}' ; then
+ libs="$libs $dep"
+ else
+ deps="$deps src/$dir/$dep"
+ fi
done < src/$dir/deps-lib/$file
- echo "lib$file.a:$deps"
- echo "lib${file}.so:$(echo "$deps" | sed 's/\.o/.lo/g')"
+ echo "lib${file}.a.xyzzy:$deps"
+ echo "lib${file}.so.xyzzy: private EXTRA_LIBS :=$libs"
+ echo "lib${file}.so.xyzzy:$(echo "$deps" | sed 's/\.o/.lo/g')"
done
for file in $(ls -1 src/$dir/deps-exe) ; do
@@ -71,7 +77,7 @@ for dir in $(ls -1 src | grep -v ^include) ; do
if echo $dep | grep -q -- \\.o$ ; then
dep="src/$dir/$dep"
fi
- if echo $dep | grep -q '^\${.*_LIB}' ; then
+ if echo $dep | grep -q -- '^\${.*_LIB}' ; then
libs="$libs $dep"
else
deps="$deps $dep"