From 9473830ad612dcb674f6048a9a17e372ff9d9ec3 Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Wed, 12 Aug 2015 20:00:17 +0000 Subject: Intermediary commit; working on source dir format change. Should work, but untested as for now. --- INSTALL | 6 +- Makefile | 45 +- configure | 26 +- doc/index.html | 11 +- doc/s6-rc-compile.html | 118 +++-- doc/s6-rc-db.html | 50 +- doc/s6-rc.html | 12 + examples/source/00/down | 1 - examples/source/devd-log/producer | 1 - examples/source/devd/logger | 1 - examples/source/dns-cache-log/producer | 1 - examples/source/dns-cache/logger | 1 - examples/source/dns-server-tcp-4-log/producer | 1 - examples/source/dns-server-tcp-4/logger | 1 - examples/source/dns-server-udp-log/producer | 1 - examples/source/dns-server-udp/logger | 1 - examples/source/fdholder-log/producer | 1 - examples/source/fdholder/logger | 1 - examples/source/hostapd-log/producer | 1 - examples/source/hostapd/logger | 1 - examples/source/httpd-4-log/producer | 1 - examples/source/httpd-4/logger | 1 - examples/source/identd-4-log/producer | 1 - examples/source/identd-4/logger | 1 - examples/source/klogd-log/producer | 1 - examples/source/klogd-srv/logger | 1 - examples/source/ntpclient-log/producer | 1 - examples/source/ntpclient/logger | 1 - examples/source/qmail-log/producer | 1 - examples/source/qmail/logger | 1 - examples/source/qmtpd-4-log/producer | 1 - examples/source/qmtpd-4/logger | 1 - examples/source/smtpd-4-log/producer | 1 - examples/source/smtpd-4/logger | 1 - examples/source/sshd-4-log/producer | 1 - examples/source/sshd-4/logger | 1 - examples/source/syslogd-log/producer | 1 - examples/source/syslogd-srv/logger | 1 - examples/source/taiclockd-4-log/producer | 1 - examples/source/taiclockd-4/logger | 1 - examples/source/udhcpc-eth3-log/producer | 1 - examples/source/udhcpc-eth3/logger | 1 - examples/source/udhcpd-wlan0-log/producer | 1 - examples/source/udhcpd-wlan0/logger | 1 - package/deps.mak | 6 +- package/targets.mak | 15 +- src/include/s6-rc/s6rc-constants.h | 3 + src/include/s6-rc/s6rc-db.h | 6 +- src/libs6rc/deps-lib/s6rc | 4 +- src/libs6rc/s6rc_db_check_depcycles.c | 26 +- src/libs6rc/s6rc_db_check_revdeps.c | 5 +- src/libs6rc/s6rc_db_read.c | 5 +- src/s6-rc/s6-rc-compile.c | 660 ++++++++++++++++++-------- src/s6-rc/s6-rc-db.c | 58 ++- src/s6-rc/s6-rc-update.c | 101 ++-- src/s6-rc/s6-rc.c | 8 +- tools/gen-deps.sh | 14 +- 57 files changed, 809 insertions(+), 407 deletions(-) delete mode 100644 examples/source/00/down delete mode 100644 examples/source/devd-log/producer delete mode 100644 examples/source/devd/logger delete mode 100644 examples/source/dns-cache-log/producer delete mode 100644 examples/source/dns-cache/logger delete mode 100644 examples/source/dns-server-tcp-4-log/producer delete mode 100644 examples/source/dns-server-tcp-4/logger delete mode 100644 examples/source/dns-server-udp-log/producer delete mode 100644 examples/source/dns-server-udp/logger delete mode 100644 examples/source/fdholder-log/producer delete mode 100644 examples/source/fdholder/logger delete mode 100644 examples/source/hostapd-log/producer delete mode 100644 examples/source/hostapd/logger delete mode 100644 examples/source/httpd-4-log/producer delete mode 100644 examples/source/httpd-4/logger delete mode 100644 examples/source/identd-4-log/producer delete mode 100644 examples/source/identd-4/logger delete mode 100644 examples/source/klogd-log/producer delete mode 100644 examples/source/klogd-srv/logger delete mode 100644 examples/source/ntpclient-log/producer delete mode 100644 examples/source/ntpclient/logger delete mode 100644 examples/source/qmail-log/producer delete mode 100644 examples/source/qmail/logger delete mode 100644 examples/source/qmtpd-4-log/producer delete mode 100644 examples/source/qmtpd-4/logger delete mode 100644 examples/source/smtpd-4-log/producer delete mode 100644 examples/source/smtpd-4/logger delete mode 100644 examples/source/sshd-4-log/producer delete mode 100644 examples/source/sshd-4/logger delete mode 100644 examples/source/syslogd-log/producer delete mode 100644 examples/source/syslogd-srv/logger delete mode 100644 examples/source/taiclockd-4-log/producer delete mode 100644 examples/source/taiclockd-4/logger delete mode 100644 examples/source/udhcpc-eth3-log/producer delete mode 100644 examples/source/udhcpc-eth3/logger delete mode 100644 examples/source/udhcpd-wlan0-log/producer delete mode 100644 examples/source/udhcpd-wlan0/logger diff --git a/INSTALL b/INSTALL index 3145866..b2c9d03 100644 --- a/INSTALL +++ b/INSTALL @@ -6,9 +6,9 @@ Build Instructions - A POSIX-compliant C development environment - GNU make version 4.0 or later - - skalibs version 2.3.6.0 or later: http://skarnet.org/software/skalibs/ - - execline version 2.1.3.0 or later: http://skarnet.org/software/execline/ - - s6 version 2.2.0.0 or later: http://skarnet.org/software/s6/ + - skalibs version 2.3.6.1 or later: http://skarnet.org/software/skalibs/ + - execline version 2.1.3.1 or later: http://skarnet.org/software/execline/ + - s6 version 2.2.0.1 or later: http://skarnet.org/software/s6/ This software will run on any operating system that implements POSIX.1-2008, available at: diff --git a/Makefile b/Makefile index 7ff52e7..6eba87f 100644 --- a/Makefile +++ b/Makefile @@ -18,9 +18,23 @@ STATIC_LIBS := SHARED_LIBS := INTERNAL_LIBS := EXTRA_TARGETS := +LIB_DEFS := + +define library_definition = +LIB$(firstword $(subst =, ,$(1))) := lib$(lastword $(subst =, ,$(1))).$(if $(DO_ALLSTATIC),a,so).xyzzy +ifdef DO_SHARED +SHARED_LIBS += lib$(lastword $(subst =, ,$(1))).so.xyzzy +endif +ifdef DO_STATIC +STATIC_LIBS += lib$(lastword $(subst =, ,$(1))).a.xyzzy +endif +endef -include config.mak include package/targets.mak + +$(foreach var,$(LIB_DEFS),$(eval $(call library_definition,$(var)))) + include package/deps.mak version_m := $(basename $(version)) @@ -30,8 +44,6 @@ CPPFLAGS_ALL := -iquote src/include-local -Isrc/include $(CPPFLAGS) CFLAGS_ALL := $(CFLAGS) -pipe -Wall CFLAGS_SHARED := -fPIC LDFLAGS_ALL := $(LDFLAGS) -LDFLAGS_SHARED := -shared -LDLIBS_ALL := $(LDLIBS) REALCC = $(CROSS_COMPILE)$(CC) AR := $(CROSS_COMPILE)ar RANLIB := $(CROSS_COMPILE)ranlib @@ -67,11 +79,11 @@ ifneq ($(strip $(ALL_BINS)),) endif install: install-dynlib install-libexec install-bin install-sbin install-lib install-include -install-dynlib: $(SHARED_LIBS:lib%.so=$(DESTDIR)$(dynlibdir)/lib%.so) +install-dynlib: $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(dynlibdir)/lib%.so) install-libexec: $(LIBEXEC_TARGETS:%=$(DESTDIR)$(libexecdir)/%) install-bin: $(BIN_TARGETS:%=$(DESTDIR)$(bindir)/%) install-sbin: $(SBIN_TARGETS:%=$(DESTDIR)$(sbindir)/%) -install-lib: $(STATIC_LIBS:lib%.a=$(DESTDIR)$(libdir)/lib%.a) +install-lib: $(STATIC_LIBS:lib%.a.xyzzy=$(DESTDIR)$(libdir)/lib%.a) install-include: $(ALL_INCLUDES:src/include/$(package)/%.h=$(DESTDIR)$(includedir)/$(package)/%.h) install-data: $(ALL_DATA:src/etc/%=$(DESTDIR)$(datadir)/%) @@ -80,12 +92,12 @@ ifneq ($(exthome),) update: exec $(INSTALL) -l $(notdir $(home)) $(DESTDIR)$(exthome) -global-links: $(DESTDIR)$(exthome) $(SHARED_LIBS:lib%.so=$(DESTDIR)$(sproot)/library.so/lib%.so) $(BIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%) $(SBIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%) +global-links: $(DESTDIR)$(exthome) $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M)) $(BIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%) $(SBIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%) $(DESTDIR)$(sproot)/command/%: $(DESTDIR)$(home)/command/% exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/command/$( A POSIX-compliant system with a standard C development environment
  • GNU make, version 4.0 or later
  • skalibs version -2.3.6.0 or later
  • +2.3.6.1 or later
  • execline version -2.1.3.0 or later
  • +2.1.3.1 or later
  • s6 version -2.2.0.0 or later
  • +2.2.0.1 or later

    Licensing

    @@ -92,11 +92,6 @@ the previous versions of s6-rc and the current one.

    Commands

    -

    - All these commands exit 111 if they encounter a temporary error, and -100 if they encounter a permanent error - such as a misuse. -

    -

    Offline tools: creating and managing a compiled service database

    @@ -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 +s6rc- and s6-rc- prefixes.

    @@ -221,15 +235,16 @@ directory, but there are a few differences:

  • 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, data and env. +subdirectories will be copied verbatim, data and env. 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 data/ or env/ subdirectory.
  • Definition directories cannot have a log 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 two separate -s6-rc services, one for the producer and one for the logger; there is -specific syntax to link those two services.
  • +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.

    @@ -243,16 +258,23 @@ files will be copied, or recreated, in the generated service directory.

  • Optional directories named data and env. These will be copied verbatim into the generated service directory.
  • -
  • An optional file named logger. If this file exists, then -service will be flagged as a producer, and the file must -contain the name of another longrun service servicelog, which will -be declared as a logger for service. service must also -be declared as a producer in servicelog's definition directory.
  • -
  • An optional file named producer. If this file exists, then -service will be flagged as a logger, and the file must -contain the name of another longrun service serviceprod, which will -be declared as a producer for service. service must also -be declared as a logger in serviceprod's definition directory.
  • +
  • An optional file named producer-for. If this file exists, then +it must contain the name of another longrun service servicelog; +service is then declared as a producer for servicelog. +servicelog must also, in its own definition directory, +be declared as a consumer for service.
  • +
  • An optional file named consumer-for. If this file exists, then +it must contain the name of another longrun service serviceprod; +service is then declared as a consumer for serviceprod. +serviceprod must also, in its own definition directory, +be declared as a producer for service.
  • +
  • An optional file named pipeline-name. If this file exists +along with a producer-for file, and there is no +consumer-for file, then a bundle will automatically be +created, named with the content of the pipeline-name file, and +containing all the services in the pipeline that starts at service. +See below for more about pipelining. The pipeline-name file +is ignored if service is not a first producer.
  • @@ -271,26 +293,60 @@ services that are down.

    - The logger and producer files are support for logged services: -A service defined as a logger for producer p will have its s6 service -directory set to p/log. Logged service definitions must be consistent: + The producer-for, consumer-for and pipeline-name +files are used to set up automatic longrun pipelining. +

    + +

    Longrun pipelining

    + +

    + 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. +

    + +

    + 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.

    +

    + 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. +

    + +

    + s6-rc-compile checks for pipeline consistency. It must see a +producer-for file in the producer's definition that is consistent +with the consumer-for file in the consumer's definition. It will +detect and reject cycles as well as collisions. +

    + +

    + 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 +s6-fdholder-daemon +instance created by an automatically generated longrun service. +

    +

    A complete example

    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 live ] [ -c compiled ] [ -u | -d ] timeout atomicname s6-rc-db [ -l live ] [ -c compiled ] contents bundlename s6-rc-db [ -l live ] [ -c compiled ] [ -u | -d ] dependencies servicename - s6-rc-db [ -l live ] [ -c compiled ] servicedir longrunname + s6-rc-db [ -l live ] [ -c compiled ] pipeline longrunname s6-rc-db [ -l live ] [ -c compiled ] [ -u | -d ] script oneshotname s6-rc-db [ -l live ] [ -c compiled ] flags atomicname s6-rc-db [ -l live ] [ -c compiled ] atomics servicename... @@ -54,9 +54,8 @@ operation.

  • s6-rc-db expects to find a compiled service database in compiled; by default it uses the service database used by the live state in live. -It reads and parses the compiled database it finds. If the -database is invalid, it exits 4.
  • -
  • 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.
  • @@ -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. +

    Exit codes

    + + +

    Subcommands

    s6-rc-db help

    @@ -134,8 +144,7 @@ dependency tables, or a dependency cycle.

    Prints the type of servicename: oneshot, longrun -or bundle. Exits 1 if -servicename is not a valid identifier in the database. +or bundle.

    s6-rc-db timeout atomicname

    @@ -143,8 +152,8 @@ or bundle. Exits 1 if

    Prints the timeout value, in milliseconds, after which bringing atomicname up or down is considered a failure if the -called script still has not succeeded. Exits 1 if atomicname -isn't a valid atomic service. By default, or if the -u +called script still has not succeeded. +By default, or if the -u option has been given to s6-rc-db, the timeout for up is printed; the timeout for down is printed instead if the -d option has been given. @@ -154,14 +163,12 @@ printed; the timeout for down is printed instead if the

    Lists the atomic services represented by bundle bundlename. -Exits 1 if bundlename is not a valid bundle.

    s6-rc-db dependencies servicename

    - Prints the list of direct dependencies for servicename. -Exits 1 if servicename isn't a valid identifier. If + Prints the list of direct dependencies for servicename. If servicename 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 servicename, or on one of its components if it is a bundle.

    -

    s6-rc-db servicedir longrunname

    +

    s6-rc-db pipeline longrunname

    - Prints the service directory for longrun service longrunname; -this value is relative to the scandir. Exits 1 if -longrunname is not a valid longrun. + Prints the longrun service pipeline longrunname is a +part of, one service per line, producers before consumers. +If longrunname isn't +part of a pipeline, only longrunname is printed.

    s6-rc-db script oneshotname

    @@ -190,8 +198,7 @@ an argv, i.e. a Unix command line. Each component of this command line is terminated by a null character, so to print it in a human-readable format, pipe the output into something like -xargs -0 echo. The command exits 1 if oneshotname -is not a valid oneshot. +xargs -0 echo.

    @@ -203,8 +210,7 @@ is not a valid oneshot.

    Prints a hexadecimal number that is the list of all binary flags -for atomic service atomicname. Exits 1 if atomicname -is not a valid atomic service. +for atomic service atomicname.

    @@ -219,8 +225,7 @@ future version of s6-rc. servicename... arguments, i.e. the union of all atomic services contained in servicename.... Each argument in servicename... can be an atomic service or -a bundle. If an argument isn't a valid identifier, the command -exits 1. +a bundle.

    s6-rc-db all-dependencies servicename...

    @@ -232,8 +237,7 @@ dependencies, recursively. In other words: for servicename... to be up, every single service listed in the output will need to be up. The output includes the atomic services represented by the -servicename... arguments themselves. If one of those -arguments isn't a valid identifier, the command exits 1. +servicename... arguments themselves.

    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. +

    Exit codes

    + + +

    Service selection

    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 +#include #include #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 +#include #include #include #include @@ -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 #include #include #include @@ -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 #include -#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 #include #include -#include +#include +#include #include +#include #include #include #include @@ -21,7 +23,7 @@ #include #include -#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" -- cgit v1.2.3