diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2015-08-12 20:00:17 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2015-08-12 20:00:17 +0000 |
commit | 9473830ad612dcb674f6048a9a17e372ff9d9ec3 (patch) | |
tree | 6cf045657b34be4b6fd685c68993b13bf7e55f26 | |
parent | abfd58b78188c3408599b98fcce611349bfa8b9c (diff) | |
download | s6-rc-9473830ad612dcb674f6048a9a17e372ff9d9ec3.tar.xz |
Intermediary commit; working on source dir format change. Should work, but untested as for now.
57 files changed, 809 insertions, 407 deletions
@@ -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: @@ -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 @@ -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 <em>fdhuser</em></tt> : 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" |