summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2019-12-30 23:27:32 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2019-12-30 23:27:32 +0000
commited9dadb2778ab4ff7683622907e22ed8c561bfda (patch)
tree59d4341aa2d885d6928e1e30ab6f5f57916c09ee
downloads6-frontend-ed9dadb2778ab4ff7683622907e22ed8c561bfda.tar.xz
Initial commit.
-rw-r--r--.gitignore5
-rw-r--r--AUTHORS2
-rw-r--r--COPYING13
-rw-r--r--INSTALL174
-rw-r--r--Makefile151
-rw-r--r--NEWS6
-rw-r--r--README25
-rwxr-xr-xconfigure509
-rw-r--r--doc/index.html149
-rw-r--r--doc/quickstart.html26
-rw-r--r--doc/s6-frontend-alias.html41
-rw-r--r--doc/s6-frontend-config-preprocess.html87
-rw-r--r--doc/upgrade.html28
-rw-r--r--package/deps-build4
-rw-r--r--package/deps.mak17
-rw-r--r--package/info4
-rw-r--r--package/modes4
-rw-r--r--package/targets.mak75
-rw-r--r--src/alias/deps-exe/s6-frontend-alias1
-rw-r--r--src/alias/deps-exe/s6-frontend-alias-chpst1
-rw-r--r--src/alias/deps-exe/s6-frontend-alias-sv3
-rw-r--r--src/alias/s6-frontend-alias-chpst.c347
-rw-r--r--src/alias/s6-frontend-alias-sv.c377
-rw-r--r--src/alias/s6-frontend-alias.c235
-rw-r--r--src/config/deps-exe/s6-frontend-config-preprocess1
-rw-r--r--src/config/s6-frontend-config-preprocess.c286
-rw-r--r--src/config/s6-frontend-config-preprocess.txt38
-rwxr-xr-xtools/gen-deps.sh93
-rwxr-xr-xtools/install.sh64
29 files changed, 2766 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9ac94b8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*.o
+*.lo
+/config.mak
+/src/include/s6-frontend/config.h
+/s6-frontend-*
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..7a708a1
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,2 @@
+Main author:
+ Laurent Bercot <ska-skaware@skarnet.org>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..361dcb6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,13 @@
+Copyright (c) 2018 Laurent Bercot <ska-skaware@skarnet.org>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..6442173
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,174 @@
+Build Instructions
+------------------
+
+* Requirements
+ ------------
+
+ - A POSIX compatible system with a standard C development environment
+ - GNU make version 3.81 or later
+ - skalibs version 2.9.1.0 or later: https://skarnet.org/software/skalibs/
+ - execline version 2.6.0.0 or later: https://skarnet.org/software/execline/
+ - s6 version 2.9.0.1 or later: https://skarnet.org/software/s6/
+ - s6-rc version 0.5.1.1 or later: https://skarnet.org/software/s6-rc/
+ - s6-linux-init version 1.0.3.1 or later: https://skarnet.org/software/s6-linux-init/
+
+
+* Standard usage
+ --------------
+
+ ./configure && make && sudo make install
+
+ will work for most users.
+ It will install the binaries in /bin.
+
+ You can strip the binaries and libraries of their extra symbols via
+"make strip" before the "make install" phase. It will shave a few bytes
+off them.
+
+
+* Customization
+ -------------
+
+ You can customize paths via flags given to configure.
+ See ./configure --help for a list of all available configure options.
+
+ --enable-alias-daemontools will build some daemontools emulation
+binaries and, at installation time, ensure daemontools binary names
+(such as "envdir" or "svc") point to them.
+
+ --enable-alias-runit will build some runit emulation binaries and,
+at installation time, ensure runit binary names (such as "sv" or
+"chpst") point to them.
+
+
+* Environment variables
+ ---------------------
+
+ Controlling a build process via environment variables is a big and
+dangerous hammer. You should try and pass flags to configure instead;
+nevertheless, a few standard environment variables are recognized.
+
+ If the CC environment variable is set, its value will override compiler
+detection by configure. The --host=HOST option will still add a HOST-
+prefix to the value of CC.
+
+ The values of CFLAGS, CPPFLAGS and LDFLAGS will be appended to flags
+auto-detected by configure. To entirely override the flags set by
+configure instead, use make variables.
+
+
+* Make variables
+ --------------
+
+ You can invoke make with a few variables for more configuration.
+
+ CC, CFLAGS, CPPFLAGS, LDFLAGS, LDLIBS, AR, RANLIB, STRIP, INSTALL and
+CROSS_COMPILE can all be overridden on the make command line. This is
+an even bigger hammer than running ./configure with environment
+variables, so it is advised to only do this when it is the only way of
+obtaining the behaviour you want.
+
+ DESTDIR can be given on the "make install" command line in order to
+install to a staging directory.
+
+
+* Shared libraries
+ ----------------
+
+ Software from skarnet.org is small enough that shared libraries are
+generally not worth using. Static linking is simpler and incurs less
+runtime overhead and less points of failure: so by default, shared
+libraries are not built and binaries are linked against the static
+versions of the skarnet.org libraries. Nevertheless, you can:
+ * build shared libraries: --enable-shared
+ * link binaries against shared libraries: --disable-allstatic
+
+
+* Static binaries
+ ---------------
+
+ By default, binaries are linked against static versions of all the
+libraries they depend on, except for the libc. You can enforce
+linking against the static libc with --enable-static-libc.
+
+ (If you are using a GNU/Linux system, be aware that the GNU libc
+behaves badly with static linking and produces huge executables,
+which is why it is not the default. Other libcs are better suited
+to static linking, for instance musl: https://musl-libc.org/)
+
+
+* Cross-compilation
+ -----------------
+
+ skarnet.org packages centralize all the difficulty of
+cross-compilation in one place: skalibs. Once you have
+cross-compiled skalibs, the rest is easy.
+
+ * Use the --host=HOST option to configure, HOST being the triplet
+for your target.
+ * Make sure your cross-toolchain binaries (i.e. prefixed with HOST-)
+are accessible via your PATH environment variable.
+ * Make sure to use the correct version of skalibs for your target,
+and the correct sysdeps directory, making use of the
+--with-include, --with-lib, --with-dynlib and --with-sysdeps
+options as necessary.
+
+
+* The slashpackage convention
+ ---------------------------
+
+ The slashpackage convention (http://cr.yp.to/slashpackage.html)
+is a package installation scheme that provides a few guarantees
+over other conventions such as the FHS, for instance fixed
+absolute pathnames. skarnet.org packages support it: use the
+--enable-slashpackage option to configure, or
+--enable-slashpackage=DIR for a prefixed DIR/package tree.
+This option will activate slashpackage support during the build
+and set slashpackage-compatible installation directories.
+If $package_home is the home of the package, defined as
+DIR/package/$category/$package-$version with the variables
+read from the package/info file, then:
+
+ --dynlibdir is set to $package_home/library.so
+ --bindir is set to $package_home/command
+ --sbindir is also set to $package_home/command (slashpackage
+differentiates root-only binaries by their Unix rights, not their
+location in the filesystem)
+ --libexecdir is also set to $package_home/command (slashpackage
+does not need a specific directory for internal binaries)
+ --libdir is set to $package_home/library
+ --includedir is set to $package_home/include
+
+ --prefix is pretty much ignored when you use --enable-slashpackage.
+You should probably not use both --enable-slashpackage and --prefix.
+
+ When using slashpackage, two additional Makefile targets are
+available after "make install":
+ - "make update" changes the default version of the software to the
+freshly installed one. (This is useful when you have several installed
+versions of the same software, which slashpackage supports.)
+ - "make -L global-links" adds links from /command and /library.so to the
+default version of the binaries and shared libraries. The "-L" option to
+make is necessary because targets are symbolic links, and the default make
+behaviour is to check the pointed file's timestamp and not the symlink's
+timestamp.
+
+
+* Absolute pathnames
+ ------------------
+
+ You may want to use fixed absolute pathnames even if you're not
+following the slashpackage convention: for instance, the Nix packaging
+system prefers calling binaries with immutable paths rather than rely on
+PATH resolution. If you are in that case, use the --enable-absolute-paths
+option to configure. This will ensure that programs calling binaries from
+this package will call them with their full installation path (in bindir)
+without relying on a PATH search.
+
+
+* Out-of-tree builds
+ ------------------
+
+ skarnet.org packages do not support out-of-tree builds. They
+are small, so it does not cost much to duplicate the entire
+source tree if parallel builds are needed.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..610dbb6
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,151 @@
+#
+# This Makefile requires GNU make.
+#
+# Do not make changes here.
+# Use the included .mak files.
+#
+
+it: all
+
+make_need := 3.81
+ifeq "" "$(strip $(filter $(make_need), $(firstword $(sort $(make_need) $(MAKE_VERSION)))))"
+fail := $(error Your make ($(MAKE_VERSION)) is too old. You need $(make_need) or newer)
+endif
+
+CC = $(error Please use ./configure first)
+
+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))
+version_M := $(basename $(version_m))
+version_l := $(basename $(version_M))
+CPPFLAGS_ALL := $(CPPFLAGS_AUTO) $(CPPFLAGS)
+CFLAGS_ALL := $(CFLAGS_AUTO) $(CFLAGS)
+ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)
+CFLAGS_SHARED := -fPIC
+else
+CFLAGS_SHARED :=
+endif
+LDFLAGS_ALL := $(LDFLAGS_AUTO) $(LDFLAGS)
+REALCC = $(CROSS_COMPILE)$(CC)
+AR := $(CROSS_COMPILE)ar
+RANLIB := $(CROSS_COMPILE)ranlib
+STRIP := $(CROSS_COMPILE)strip
+INSTALL := ./tools/install.sh
+
+ALL_BINS := $(LIBEXEC_TARGETS) $(BIN_TARGETS)
+ALL_LIBS := $(SHARED_LIBS) $(STATIC_LIBS) $(INTERNAL_LIBS)
+ALL_INCLUDES := $(wildcard src/include/$(package)/*.h)
+
+all: $(ALL_LIBS) $(ALL_BINS) $(ALL_INCLUDES)
+
+clean:
+ @exec rm -f $(ALL_LIBS) $(ALL_BINS) $(wildcard src/*/*.o src/*/*.lo) $(EXTRA_TARGETS)
+
+distclean: clean
+ @exec rm -f config.mak src/include/$(package)/config.h
+
+tgz: distclean
+ @. package/info && \
+ rm -rf /tmp/$$package-$$version && \
+ cp -a . /tmp/$$package-$$version && \
+ cd /tmp && \
+ tar -zpcv --owner=0 --group=0 --numeric-owner --exclude=.git* -f /tmp/$$package-$$version.tar.gz $$package-$$version && \
+ exec rm -rf /tmp/$$package-$$version
+
+strip: $(ALL_LIBS) $(ALL_BINS)
+ifneq ($(strip $(STATIC_LIBS)),)
+ exec $(STRIP) -x -R .note -R .comment -R .note.GNU-stack $(STATIC_LIBS)
+endif
+ifneq ($(strip $(ALL_BINS)$(SHARED_LIBS)),)
+ exec $(STRIP) -R .note -R .comment -R .note.GNU-stack $(ALL_BINS) $(SHARED_LIBS)
+endif
+
+install: install-dynlib install-libexec install-bin install-lib install-include
+install-dynlib: $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(dynlibdir)/lib%.so)
+install-libexec: $(LIBEXEC_TARGETS:%=$(DESTDIR)$(libexecdir)/%)
+install-bin: $(BIN_TARGETS:%=$(DESTDIR)$(bindir)/%)
+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)/%)
+
+ifneq ($(exthome),)
+
+$(DESTDIR)$(exthome): $(DESTDIR)$(home)
+ exec $(INSTALL) -l $(notdir $(home)) $(DESTDIR)$(exthome)
+
+update: $(DESTDIR)$(exthome)
+
+global-links: $(DESTDIR)$(exthome) $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M)) $(BIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%)
+
+$(DESTDIR)$(sproot)/command/%: $(DESTDIR)$(home)/command/%
+ exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/command/$(<F) $@
+
+$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M): $(DESTDIR)$(dynlibdir)/lib%.so.$(version_M)
+ exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/library.so/$(<F) $@
+
+.PHONY: update global-links
+
+endif
+
+$(DESTDIR)$(datadir)/%: src/etc/%
+ exec $(INSTALL) -D -m 644 $< $@
+
+$(DESTDIR)$(dynlibdir)/lib%.so: lib%.so.xyzzy
+ $(INSTALL) -D -m 755 $< $@.$(version) && \
+ $(INSTALL) -l $(@F).$(version) $@.$(version_m) && \
+ $(INSTALL) -l $(@F).$(version_m) $@.$(version_M) && \
+ exec $(INSTALL) -l $(@F).$(version_M) $@
+
+$(DESTDIR)$(libexecdir)/% $(DESTDIR)$(bindir)/%: % package/modes
+ exec $(INSTALL) -D -m 600 $< $@
+ grep -- ^$(@F) < package/modes | { read name mode owner && \
+ if [ x$$owner != x ] ; then chown -- $$owner $@ ; fi && \
+ chmod $$mode $@ ; }
+
+$(DESTDIR)$(libdir)/lib%.a: lib%.a.xyzzy
+ exec $(INSTALL) -D -m 644 $< $@
+
+$(DESTDIR)$(includedir)/$(package)/%.h: src/include/$(package)/%.h
+ exec $(INSTALL) -D -m 644 $< $@
+
+%.o: %.c
+ exec $(REALCC) $(CPPFLAGS_ALL) $(CFLAGS_ALL) -c -o $@ $<
+
+%.lo: %.c
+ exec $(REALCC) $(CPPFLAGS_ALL) $(CFLAGS_ALL) $(CFLAGS_SHARED) -c -o $@ $<
+
+$(ALL_BINS):
+ exec $(REALCC) -o $@ $(CFLAGS_ALL) $(LDFLAGS_ALL) $(LDFLAGS_NOSHARED) $^ $(EXTRA_LIBS) $(LDLIBS)
+
+lib%.a.xyzzy:
+ exec $(AR) rc $@ $^
+ exec $(RANLIB) $@
+
+lib%.so.xyzzy:
+ exec $(REALCC) -o $@ $(CFLAGS_ALL) $(CFLAGS_SHARED) $(LDFLAGS_ALL) $(LDFLAGS_SHARED) -Wl,-soname,$(patsubst lib%.so.xyzzy,lib%.so.$(version_M),$@) $^ $(EXTRA_LIBS) $(LDLIBS)
+
+.PHONY: it all clean distclean tgz strip install install-dynlib install-bin install-lib install-include install-data
+
+.DELETE_ON_ERROR:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..b662d60
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,6 @@
+Changelog for s6-frontend
+
+In 0.0.1.0
+----------
+
+ - Initial release.
diff --git a/README b/README
new file mode 100644
index 0000000..0d975bb
--- /dev/null
+++ b/README
@@ -0,0 +1,25 @@
+s6-frontend - a s6-based init system with a friendly UI
+-------------------------------------------------------
+
+ s6-frontend is a set of programs providing interfaces
+to the s6 family of programs (s6, s6-rc, s6-linux-init)
+for users who are used to different systems. It also
+comes with a full set of init scripts and can be used as
+a turnkey init system.
+
+ See https://skarnet.org/software/s6-frontend/ for details.
+
+
+* Installation
+ ------------
+
+ See the INSTALL file.
+
+
+* Contact information
+ -------------------
+
+ Laurent Bercot <ska-skaware at skarnet.org>
+
+ Please use the <supervision at list.skarnet.org> mailing-list for
+questions about s6-frontend.
diff --git a/configure b/configure
new file mode 100755
index 0000000..1abcd9c
--- /dev/null
+++ b/configure
@@ -0,0 +1,509 @@
+#!/bin/sh
+
+cd `dirname "$0"`
+. package/info
+
+usage () {
+cat <<EOF
+Usage: $0 [OPTION]... [TARGET]
+
+Defaults for the options are specified in brackets.
+
+System types:
+ --target=TARGET configure to run on target TARGET [detected]
+ --host=TARGET same as --target
+
+Installation directories:
+ --prefix=PREFIX main installation prefix [/]
+ --exec-prefix=EPREFIX installation prefix for executable files [PREFIX]
+
+Fine tuning of the installation directories:
+ --dynlibdir=DIR shared library files [PREFIX/lib]
+ --bindir=BINDIR user executables [EPREFIX/bin]
+ --libexecdir=DIR package-scoped executables [EPREFIX/libexec]
+ --libdir=DIR static library files [PREFIX/lib/$package]
+ --includedir=DIR C header files [PREFIX/include]
+
+ If no --prefix option is given, by default libdir (but not dynlibdir) will be
+ /usr/lib/$package, and includedir will be /usr/include.
+
+Dependencies:
+ --with-sysdeps=DIR use sysdeps in DIR [PREFIX/lib/skalibs/sysdeps]
+ --with-include=DIR add DIR to the list of searched directories for headers
+ --with-lib=DIR add DIR to the list of searched directories for static libraries
+ --with-dynlib=DIR add DIR to the list of searched directories for shared libraries
+
+ If no --prefix option is given, by default sysdeps will be fetched from
+ /usr/lib/skalibs/sysdeps.
+
+Optional features:
+ --enable-shared build shared libraries [disabled]
+ --disable-static do not build static libraries [enabled]
+ --disable-allstatic do not prefer linking against static libraries [enabled]
+ --enable-static-libc make entirely static binaries [disabled]
+ --disable-all-pic do not build executables or static libs as PIC [enabled]
+ --enable-slashpackage[=ROOT] assume /package installation at ROOT [disabled]
+ --enable-absolute-paths do not rely on PATH to access this package's binaries,
+ hardcode absolute BINDIR/foobar paths instead [disabled]
+ --enable-nsss use the nsss library for user information [disabled]
+ --enable-aliases-daemontools build emulation of daemontools programs [disabled]
+ --enable-aliases-runit build emulation of runit programs [disabled]
+
+EOF
+exit 0
+}
+
+# Helper functions
+
+# If your system does not have printf, you can comment this, but it is
+# generally not a good idea to use echo.
+# See http://www.etalabs.net/sh_tricks.html
+echo () {
+ IFS=" "
+ printf %s\\n "$*"
+}
+
+quote () {
+ tr '\n' ' ' <<EOF | grep '^[-[:alnum:]_=,./:]* $' >/dev/null 2>&1 && { echo "$1" ; return 0 ; }
+$1
+EOF
+ echo "$1" | sed -e "s/'/'\\\\''/g" -e "1s/^/'/" -e "\$s/\$/'/" -e "s#^'\([-[:alnum:]_,./:]*\)=\(.*\)\$#\1='\2#" -e "s|\*/|* /|g"
+}
+
+fail () {
+ echo "$*"
+ exit 1
+}
+
+fnmatch () {
+ eval "case \"\$2\" in $1) return 0 ;; *) return 1 ;; esac"
+}
+
+cmdexists () {
+ type "$1" >/dev/null 2>&1
+}
+
+trycc () {
+ test -z "$CC_AUTO" && cmdexists "$1" && CC_AUTO="$*"
+}
+
+stripdir () {
+ while eval "fnmatch '*/' \"\${$1}\"" ; do
+ eval "$1=\${$1%/}"
+ done
+}
+
+tryflag () {
+ echo "Checking whether compiler accepts $2 ..."
+ echo "typedef int x;" > "$tmpc"
+ if $CC_AUTO $CPPFLAGS_AUTO $CPPFLAGS $CPPFLAGS_POST $CFLAGS_AUTO $CFLAGS $CFLAGS_POST "$2" -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then
+ echo " ... yes"
+ eval "$1=\"\${$1} \$2\""
+ eval "$1=\${$1# }"
+ return 0
+ else
+ echo " ... no"
+ return 1
+ fi
+}
+
+tryldflag () {
+ echo "Checking whether linker accepts $2 ..."
+ echo "typedef int x;" > "$tmpc"
+ if $CC_AUTO $CFLAGS_AUTO $CFLAGS $CFLAGS_POST $LDFLAGS_AUTO $LDFLAGS $LDFLAGS_POST -nostdlib "$2" -o /dev/null "$tmpc" >/dev/null 2>&1 ; then
+ echo " ... yes"
+ eval "$1=\"\${$1} \$2\""
+ eval "$1=\${$1# }"
+ return 0
+ else
+ echo " ... no"
+ return 1
+ fi
+}
+
+
+# Actual script
+
+CC_AUTO=
+CPPFLAGS_AUTO="-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -iquote src/include-local -Isrc/include"
+CPPFLAGS_POST="$CPPFLAGS"
+CPPFLAGS=
+CFLAGS_AUTO="-pipe -Wall"
+CFLAGS_POST="$CFLAGS"
+CFLAGS=-O2
+LDFLAGS_AUTO=
+LDFLAGS_POST="$LDFLAGS"
+LDFLAGS=
+LDFLAGS_NOSHARED=
+LDFLAGS_SHARED=-shared
+prefix=
+exec_prefix='$prefix'
+dynlibdir='$prefix/lib'
+libexecdir='$exec_prefix/libexec'
+bindir='$exec_prefix/bin'
+libdir='$prefix/lib/$package'
+includedir='$prefix/include'
+sysdeps='$prefix/lib/skalibs/sysdeps'
+manualsysdeps=false
+shared=false
+static=true
+allpic=true
+slashpackage=false
+abspath=false
+usensss=false
+sproot=
+home=
+exthome=
+allstatic=true
+evenmorestatic=false
+addincpath=''
+addlibspath=''
+addlibdpath=''
+vpaths=''
+vpathd=''
+build=
+adaemontools=false
+arunit=false
+
+for arg ; do
+ case "$arg" in
+ --help) usage ;;
+ --prefix=*) prefix=${arg#*=} ;;
+ --exec-prefix=*) exec_prefix=${arg#*=} ;;
+ --dynlibdir=*) dynlibdir=${arg#*=} ;;
+ --libexecdir=*) libexecdir=${arg#*=} ;;
+ --bindir=*) bindir=${arg#*=} ;;
+ --libdir=*) libdir=${arg#*=} ;;
+ --includedir=*) includedir=${arg#*=} ;;
+ --with-sysdeps=*) sysdeps=${arg#*=} manualsysdeps=true ;;
+ --with-include=*) var=${arg#*=} ; stripdir var ; addincpath="$addincpath -I$var" ;;
+ --with-lib=*) var=${arg#*=} ; stripdir var ; addlibspath="$addlibspath -L$var" ; vpaths="$vpaths $var" ;;
+ --with-dynlib=*) var=${arg#*=} ; stripdir var ; addlibdpath="$addlibdpath -L$var" ; vpathd="$vpathd $var" ;;
+ --enable-shared|--enable-shared=yes) shared=true ;;
+ --disable-shared|--enable-shared=no) shared=false ;;
+ --enable-static|--enable-static=yes) static=true ;;
+ --disable-static|--enable-static=no) static=false ;;
+ --enable-allstatic|--enable-allstatic=yes) allstatic=true ;;
+ --disable-allstatic|--enable-allstatic=no) allstatic=false ; evenmorestatic=false ;;
+ --enable-static-libc|--enable-static-libc=yes) allstatic=true ; evenmorestatic=true ;;
+ --disable-static-libc|--enable-static-libc=no) evenmorestatic=false ;;
+ --enable-all-pic|--enable-all-pic=yes) allpic=true ;;
+ --disable-all-pic|--enable-all-pic=no) allpic=false ;;
+ --enable-slashpackage=*) sproot=${arg#*=} ; slashpackage=true ; ;;
+ --enable-slashpackage) sproot= ; slashpackage=true ;;
+ --disable-slashpackage) sproot= ; slashpackage=false ;;
+ --enable-absolute-paths|--enable-absolute-paths=yes) abspath=true ;;
+ --disable-absolute-paths|--enable-absolute-paths=no) abspath=false ;;
+ --enable-nsss|--enable-nsss=yes) usensss=true ;;
+ --disable-nsss|--enable-nsss=no) usensss=false ;;
+ --enable-aliases-daemontools|--enable-aliases-daemontools=yes) adaemontools=true ;;
+ --disable-aliases-daemontools|--enable-aliases-daemontools=no) adaemontools=false ;;
+ --enable-aliases-runit|--enable-aliases-runit=yes) arunit=true ;;
+ --disable-aliases-runit|--enable-aliases-runit=no) arunit=false ;;
+ --enable-*|--disable-*|--with-*|--without-*|--*dir=*) ;;
+ --host=*|--target=*) target=${arg#*=} ;;
+ --build=*) build=${arg#*=} ;;
+ -* ) echo "$0: unknown option $arg" ;;
+ *=*) ;;
+ *) target=$arg ;;
+ esac
+done
+
+# Add /usr in the default default case
+if test -z "$prefix" ; then
+ if test "$libdir" = '$prefix/lib/$package' ; then
+ libdir=/usr/lib/$package
+ fi
+ if test "$includedir" = '$prefix/include' ; then
+ includedir=/usr/include
+ fi
+ if test "$sysdeps" = '$prefix/lib/skalibs/sysdeps' ; then
+ sysdeps=/usr/lib/skalibs/sysdeps
+ fi
+fi
+
+# Expand installation directories
+stripdir prefix
+for i in exec_prefix dynlibdir libexecdir bindir libdir includedir sysdeps sproot ; do
+ eval tmp=\${$i}
+ eval $i=$tmp
+ stripdir $i
+done
+
+# Get usable temp filenames
+i=0
+set -C
+while : ; do
+ i=$(($i+1))
+ tmpc="./tmp-configure-$$-$PPID-$i.c"
+ tmpe="./tmp-configure-$$-$PPID-$i.tmp"
+ 2>|/dev/null > "$tmpc" && break
+ 2>|/dev/null > "$tmpe" && break
+ test "$i" -gt 50 && fail "$0: cannot create temporary files"
+done
+set +C
+trap 'rm -f "$tmpc" "$tmpe"' EXIT ABRT INT QUIT TERM HUP
+
+# Set slashpackage values
+if $slashpackage ; then
+ home=${sproot}/package/${category}/${package}-${version}
+ exthome=${sproot}/package/${category}/${package}
+ if $manualsysdeps ; then
+ :
+ else
+ sysdeps=${sproot}/package/prog/skalibs/sysdeps
+ fi
+ extbinprefix=${exthome}/command
+ dynlibdir=${home}/library.so
+ bindir=${home}/command
+ libdir=${home}/library
+ libexecdir=$bindir
+ includedir=${home}/include
+ while read dep condvar ; do
+ if test -n "$condvar" ; then
+ eval "cond=$condvar"
+ else
+ cond=true
+ fi
+ if $cond ; then
+ addincpath="$addincpath -I${sproot}${dep}/include"
+ vpaths="$vpaths ${sproot}${dep}/library"
+ addlibspath="$addlibspath -L${sproot}${dep}/library"
+ vpathd="$vpathd ${sproot}${dep}/library.so"
+ addlibdpath="$addlibdpath -L${sproot}${dep}/library.so"
+ fi
+ done < package/deps-build
+fi
+
+# Find a C compiler to use
+if test -n "$target" && test x${build} != x${target} ; then
+ cross=${target}-
+else
+ cross=
+fi
+echo "Checking for C compiler..."
+trycc ${CC}
+if test -n "$CC_AUTO" ; then
+ b=`basename "$CC"`
+ adjust_cross=false
+ if test "$b" != "$CC" ; then
+ adjust_cross=true
+ echo "$0: warning: compiler $CC is declared with its own path. If it's not accessible via PATH, you will need to pass AR, RANLIB and STRIP make variables to the make invocation." 1>&2
+ fi
+ if test -n "$cross" ; then
+ if test "$b" = "${b##$cross}" ; then
+ echo "$0: warning: compiler $CC is declared as a cross-compiler for target $target but does not start with prefix ${cross}" 1>&2
+ elif $adjust_cross ; then
+ cross=`dirname "$CC"`/"$cross"
+ fi
+ fi
+fi
+trycc ${cross}gcc
+trycc ${cross}clang
+trycc ${cross}cc
+test -n "$CC_AUTO" || { echo "$0: cannot find a C compiler" ; exit 1 ; }
+echo " ... $CC_AUTO"
+echo "Checking whether C compiler works... "
+echo "typedef int x;" > "$tmpc"
+if $CC_AUTO $CPPFLAGS_AUTO $CPPFLAGS $CPPFLAGS_POST $CFLAGS_AUTO $CFLAGS $CFLAGS_POST -c -o /dev/null "$tmpc" 2>"$tmpe" ; then
+ echo " ... yes"
+else
+ echo " ... no. Compiler output follows:"
+ cat < "$tmpe"
+ exit 1
+fi
+
+echo "Checking target system type..."
+if test -z "$target" ; then
+ if test -n "$build" ; then
+ target=$build ;
+ else
+ target=$($CC_AUTO -dumpmachine 2>/dev/null) || target=unknown
+ fi
+fi
+echo " ... $target"
+if test ! -d $sysdeps || test ! -f $sysdeps/target ; then
+ echo "$0: error: $sysdeps is not a valid sysdeps directory"
+ exit 1
+fi
+if [ "x$target" != "x$(cat $sysdeps/target)" ] ; then
+ echo "$0: error: target $target does not match the contents of $sysdeps/target"
+ exit 1
+fi
+
+spawn_lib=$(cat $sysdeps/spawn.lib)
+socket_lib=$(cat $sysdeps/socket.lib)
+sysclock_lib=$(cat $sysdeps/sysclock.lib)
+timer_lib=$(cat $sysdeps/timer.lib)
+util_lib=$(cat $sysdeps/util.lib)
+
+if $allpic ; then
+ tryflag CPPFLAGS_AUTO -fPIC
+fi
+tryflag CFLAGS_AUTO -std=c99
+tryflag CFLAGS -fomit-frame-pointer
+tryflag CFLAGS_AUTO -fno-exceptions
+tryflag CFLAGS_AUTO -fno-unwind-tables
+tryflag CFLAGS_AUTO -fno-asynchronous-unwind-tables
+tryflag CFLAGS_AUTO -Wa,--noexecstack
+tryflag CFLAGS -fno-stack-protector
+tryflag CPPFLAGS_AUTO -Werror=implicit-function-declaration
+tryflag CPPFLAGS_AUTO -Werror=implicit-int
+tryflag CPPFLAGS_AUTO -Werror=pointer-sign
+tryflag CPPFLAGS_AUTO -Werror=pointer-arith
+tryflag CFLAGS_AUTO -ffunction-sections
+tryflag CFLAGS_AUTO -fdata-sections
+
+tryldflag LDFLAGS_AUTO -Wl,--sort-section=alignment
+tryldflag LDFLAGS_AUTO -Wl,--sort-common
+
+CPPFLAGS_AUTO="${CPPFLAGS_AUTO}${addincpath}"
+
+if $evenmorestatic ; then
+ LDFLAGS_NOSHARED=-static
+fi
+
+if $shared ; then
+ tryldflag LDFLAGS -Wl,--hash-style=both
+fi
+
+LDFLAGS_SHARED="${LDFLAGS_SHARED}${addlibdpath}"
+
+if $allstatic ; then
+ LDFLAGS_NOSHARED="${LDFLAGS_NOSHARED}${addlibspath}"
+ tryldflag LDFLAGS_NOSHARED -Wl,--gc-sections
+else
+ LDFLAGS_NOSHARED="${LDFLAGS_NOSHARED}${addlibdpath}"
+fi
+
+if test -z "$vpaths" ; then
+ while read dep ; do
+ base=$(basename $dep) ;
+ vpaths="$vpaths /usr/lib/$base"
+ addlibspath="$addlibspath -L/usr/lib/$base"
+ done < package/deps-build
+fi
+
+echo "Creating config.mak..."
+cmdline=$(quote "$0")
+for i ; do cmdline="$cmdline $(quote "$i")" ; done
+exec 3>&1 1>config.mak
+cat << EOF
+# This file was generated by:
+# $cmdline
+# Any changes made here will be lost if configure is re-run.
+
+target := $target
+package := $package
+prefix := $prefix
+exec_prefix := $exec_prefix
+dynlibdir := $dynlibdir
+libexecdir := $libexecdir
+bindir := $bindir
+libdir := $libdir
+includedir := $includedir
+sysdeps := $sysdeps
+slashpackage := $slashpackage
+sproot := $sproot
+version := $version
+home := $home
+exthome := $exthome
+SPAWN_LIB := ${spawn_lib}
+SOCKET_LIB := ${socket_lib}
+SYSCLOCK_LIB := ${sysclock_lib}
+TIMER_LIB := ${timer_lib}
+UTIL_LIB := ${util_lib}
+
+CC := $CC_AUTO
+CPPFLAGS_AUTO := $CPPFLAGS_AUTO
+CPPFLAGS := $CPPFLAGS $CPPFLAGS_POST
+CFLAGS_AUTO := $CFLAGS_AUTO
+CFLAGS := $CFLAGS $CFLAGS_POST
+LDFLAGS_AUTO := $LDFLAGS_AUTO
+LDFLAGS := $LDFLAGS $LDFLAGS_POST
+LDFLAGS_SHARED := $LDFLAGS_SHARED
+LDFLAGS_NOSHARED := $LDFLAGS_NOSHARED
+CROSS_COMPILE := $cross
+
+vpath lib%.a$vpaths
+vpath lib%.so$vpathd
+EOF
+if $allstatic ; then
+ echo ".LIBPATTERNS := lib%.a"
+ echo "DO_ALLSTATIC := 1"
+else
+ echo ".LIBPATTERNS := lib%.so"
+fi
+if $static ; then
+ echo "DO_STATIC := 1"
+else
+ echo "DO_STATIC :="
+fi
+if $shared ; then
+ echo "DO_SHARED := 1"
+else
+ echo "DO_SHARED :="
+fi
+if $allpic ; then
+ echo "STATIC_LIBS_ARE_PIC := 1"
+else
+ echo "STATIC_LIBS_ARE_PIC :="
+fi
+if $usensss ; then
+ echo "LIBNSSS := -lnsss"
+ echo "MAYBEPTHREAD_LIB := -lpthread"
+else
+ echo "LIBNSSS :="
+ echo "MAYBEPTHREAD_LIB :="
+fi
+if $adaemontools ; then
+ echo "WRAP_DAEMONTOOLS := 1"
+else
+ echo "WRAP_DAEMONTOOLS :="
+fi
+if $arunit ; then
+ echo "WRAP_RUNIT := 1"
+else
+ echo "WRAP_RUNIT :="
+fi
+
+exec 1>&3 3>&-
+echo " ... done."
+
+echo "Creating src/include/${package}/config.h..."
+mkdir -p -m 0755 src/include/${package}
+exec 3>&1 1> src/include/${package}/config.h
+cat <<EOF
+/* ISC license. */
+
+/* Generated by: $cmdline */
+
+#ifndef ${package_macro_name}_CONFIG_H
+#define ${package_macro_name}_CONFIG_H
+
+#define ${package_macro_name}_VERSION "$version"
+EOF
+if $slashpackage ; then
+ echo "#define ${package_macro_name}_BINPREFIX \"$bindir/\""
+ echo "#define ${package_macro_name}_EXTBINPREFIX \"$extbinprefix/\""
+elif $abspath ; then
+ echo "#define ${package_macro_name}_BINPREFIX \"$bindir/\""
+ echo "#define ${package_macro_name}_EXTBINPREFIX \"$bindir/\""
+else
+ echo "#define ${package_macro_name}_BINPREFIX \"\""
+ echo "#define ${package_macro_name}_EXTBINPREFIX \"\""
+fi
+echo "#define ${package_macro_name}_LIBEXECPREFIX \"$libexecdir/\""
+echo
+echo "#undef ${package_macro_name}_WRAP_DAEMONTOOLS"
+if $adaemontools ; then
+ echo "#define ${package_macro_name}_WRAP_DAEMONTOOLS"
+fi
+echo "#undef ${package_macro_name}_WRAP_RUNIT"
+if $arunit ; then
+ echo "#define ${package_macro_name}_WRAP_RUNIT"
+fi
+echo
+echo "#endif"
+exec 1>&3 3>&-
+echo " ... done."
diff --git a/doc/index.html b/doc/index.html
new file mode 100644
index 0000000..bd6512c
--- /dev/null
+++ b/doc/index.html
@@ -0,0 +1,149 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-frontend - a frontend to the s6 ecosystem</title>
+ <meta name="Description" content="s6-frontend - a frontend to the s6 ecosystem" />
+ <meta name="Keywords" content="s6 s6-rc frontend administration root laurent bercot ska skarnet init" />
+ <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="//skarnet.org/software/">Software</a><br />
+<a href="//skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> s6-frontend </h1>
+
+<h2> What is it&nbsp;? </h2>
+
+<p>
+ <strong><em><red> s6-frontend is still in development. </red></em></strong>
+</p>
+
+<p>
+ s6-frontend is a frontend to the s6 ecosystem. It is made of
+several parts:
+</p>
+
+<ul>
+ <li> A set of user-friendly commands, making it easier to manage a
+s6-based system for people who are used to other tools. </li>
+ <li> An independent configuration file format,
+and tools that automatically analyze a configuration written in that
+format and transform it into a configuration suitable for booting a
+system via
+<a href="//skarnet.org/software/s6/">s6</a>,
+<a href="//skarnet.org/software/s6-linux-init/">s6-linux-init</a> and
+<a href="//skarnet.org/software/s6-rc/">s6-rc</a>. This should help
+users who are not familiar with s6 and s6-rc directory-based configuration
+but are used to, for instance, systemd unit files.</li>
+ <li> A prepackaged set of configuration files, implementing <em>policy</em>,
+suitable for booting a large majority of Linux-based systems. This should
+help distributions that want to switch to s6 but do not want to rewrite all
+their init scripts in yet another format. </li>
+</ul>
+
+<p>
+ These parts are all independent from one another. But when put all together,
+they implement a powerful, fast, turnkey init system that is usable on
+<em>any</em> distribution.
+</p>
+
+<hr />
+
+<ul>
+ <li> <a href="quickstart.html">Quickstart and FAQ</a> </li>
+</ul>
+
+<hr />
+<h2> Installation </h2>
+
+<h3> Requirements </h3>
+
+<ul>
+ <li> A Linux-based system with a standard C development environment </li>
+ <li> GNU make, version 3.81 or later </li>
+ <li> <a href="//skarnet.org/software/skalibs/">skalibs</a> version
+2.9.1.0 or later </li>
+ <li> <a href="//skarnet.org/software/execline/">execline</a> version
+2.6.0.0 or later </li>
+ <li> <a href="//skarnet.org/software/s6/">s6</a> version
+2.9.0.1 or later </li>
+ <li> <a href="//skarnet.org/software/s6-rc/">s6-rc</a> version
+0.5.1.1 or later </li>
+ <li> <a href="//skarnet.org/software/s6-linux-init/">s6-linux-init</a> version
+1.0.3.1 or later </li>
+</ul>
+
+<p>
+ Those are all build-time dependencies as well as run-time dependencies.
+skalibs is only a run-time dependency if you link the binaries against
+the shared version of the skarnet library.
+</p>
+
+<h3> Licensing </h3>
+
+<p>
+ s6-frontend is free software. It is available under the
+<a href="http://opensource.org/licenses/ISC">ISC license</a>.
+</p>
+
+<h3> Download </h3>
+
+<ul>
+ <li> The current released version of s6-frontend is
+<a href="s6-frontend-0.0.1.0.tar.gz">0.0.1.0</a>. <strong><red>(unavailable while in development)</red></strong> </li>
+ <li> Alternatively, you can checkout a copy of the
+<a href="//git.skarnet.org/cgi-bin/cgit.cgi/s6-frontend/">s6-frontend
+git repository</a>:
+<pre> git clone git://git.skarnet.org/s6-frontend </pre> </li>
+ <li> There's also a
+<a href="https://github.com/skarnet/s6-frontend">GitHub mirror</a>
+of the s6-frontend git repository. </li>
+</ul>
+
+<h3> Compilation </h3>
+
+<ul>
+ <li> See the enclosed INSTALL file for installation details. </li>
+</ul>
+
+<h3> Upgrade notes </h3>
+
+<ul>
+ <li> <a href="upgrade.html">This page</a> lists the differences to be aware of between
+the previous versions of s6-frontend and the current one. </li>
+</ul>
+
+<hr />
+
+<h2> Reference </h2>
+
+<h3> Commands </h3>
+
+<p>
+ All these commands exit 111 if they encounter a temporary error, and
+100 if they encounter a permanent error - such as a misuse.
+</p>
+
+<ul>
+ <li> The <a href="s6-frontend-config-preprocess.html"><tt>s6-frontend-config-preprocess</tt></a> program </li>
+ <li> The <a href="s6-frontend-alias.html"><tt>s6-frontend-alias</tt></a> program </li>
+ <li> The <a href="s6-frontend-alias-chpst.html"><tt>s6-frontend-alias-chpst</tt></a> program </li>
+ <li> The <a href="s6-frontend-alias-sv.html"><tt>s6-frontend-alias-sv</tt></a> program </li>
+</ul>
+
+<h2> Related resources </h2>
+
+<ul>
+ <li> <tt>s6-frontend</tt> is discussed on the
+<a href="//skarnet.org/lists.html#supervision">supervision</a> mailing-list. </li>
+ <li> There is a <tt>#s6</tt> IRC channel on Freenode. Sometimes people
+are there and even answer questions. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/quickstart.html b/doc/quickstart.html
new file mode 100644
index 0000000..6c99510
--- /dev/null
+++ b/doc/quickstart.html
@@ -0,0 +1,26 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-frontend: quickstart and FAQ</title>
+ <meta name="Description" content="s6-frontend: quickstart and FAQ" />
+ <meta name="Keywords" content="s6-frontend installation quickstart faq" />
+ <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6-frontend</a><br />
+<a href="//skarnet.org/software/">Software</a><br />
+<a href="//skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> Quickstart and FAQ for s6-frontend </h1>
+
+<p>
+ (To be written.)
+</p>
+
+</body>
+</html>
diff --git a/doc/s6-frontend-alias.html b/doc/s6-frontend-alias.html
new file mode 100644
index 0000000..4e824c9
--- /dev/null
+++ b/doc/s6-frontend-alias.html
@@ -0,0 +1,41 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-frontend: the s6-frontend-alias program</title>
+ <meta name="Description" content="s6-frontend: the s6-frontend-alias program" />
+ <meta name="Keywords" content="s6 command s6-frontend-alias daemontools runit" />
+ <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6-frontend</a><br />
+<a href="//skarnet.org/software/">Software</a><br />
+<a href="//skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-frontend-alias program </h1>
+
+<p>
+s6-frontend-alias
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-frontend-alias
+</pre>
+
+<p>
+</p>
+
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-v</tt>&nbsp;: verbose. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-frontend-config-preprocess.html b/doc/s6-frontend-config-preprocess.html
new file mode 100644
index 0000000..f58ff7c
--- /dev/null
+++ b/doc/s6-frontend-config-preprocess.html
@@ -0,0 +1,87 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-frontend: the s6-frontend-config-preprocess program</title>
+ <meta name="Description" content="s6-frontend: the s6-frontend-config-preprocess program" />
+ <meta name="Keywords" content="s6-frontend command s6 configuration unit file s6-frontend-config preprocess preprocessor" />
+ <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6</a><br />
+<a href="//skarnet.org/software/">Software</a><br />
+<a href="//skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The s6-frontend-config-preprocess program </h1>
+
+<p>
+ <tt>s6-frontend-config-preprocess</tt> reads a s6-frontend configuration
+file and executes all its inclusion directives, also preprocessing the
+included files. It streams the result to stdout, which is a complete
+configuration file without inclusions.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+ s6-frontend-config-preprocess <em>file</em>
+</pre>
+
+<p>
+ <tt>s6-frontend-config-preprocess reads <em>file</em> and prints it
+to stdout. It removes lines starting with <tt>!!</tt>.
+</p>
+
+<p>
+ When it finds a <tt>!include</tt> or <tt>!includeonce</tt> directive
+in <em>file</em>, it replaces it with the contents of the included
+file - recursively preprocessed.
+</p>
+
+<p>
+ When it finds a <tt>!includedir</tt> or <tt>!includedironce</tt>
+directive in <em>file</em>, it replaces it with the recursively
+preprocessed contents of every file present in the included
+directory. The files are sorted alphabetically according to the
+C locale.
+</p>
+
+<p>
+ <tt>!includeonce</tt> and <tt>!includedironce</tt> only print
+a file (resp. a directory) the first time they encounter it, and
+silently ignore subsequent instances. <tt>!include</tt> and
+<tt>!includedir</tt> directives will happily include the same
+files several times.
+</p>
+
+<p>
+ To avoid loops, a nesting limit exists. <tt>s6-frontend-config-preprocess</tt>
+will fail if there are too many nested inclusions.
+</p>
+
+<h2> Exit codes </h2>
+
+<ul>
+ <li> 0: success </li>
+ <li> 1: syntax error in a configuration file </li>
+ <li> 2: other error in a configuration file </li>
+ <li> 3: too many nested inclusions </li>
+ <li> 100: usage error </li>
+ <li> 111: system call failed </li>
+</ul>
+
+<h2> Notes </h2>
+
+<ul>
+ <li> <tt>s6-frontend-config-preprocess</tt> is not meant to be
+called directly by the user. It is normally invoked by
+<a href="s6-frontend-config-parse.html">s6-frontend-config-parse</a>.
+However, the binary is made available for debugging purposes. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/upgrade.html b/doc/upgrade.html
new file mode 100644
index 0000000..24f7bfb
--- /dev/null
+++ b/doc/upgrade.html
@@ -0,0 +1,28 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>s6-frontend: how to upgrade</title>
+ <meta name="Description" content="s6-frontend: how to upgrade" />
+ <meta name="Keywords" content="s6-frontend installation upgrade" />
+ <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6-frontend</a><br />
+<a href="//skarnet.org/software/">Software</a><br />
+<a href="//skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> What has changed in s6-frontend </h1>
+
+<h2> in 0.0.1.0 </h2>
+
+<ul>
+ <li> Initial release. </li>
+</ul>
+
+</body>
+</html>
diff --git a/package/deps-build b/package/deps-build
new file mode 100644
index 0000000..cc1abb1
--- /dev/null
+++ b/package/deps-build
@@ -0,0 +1,4 @@
+/package/prog/skalibs
+/package/admin/execline
+/package/admin/s6
+/package/admin/s6-rc
diff --git a/package/deps.mak b/package/deps.mak
new file mode 100644
index 0000000..ec41fd5
--- /dev/null
+++ b/package/deps.mak
@@ -0,0 +1,17 @@
+#
+# This file has been generated by tools/gen-deps.sh
+#
+
+src/alias/s6-frontend-alias-chpst.o src/alias/s6-frontend-alias-chpst.lo: src/alias/s6-frontend-alias-chpst.c
+src/alias/s6-frontend-alias-sv.o src/alias/s6-frontend-alias-sv.lo: src/alias/s6-frontend-alias-sv.c
+src/alias/s6-frontend-alias.o src/alias/s6-frontend-alias.lo: src/alias/s6-frontend-alias.c src/include/s6-frontend/config.h
+src/config/s6-frontend-config-preprocess.o src/config/s6-frontend-config-preprocess.lo: src/config/s6-frontend-config-preprocess.c
+
+s6-frontend-alias: EXTRA_LIBS := -lskarnet
+s6-frontend-alias: src/alias/s6-frontend-alias.o
+s6-frontend-alias-chpst: EXTRA_LIBS := -lskarnet
+s6-frontend-alias-chpst: src/alias/s6-frontend-alias-chpst.o
+s6-frontend-alias-sv: EXTRA_LIBS := -ls6 -lskarnet ${SPAWN_LIB}
+s6-frontend-alias-sv: src/alias/s6-frontend-alias-sv.o
+s6-frontend-config-preprocess: EXTRA_LIBS := -lskarnet
+s6-frontend-config-preprocess: src/config/s6-frontend-config-preprocess.o
diff --git a/package/info b/package/info
new file mode 100644
index 0000000..f0b5985
--- /dev/null
+++ b/package/info
@@ -0,0 +1,4 @@
+package=s6-frontend
+version=0.0.1.0
+category=admin
+package_macro_name=S6_FRONTEND
diff --git a/package/modes b/package/modes
new file mode 100644
index 0000000..8e2e6cf
--- /dev/null
+++ b/package/modes
@@ -0,0 +1,4 @@
+s6-frontend-config-preprocess 0755
+s6-frontend-alias 0755
+s6-frontend-alias-sv 0755
+s6-frontend-alias-chpst 0755
diff --git a/package/targets.mak b/package/targets.mak
new file mode 100644
index 0000000..5767606
--- /dev/null
+++ b/package/targets.mak
@@ -0,0 +1,75 @@
+BIN_TARGETS := \
+s6-frontend-config-preprocess
+
+LIBEXEC_TARGETS :=
+
+WRAP_ANY :=
+
+ifdef WRAP_DAEMONTOOLS
+
+DAEMONTOOLS_TARGETS := \
+envdir \
+envuidgid \
+fghack \
+multilog \
+pgrphack \
+readproctitle \
+setlock \
+setuidgid \
+softlimit \
+supervise \
+svc \
+svok \
+svscan \
+svscanboot \
+svstat \
+tai64n \
+tai64nlocal
+
+install-bin: $(DAEMONTOOLS_TARGETS:%=$(DESTDIR)$(bindir)/%)
+
+ifneq ($(exthome),)
+global-links: $(DAEMONTOOLS_TARGETS:%=$(DESTDIR)$(sproot)/command/%)
+endif
+
+WRAP_ANY := 1
+
+endif
+
+ifdef WRAP_RUNIT
+
+RUNIT_TARGETS := \
+runit \
+runit-init \
+runsv \
+runsvchdir \
+runsvdir \
+svlogd \
+utmpset
+
+RUNIT_SPECIAL_TARGETS := chpst sv
+BIN_TARGETS += s6-frontend-alias-sv s6-frontend-alias-chpst
+
+install-bin: $(RUNIT_TARGETS:%=$(DESTDIR)$(bindir)/%) $(RUNIT_SPECIAL_TARGETS:%=$(DESTDIR)$(bindir)/%)
+
+ifneq ($(exthome),)
+global-links: $(RUNIT_TARGETS:%=$(DESTDIR)$(sproot)/command/%) $(RUNIT_SPECIAL_TARGETS:%=$(DESTDIR)$(sproot)/command/%)
+endif
+
+WRAP_ANY := 1
+
+$(DESTDIR)$(bindir)/chpst: $(DESTDIR)$(bindir)/s6-frontend-alias-chpst
+ exec $(INSTALL) -D -l s6-frontend-alias-chpst $@
+$(DESTDIR)$(bindir)/sv: $(DESTDIR)$(bindir)/s6-frontend-alias-sv
+ exec $(INSTALL) -D -l s6-frontend-alias-sv $@
+
+endif
+
+ifdef WRAP_ANY
+
+BIN_TARGETS += s6-frontend-alias
+
+$(DAEMONTOOLS_TARGETS:%=$(DESTDIR)$(bindir)/%) $(RUNIT_TARGETS:%=$(DESTDIR)$(bindir)/%): $(DESTDIR)$(bindir)/s6-frontend-alias
+ exec $(INSTALL) -D -l s6-frontend-alias $@
+
+endif
diff --git a/src/alias/deps-exe/s6-frontend-alias b/src/alias/deps-exe/s6-frontend-alias
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/alias/deps-exe/s6-frontend-alias
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/alias/deps-exe/s6-frontend-alias-chpst b/src/alias/deps-exe/s6-frontend-alias-chpst
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/alias/deps-exe/s6-frontend-alias-chpst
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/alias/deps-exe/s6-frontend-alias-sv b/src/alias/deps-exe/s6-frontend-alias-sv
new file mode 100644
index 0000000..b3e8440
--- /dev/null
+++ b/src/alias/deps-exe/s6-frontend-alias-sv
@@ -0,0 +1,3 @@
+-ls6
+-lskarnet
+${SPAWN_LIB}
diff --git a/src/alias/s6-frontend-alias-chpst.c b/src/alias/s6-frontend-alias-chpst.c
new file mode 100644
index 0000000..860654e
--- /dev/null
+++ b/src/alias/s6-frontend-alias-chpst.c
@@ -0,0 +1,347 @@
+ /* ISC license. */
+
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <skalibs/uint64.h>
+#include <skalibs/types.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/buffer.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/env.h>
+#include <skalibs/djbunix.h>
+
+#include <execline/config.h>
+
+#include <s6/config.h>
+
+#define USAGE "s6-frontend-alias-chpst [ -v ] [ -P ] [ -0 ] [ -1 ] [ -2 ] [ -u user ] [ -U user ] [ -b argv0 ] [ -e dir ] [ -n niceness ] [ -l lock | -L lock ] [ -m bytes ] [ -d bytes ] [ -o n ] [ -p n ] [ -f bytes ] [ -c bytes ] prog..."
+
+#define dienomem() strerr_diefu1sys(111, "stralloc_catb")
+#define dieusage() strerr_dieusage(100, USAGE)
+
+static unsigned int verbosity = 0 ;
+
+static void printit (char const *const *argv)
+{
+ buffer_puts(buffer_2, PROG) ;
+ buffer_puts(buffer_2, ": info: executing the following command line:") ;
+ for (; *argv ; argv++)
+ {
+ buffer_puts(buffer_2, " ") ;
+ buffer_puts(buffer_2, *argv) ;
+ }
+ buffer_putsflush(buffer_2, "\n") ;
+}
+
+static inline size_t parseuggnum (char const *s, uint32_t *flags, uid_t *uid, gid_t *gid, gid_t *tab)
+{
+ size_t n = 0 ;
+ size_t pos = uid_scan(s, uid) ;
+ if (!pos) dieusage() ;
+ if (!s[pos]) return 0 ;
+ if (s[pos] != ':') dieusage() ;
+ s += pos+1 ;
+ pos = gid_scan(s, gid) ;
+ if (!pos) dieusage() ;
+ *flags |= 32768 ;
+ if (!s[pos]) return 0 ;
+ if (s[pos] != ':') dieusage() ;
+ s += pos+1 ;
+ if (!gid_scanlist(tab, NGROUPS_MAX, s, &n)) dieusage() ;
+ return n ;
+}
+
+static struct passwd *do_getpwnam (char const *s)
+{
+ struct passwd *pw = getpwnam(s) ;
+ if (!pw)
+ {
+ if (errno) strerr_diefu1sys(111, "read user database") ;
+ else strerr_dief2x(100, "user not found in user database: ", s) ;
+ }
+ return pw ;
+}
+
+static struct group *do_getgrnam (char const *s)
+{
+ struct group *gr = getgrnam(s) ;
+ if (!gr)
+ {
+ if (errno) strerr_diefu1sys(111, "read group database") ;
+ else strerr_dief2x(100, "group not found in group database: ", s) ;
+ }
+ return gr ;
+}
+
+static inline size_t parseuggsym (char const *s, uint32_t *flags, uid_t *uid, gid_t *gid, gid_t *tab)
+{
+ size_t n = 0 ;
+ struct passwd *pw ;
+ struct group *gr ;
+ size_t pos = str_chr(s, ':') ;
+ *flags |= 32768 ;
+ errno = 0 ;
+ if (!s[pos]) pw = do_getpwnam(s) ;
+ else
+ {
+ char tmp[pos+1] ;
+ memcpy(tmp, s, pos) ;
+ tmp[pos] = 0 ;
+ pw = do_getpwnam(tmp) ;
+ }
+ *uid = pw->pw_uid ;
+ if (!s[pos])
+ {
+ *gid = pw->pw_gid ;
+ return 0 ;
+ }
+ s += pos+1 ;
+ pos = str_chr(s, ':') ;
+ errno = 0 ;
+ if (!s[pos]) gr = do_getgrnam(s) ;
+ else
+ {
+ char tmp[pos+1] ;
+ memcpy(tmp, s, pos) ;
+ tmp[pos] = 0 ;
+ gr = do_getgrnam(tmp) ;
+ }
+ *gid = gr->gr_gid ;
+ if (!s[pos]) return 0 ;
+ s += pos+1 ;
+ while (*s)
+ {
+ if (n >= NGROUPS_MAX)
+ strerr_dief1x(100, "too many supplementary groups listed for the -u option") ;
+ pos = str_chr(s, ':') ;
+ errno = 0 ;
+ if (!s[pos]) gr = do_getgrnam(s) ;
+ else
+ {
+ char tmp[pos+1] ;
+ memcpy(tmp, s, pos) ;
+ tmp[pos] = 0 ;
+ gr = do_getgrnam(tmp) ;
+ }
+ tab[n++] = gr->gr_gid ;
+ s += s[pos] ? pos+1 : pos ;
+ }
+ return n ;
+}
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ static char const *valopt[6] = { "-m", "-d", "-o", "-p", "-f", "-c" } ;
+ genalloc envdirs = GENALLOC_ZERO ; /* char const * */
+ stralloc newroot = STRALLOC_ZERO ;
+ unsigned int newargc = 0 ;
+ char const *argv0 = 0 ;
+ char const *lockfile = 0 ;
+ char const *envug = 0 ;
+ uint32_t flags = 0 ;
+ int niceval = 0 ;
+ char valfmt[6][UINT64_FMT] ;
+ char nicefmt[INT_FMT] ;
+ char uidfmt[UID_FMT] ;
+ char gidfmt[GID_FMT] ;
+ char gidlistfmt[GID_FMT * NGROUPS_MAX] ;
+ PROG = "s6-frontend-alias-chpst" ;
+
+ {
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ int opt = subgetopt_r(argc, argv, "vP012u:U:b:e:/:n:l:L:m:d:o:p:f:c:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 'v' : verbosity++ ; break ;
+ case '0' : flags |= 1 ; newargc += 2 ; break ;
+ case '1' : flags |= 2 ; newargc += 2 ; break ;
+ case '2' : flags |= 4 ; newargc += 2 ; break ;
+ case 'P' : flags |= 8 ; newargc += 2 ; break ;
+ case 'b' : argv0 = l.arg ; newargc += 4 ; break ;
+ case 'u' :
+ {
+ size_t n ;
+ uid_t uid ;
+ gid_t gid ;
+ gid_t tab[NGROUPS_MAX] ;
+ newargc += 6 ;
+ flags |= 16384 ; flags &= ~32768 ;
+ n = l.arg[0] == ':' ?
+ parseuggnum(l.arg + 1, &flags, &uid, &gid, tab) :
+ parseuggsym(l.arg, &flags, &uid, &gid, tab) ;
+ uidfmt[uid_fmt(uidfmt, uid)] = 0 ;
+ if (flags & 32768)
+ {
+ newargc += 2 ;
+ gidfmt[gid_fmt(gidfmt, gid)] = 0 ;
+ }
+ gidlistfmt[gid_fmtlist(gidlistfmt, tab, n)] = 0 ;
+ break ;
+ }
+ case 'U' :
+ envug = l.arg ;
+ newargc += 3 ;
+ if (envug[0] == ':') { flags |= 4096 ; envug++ ; newargc++ ; } else flags &= ~4096 ;
+ if (strchr(envug, ':')) { flags |= 8192 ; newargc++ ; } else flags &= ~8192 ;
+ break ;
+ case 'e' :
+ if (!genalloc_append(char const *, &envdirs, &l.arg)) dienomem() ;
+ newargc += 3 ;
+ break ;
+ case '/' :
+ newroot.len = 0 ;
+ if (sarealpath(&newroot, l.arg) < 0 || !stralloc_0(&newroot)) dienomem() ;
+ newargc += 2 ;
+ break ;
+ case 'n' :
+ if (!int0_scan(l.arg, &niceval)) dieusage() ;
+ newargc += 3 ;
+ break ;
+ case 'l' : lockfile = l.arg ; flags &= ~16 ; newargc += 4 ; break ;
+ case 'L' : lockfile = l.arg ; flags |= 16 ; newargc += 4 ; break ;
+ case 'm' :
+ case 'd' :
+ case 'o' :
+ case 'p' :
+ case 'f' :
+ case 'c' :
+ {
+ uint64_t val ;
+ size_t pos = byte_chr("mdopfc", 6, opt) ;
+ if (!uint640_scan(l.arg, &val)) dieusage() ;
+ valfmt[pos][uint64_fmt(valfmt[pos], val)] = 0 ;
+ flags |= 32 | (1 << (6 + pos)) ;
+ newargc += 2 ;
+ break ;
+ }
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ }
+
+ if (flags & 32) newargc += 2 ;
+ newargc += argc ;
+
+ {
+ unsigned int m = 0 ;
+ char const *newargv[newargc + 1] ;
+
+ if (niceval)
+ {
+ nicefmt[int_fmt(nicefmt, niceval)] = 0 ;
+ newargv[m++] = "nice" ;
+ newargv[m++] = "-n" ;
+ newargv[m++] = nicefmt ;
+ newargv[m++] = "--" ;
+ }
+
+ if (flags & 8)
+ {
+ newargv[m++] = S6_EXTBINPREFIX "s6-setsid" ;
+ newargv[m++] = "--" ;
+ }
+
+ if (genalloc_len(char const *, &envdirs))
+ {
+ for (size_t i = 0 ; i < genalloc_len(char const *, &envdirs) ; i++)
+ {
+ newargv[m++] = S6_EXTBINPREFIX "s6-envdir" ;
+ newargv[m++] = "--" ;
+ newargv[m++] = genalloc_s(char const *, &envdirs)[i] ;
+ }
+ }
+
+ if (lockfile)
+ {
+ newargv[m++] = S6_EXTBINPREFIX "s6-setlock" ;
+ newargv[m++] = flags & 16 ? "-n" : "-N" ;
+ newargv[m++] = "--" ;
+ newargv[m++] = lockfile ;
+ }
+
+ if (flags & 16384)
+ {
+ newargv[m++] = S6_EXTBINPREFIX "s6-applyuidgid" ;
+ newargv[m++] = "-u" ;
+ newargv[m++] = uidfmt ;
+ if (flags & 32768)
+ {
+ newargv[m++] = "-g" ;
+ newargv[m++] = gidfmt ;
+ }
+ newargv[m++] = "-G" ;
+ newargv[m++] = gidlistfmt ;
+ newargv[m++] = "--" ;
+ }
+
+ if (envug)
+ {
+ newargv[m++] = S6_EXTBINPREFIX "s6-envuidgid" ;
+ if (flags & 4096) newargv[m++] = "-n" ;
+ if (flags & 8192) newargv[m++] = "-B" ;
+ newargv[m++] = "--" ;
+ newargv[m++] = envug ;
+ }
+
+ if (flags & 32)
+ {
+ newargv[m++] = S6_EXTBINPREFIX "s6-softlimit" ;
+ for (unsigned int i = 0 ; i < 6 ; i++) if (flags & (1 << (i + 6)))
+ {
+ newargv[m++] = valopt[i] ;
+ newargv[m++] = valfmt[i] ;
+ }
+ newargv[m++] = "--" ;
+ }
+
+ if (flags & 1)
+ {
+ newargv[m++] = EXECLINE_EXTBINPREFIX "fdclose" ;
+ newargv[m++] = "0" ;
+ }
+
+ if (flags & 2)
+ {
+ newargv[m++] = EXECLINE_EXTBINPREFIX "fdclose" ;
+ newargv[m++] = "1" ;
+ }
+
+ if (flags & 4)
+ {
+ newargv[m++] = EXECLINE_EXTBINPREFIX "fdclose" ;
+ newargv[m++] = "2" ;
+ }
+
+ if (argv0)
+ {
+ newargv[m++] = EXECLINE_BINPREFIX "exec" ;
+ newargv[m++] = "-a" ;
+ newargv[m++] = argv0 ;
+ newargv[m++] = "--" ;
+ }
+
+ if (newroot.s)
+ {
+ newargv[m++] = "chroot" ;
+ newargv[m++] = newroot.s ;
+ if (argv0) strerr_warnw1x("the -b option is ineffective when the -/ option is also given") ;
+ }
+
+ for (int i = 0 ; i < argc+1 ; i++) newargv[m++] = argv[i] ;
+ if (verbosity) printit(newargv) ;
+ xpathexec0_run(newargv, envp) ;
+ }
+}
diff --git a/src/alias/s6-frontend-alias-sv.c b/src/alias/s6-frontend-alias-sv.c
new file mode 100644
index 0000000..e6e0ec8
--- /dev/null
+++ b/src/alias/s6-frontend-alias-sv.c
@@ -0,0 +1,377 @@
+ /* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <skalibs/uint32.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/djbunix.h>
+
+#include <s6/config.h>
+#include <s6/s6-supervise.h>
+
+#define USAGE "s6-frontend-alias-sv [ -v ] [ -w sec ] command services..."
+#define dieusage() strerr_dieusage(100, USAGE)
+#define dienomem() strerr_diefu1sys(111, "stralloc_catb")
+
+typedef int execfunc_t (char const *, char const *const *) ;
+typedef execfunc_t *execfunc_t_ref ;
+
+typedef struct info_s info_t, *info_t_ref ;
+struct info_s
+{
+ char const *name ;
+ execfunc_t_ref f ;
+} ;
+
+static int dowait = 0 ;
+static uint32_t secs = 7 ;
+
+static void warnnolog (void)
+{
+ strerr_warnw1x("s6-svc only sends commands to a single service, even if it has a dedicated logger") ;
+}
+
+static void warnnokill (void)
+{
+ strerr_warnw1x("s6-supervise pilots a kill signal via the timeout-kill file in the service directory") ;
+}
+
+static int info_cmp (void const *a, void const *b)
+{
+ char const *name = a ;
+ info_t const *info = b ;
+ return strcmp(name, info->name) ;
+}
+
+static int spawnit (char const *const *argv, char const *const *envp)
+{
+ int wstat ;
+ pid_t r ;
+ pid_t pid = child_spawn0(argv[0], argv, envp) ;
+ if (!pid)
+ {
+ strerr_warnwu2sys("spawn ", argv[0]) ;
+ return 1 ;
+ }
+ r = wait_pid(pid, &wstat) ;
+ if (r != pid)
+ {
+ strerr_warnwu2sys("wait for ", argv[0]) ;
+ return 1 ;
+ }
+ return !!WIFSIGNALED(wstat) || !!WEXITSTATUS(wstat) ;
+}
+
+static int simple_svc (char const *dir, char const *options, char const *const *envp)
+{
+ char const *argv[5] = { S6_EXTBINPREFIX "s6-svc", options, "--", dir, 0 } ;
+ return spawnit(argv, envp) ;
+}
+
+static int complex_svc (char const *dir, char const *order, char waitfor, char const *const *envp)
+{
+ char warg[4] = "-w?" ;
+ char fmt[2 + UINT32_FMT] = "-T" ;
+ char const *argv[7] = { S6_EXTBINPREFIX "s6-svc", warg, fmt, order, "--", dir, 0 } ;
+ fmt[2 + uint32_fmt(fmt + 2, 1000 * secs)] = 0 ;
+ warg[2] = waitfor ;
+ return spawnit(argv, envp) ;
+}
+
+static int status (char const *dir, char const *const *envp)
+{
+ char const *argv[4] = { S6_EXTBINPREFIX "s6-svstat", "--", dir, 0 } ;
+ return spawnit(argv, envp) ;
+}
+
+static int usr1_h (char const *dir, char const *const *envp)
+{
+ return simple_svc(dir, "-1", envp) ;
+}
+
+static int usr2_h (char const *dir, char const *const *envp)
+{
+ return simple_svc(dir, "-2", envp) ;
+}
+
+static int alarm_h (char const *dir, char const *const *envp)
+{
+ return simple_svc(dir, "-a", envp) ;
+}
+
+static int cont_h (char const *dir, char const *const *envp)
+{
+ if (dowait)
+ {
+ complex_svc(dir, "-o", 'U', envp) ;
+ return status(dir, envp) ;
+ }
+ else return simple_svc(dir, "-c", envp) ;
+}
+
+static int down (char const *dir, char const *const *envp)
+{
+ if (dowait)
+ {
+ complex_svc(dir, "-d", 'D', envp) ;
+ return status(dir, envp) ;
+ }
+ else return simple_svc(dir, "-d", envp) ;
+}
+
+static int bail (char const *dir, char const *const *envp)
+{
+ warnnolog() ;
+ if (dowait)
+ {
+ complex_svc(dir, "-d", 'D', envp) ;
+ status(dir, envp) ;
+ }
+ return simple_svc(dir, "-xd", envp) ;
+}
+
+static int hup_h (char const *dir, char const *const *envp)
+{
+ return simple_svc(dir, "-h", envp) ;
+}
+
+static int int_h (char const *dir, char const *const *envp)
+{
+ return simple_svc(dir, "-i", envp) ;
+}
+
+static int kill_h (char const *dir, char const *const *envp)
+{
+ return simple_svc(dir, "-k", envp) ;
+}
+
+static int once (char const *dir, char const *const *envp)
+{
+ if (dowait)
+ {
+ complex_svc(dir, "-o", 'U', envp) ;
+ return status(dir, envp) ;
+ }
+ else return simple_svc(dir, "-o", envp) ;
+}
+
+static int pause_h (char const *dir, char const *const *envp)
+{
+ return simple_svc(dir, "-p", envp) ;
+}
+
+static int quit_h (char const *dir, char const *const *envp)
+{
+ return simple_svc(dir, "-q", envp) ;
+}
+
+static int term_h (char const *dir, char const *const *envp)
+{
+ if (dowait)
+ {
+ complex_svc(dir, "-r", 'R', envp) ;
+ return status(dir, envp) ;
+ }
+ else return simple_svc(dir, "-t", envp) ;
+}
+
+static int up (char const *dir, char const *const *envp)
+{
+ if (dowait)
+ {
+ complex_svc(dir, "-u", 'U', envp) ;
+ return status(dir, envp) ;
+ }
+ else return simple_svc(dir, "-u", envp) ;
+}
+
+static int check (char const *dir, char const *const *envp)
+{
+ s6_svstatus_t svst ;
+ char warg[3] = "-?" ;
+ char fmt[2 + UINT32_FMT] = "-t" ;
+ char const *argv[6] = { S6_EXTBINPREFIX "s6-svwait", warg, fmt, "--", dir, 0 } ;
+ fmt[2 + uint32_fmt(fmt + 2, 1000 * secs)] = 0 ;
+ if (!s6_svstatus_read(dir, &svst)) return 1 ;
+ warg[1] = svst.flagwantup ? 'U' : 'D' ;
+ spawnit(argv, envp) ;
+ return status(dir, envp) ;
+}
+
+static int lsb_reload (char const *dir, char const *const *envp)
+{
+ hup_h(dir, envp) ;
+ return status(dir, envp) ;
+}
+
+static int lsb_restart (char const *dir, char const *const *envp)
+{
+ complex_svc(dir, "-ru", 'U', envp) ;
+ return status(dir, envp) ;
+}
+
+static int lsb_start (char const *dir, char const *const *envp)
+{
+ complex_svc(dir, "-u", 'U', envp) ;
+ return status(dir, envp) ;
+}
+
+static int lsb_stop (char const *dir, char const *const *envp)
+{
+ complex_svc(dir, "-d", 'D', envp) ;
+ return status(dir, envp) ;
+}
+
+static int lsb_shutdown (char const *dir, char const *const *envp)
+{
+ warnnolog() ;
+ complex_svc(dir, "-d", 'D', envp) ;
+ status(dir, envp) ;
+ return simple_svc(dir, "-x", envp) ;
+}
+
+static int lsb_forcereload (char const *dir, char const *const *envp)
+{
+ warnnokill() ;
+ return lsb_reload(dir, envp) ;
+}
+
+static int lsb_forcerestart (char const *dir, char const *const *envp)
+{
+ warnnokill() ;
+ return lsb_restart(dir, envp) ;
+}
+
+static int lsb_forcestop (char const *dir, char const *const *envp)
+{
+ warnnokill() ;
+ return lsb_stop(dir, envp) ;
+}
+
+static int lsb_forceshutdown (char const *dir, char const *const *envp)
+{
+ warnnokill() ;
+ return lsb_shutdown(dir, envp) ;
+}
+
+static int lsb_tryrestart (char const *dir, char const *const *envp)
+{
+ s6_svstatus_t svst ;
+ if (s6_svstatus_read(dir, &svst) && svst.flagwantup && svst.pid && !svst.flagfinishing)
+ complex_svc(dir, "-r", 'U', envp) ;
+ return status(dir, envp) ;
+}
+
+static info_t const commands[] =
+{
+ { .name = "1", .f = &usr1_h },
+ { .name = "2", .f = &usr2_h },
+ { .name = "a", .f = &alarm_h },
+ { .name = "alarm", .f = &alarm_h },
+ { .name = "c", .f = &cont_h },
+ { .name = "check", .f = &check },
+ { .name = "cont", .f = &cont_h },
+ { .name = "d", .f = &down },
+ { .name = "down", .f = &down },
+ { .name = "e", .f = &bail },
+ { .name = "exit", .f = &bail },
+ { .name = "force-reload", .f = &lsb_forcereload },
+ { .name = "force-restart", .f = &lsb_forcerestart },
+ { .name = "force-shutdown", .f = &lsb_forceshutdown },
+ { .name = "force-stop", .f = &lsb_forcestop },
+ { .name = "h", .f = &hup_h },
+ { .name = "hup", .f = &hup_h },
+ { .name = "i", .f = &int_h },
+ { .name = "interrupt", .f = &int_h },
+ { .name = "k", .f = &kill_h },
+ { .name = "kill", .f = &kill_h },
+ { .name = "o", .f = &once },
+ { .name = "once", .f = &once },
+ { .name = "p", .f = &pause_h },
+ { .name = "pause", .f = &pause_h },
+ { .name = "q", .f = &quit_h },
+ { .name = "quit", .f = &quit_h },
+ { .name = "reload", .f = &lsb_reload },
+ { .name = "restart", .f = &lsb_restart },
+ { .name = "s", .f = &status },
+ { .name = "shutdown", .f = &lsb_shutdown },
+ { .name = "start", .f = &lsb_start },
+ { .name = "status", .f = &status },
+ { .name = "stop", .f = &lsb_stop },
+ { .name = "t", .f = &term_h },
+ { .name = "term", .f = &term_h },
+ { .name = "try-restart", .f = &lsb_tryrestart },
+ { .name = "u", .f = &up },
+ { .name = "up", .f = &up }
+} ;
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ int e = 0 ;
+ info_t *p ;
+ char const *x = getenv("SVWAIT") ;
+ char const *scandir = getenv("SVDIR") ;
+ size_t scandirlen ;
+ PROG = "s6-frontend-alias-sv" ;
+ if (!scandir) scandir = "/run/service" ; /* TODO: infer from s6li config */
+ scandirlen = strlen(scandir) ;
+ if (x)
+ {
+ if (!uint320_scan(x, &secs))
+ strerr_warnw1x("invalid SVWAIT value") ;
+ }
+
+ {
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ int opt = subgetopt_r(argc, argv, "vw:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 'v' : dowait = 1 ; break ;
+ case 'w' : if (!uint320_scan(l.arg, &secs)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ }
+
+ if (argc < 2) dieusage() ;
+ p = bsearch(argv[0], commands, sizeof(commands) / sizeof(info_t), sizeof(info_t), &info_cmp) ;
+ if (!p) strerr_dief2x(100, "unknown command: ", argv[0]) ;
+
+ for (argv++ ; *argv ; argv++)
+ {
+ if ((argv[0][0] == '.' && (argv[0][1] == '/' || (argv[0][1] == '.' && argv[0][2] == '/'))) || argv[0][0] == '/')
+ e += (*p->f)(*argv, envp) ;
+ else
+ {
+ int what = 1 ;
+ struct stat st ;
+ size_t len = strlen(*argv) ;
+ char fn[scandirlen + len + 2] ;
+ memcpy(fn, scandir, scandirlen) ;
+ fn[scandirlen] = '/' ;
+ memcpy(fn + scandirlen + 1, *argv, len + 1) ;
+ if (stat(fn, &st) < 0) /* XXX: TOCTOU but we don't care */
+ {
+ if (errno != ENOENT)
+ {
+ e++ ;
+ what = 0 ;
+ strerr_warnwu2sys("stat ", fn) ;
+ }
+ }
+ else if (S_ISDIR(st.st_mode)) what = 2 ;
+ if (what) e += (*p->f)(what > 1 ? fn : *argv, envp) ;
+ }
+ }
+ return e ;
+}
diff --git a/src/alias/s6-frontend-alias.c b/src/alias/s6-frontend-alias.c
new file mode 100644
index 0000000..7467632
--- /dev/null
+++ b/src/alias/s6-frontend-alias.c
@@ -0,0 +1,235 @@
+ /* ISC license. */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <skalibs/buffer.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/skamisc.h>
+
+#include <s6/config.h>
+
+#include <s6-frontend/config.h>
+
+#define USAGE "s6-frontend-alias [ -v ] cmdname options..."
+#define dienomem() strerr_diefu1sys(111, "stralloc_catb")
+#define dieusage() strerr_dieusage(100, USAGE)
+
+static unsigned int verbosity = 0 ;
+
+typedef void execfunc_t (int, char const *const *, char const *const *) ;
+typedef execfunc_t *execfunc_t_ref ;
+
+typedef struct info_s info_t, *info_t_ref ;
+struct info_s
+{
+ char const *name ;
+ char const *cmd ;
+ execfunc_t_ref f ;
+} ;
+
+static int info_cmp (void const *a, void const *b)
+{
+ char const *name = a ;
+ info_t const *info = b ;
+ return strcmp(name, info->name) ;
+}
+
+#if defined(S6_FRONTEND_WRAP_DAEMONTOOLS) || defined (S6_FRONTEND_WRAP_RUNIT)
+static void noboot (char const *name)
+{
+ strerr_dief3x(100, "s6 does not provide a ", name, " emulation. To boot on a s6 supervision tree, please consider the s6-linux-init package.") ;
+}
+#endif
+
+#ifdef S6_FRONTEND_WRAP_DAEMONTOOLS
+
+static void readproctitle (int argc, char const *const *argv, char const *const *envp)
+{
+ (void)argc ;
+ (void)argv ;
+ (void)envp ;
+ noboot("readproctitle") ;
+}
+
+static void svscanboot (int argc, char const *const *argv, char const *const *envp)
+{
+ (void)argc ;
+ (void)argv ;
+ (void)envp ;
+ noboot("svscanboot") ;
+}
+
+#endif
+
+#ifdef S6_FRONTEND_WRAP_RUNIT
+
+static void runit (int argc, char const *const *argv, char const *const *envp)
+{
+ (void)argc ;
+ (void)argv ;
+ (void)envp ;
+ noboot("runit") ;
+}
+
+static void runit_init (int argc, char const *const *argv, char const *const *envp)
+{
+ (void)argc ;
+ (void)argv ;
+ (void)envp ;
+ noboot("runit-init") ;
+}
+
+static void runsvchdir (int argc, char const *const *argv, char const *const *envp)
+{
+ (void)argc ;
+ (void)argv ;
+ (void)envp ;
+ strerr_dief1x(100, "s6 does not provide a runsvchdir emulation. To handle several different sets of services, please consider the s6-rc package.") ;
+}
+
+static void runsvdir (int argc, char const *const *argv, char const *const *envp)
+{
+ char const *newargv[4] = { S6_EXTBINPREFIX "s6-svscan", "-St14000", 0, 0 } ;
+ int dosetsid = 0 ;
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ int opt = subgetopt_r(argc, argv, "P", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 'P' : dosetsid = 1 ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (dosetsid)
+ strerr_warnw1x("-P option ignored: s6-svscan does not run its supervisor processes (s6-supervise) in a new session. However, by default, it runs every service in a new session.") ;
+ if (argc >= 2)
+ strerr_warnw1x("s6-svscan does not support logging to a readproctitle process. To log the output of your supervision tree, please consider using the s6-linux-init package.") ;
+ newargv[2] = argv[0] ;
+ if (verbosity)
+ {
+ buffer_puts(buffer_2, PROG) ;
+ buffer_puts(buffer_2, ": info: executing command line:") ;
+ for (char const *const *p = argv ; *p ; p++)
+ {
+ buffer_puts(buffer_2, " ") ;
+ buffer_puts(buffer_2, *p) ;
+ }
+ buffer_putsflush(buffer_2, "\n") ;
+ }
+ xpathexec_run(newargv[0], newargv, envp) ;
+}
+
+static void svlogd (int argc, char const *const *argv, char const *const *envp)
+{
+ (void)argc ;
+ (void)argv ;
+ (void)envp ;
+ strerr_dief1x(100, "the s6-log program is similar to svlogd, but uses a different filtering syntax and does not use a config file in the logdir. Please see https://skarnet.org/software/s6/s6-log.html") ;
+}
+
+static void utmpset (int argc, char const *const *argv, char const *const *envp)
+{
+ (void)argc ;
+ (void)argv ;
+ (void)envp ;
+ strerr_dief1x(100, "s6 does not provide a utmpset emulation. To handle utmp records, please consider the s6-linux-init package, along with the utmps package if necessary.") ;
+}
+
+#endif
+
+static info_t const aliases[] =
+{
+#ifdef S6_FRONTEND_WRAP_RUNIT
+ { .name = "chpst", .cmd = S6_FRONTEND_BINPREFIX "s6-frontend-alias-chpst", .f = 0 },
+#endif
+#ifdef S6_FRONTEND_WRAP_DAEMONTOOLS
+ { .name = "envdir", .cmd = S6_EXTBINPREFIX "s6-envdir", .f = 0 },
+ { .name = "envuidgid", .cmd = S6_EXTBINPREFIX "s6-envuidgid", .f = 0 },
+ { .name = "fghack", .cmd = S6_EXTBINPREFIX "s6-fghack", .f = 0 },
+ { .name = "multilog", .cmd = S6_EXTBINPREFIX "s6-log", .f = 0 },
+ { .name = "pgrphack", .cmd = S6_EXTBINPREFIX "s6-setsid", .f = 0 },
+ { .name = "readproctitle", .cmd = 0, .f = &readproctitle },
+#endif
+#ifdef S6_FRONTEND_WRAP_RUNIT
+ { .name = "runit", .cmd = 0, .f = &runit },
+ { .name = "runit-init", .cmd = 0, .f = &runit_init },
+ { .name = "runsv", .cmd = S6_EXTBINPREFIX "s6-supervise", .f = 0 },
+ { .name = "runsvchdir", .cmd = 0, .f = &runsvchdir },
+ { .name = "runsvdir", .cmd = 0, .f = &runsvdir },
+#endif
+#ifdef S6_FRONTEND_WRAP_DAEMONTOOLS
+ { .name = "setlock", .cmd = S6_EXTBINPREFIX "s6-setlock", .f = 0 },
+ { .name = "setuidgid", .cmd = S6_EXTBINPREFIX "s6-setuidgid", .f = 0 },
+ { .name = "softlimit", .cmd = S6_EXTBINPREFIX "s6-softlimit", .f = 0 },
+ { .name = "supervise", .cmd = S6_EXTBINPREFIX "s6-supervise", .f = 0 },
+#endif
+#ifdef S6_FRONTEND_WRAP_RUNIT
+ { .name = "sv", .cmd = S6_FRONTEND_BINPREFIX "s6-frontend-alias-sv", .f = 0 },
+#endif
+#ifdef S6_FRONTEND_WRAP_DAEMONTOOLS
+ { .name = "svc", .cmd = S6_EXTBINPREFIX "s6-svc", .f = 0 },
+#endif
+#ifdef S6_FRONTEND_WRAP_RUNIT
+ { .name = "svlogd", .cmd = 0, .f = &svlogd },
+#endif
+#ifdef S6_FRONTEND_WRAP_DAEMONTOOLS
+ { .name = "svok", .cmd = S6_EXTBINPREFIX "s6-svok", .f = 0 },
+ { .name = "svscan", .cmd = S6_EXTBINPREFIX "s6-svscan", .f = 0 },
+ { .name = "svscanboot", .cmd = 0, .f = &svscanboot },
+ { .name = "svstat", .cmd = S6_EXTBINPREFIX "s6-svstat", .f = 0 },
+ { .name = "tai64n", .cmd = S6_EXTBINPREFIX "s6-tai64n", .f = 0 },
+ { .name = "tai64nlocal", .cmd = S6_EXTBINPREFIX "s6-tai64nlocal", .f = 0 },
+#endif
+#ifdef S6_FRONTEND_WRAP_RUNIT
+ { .name = "utmpset", .cmd = 0, .f = &utmpset },
+#endif
+} ;
+
+int main (int argc, char const **argv, char const *const *envp)
+{
+ char const *name = argv[0] ;
+ stralloc sa = STRALLOC_ZERO ;
+ info_t *p ;
+ PROG = "s6-frontend-alias" ;
+
+ if (!sabasename(&sa, name, strlen(name)) || !stralloc_0(&sa)) dienomem() ;
+ if (!strcmp(sa.s, PROG))
+ {
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ int opt = subgetopt_r(argc, argv, "v", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 'v' : verbosity++ ; break ;
+ default : strerr_dieusage(100, USAGE) ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (!argc) dieusage() ;
+ name = *argv ;
+ stralloc_free(&sa) ;
+ }
+ else name = sa.s ;
+
+ p = bsearch(name, aliases, sizeof(aliases) / sizeof(info_t), sizeof(info_t), &info_cmp) ;
+ if (!p) strerr_dief2x(100, "unknown alias: ", name) ;
+ if (p->cmd)
+ {
+ argv[0] = p->cmd ;
+ if (verbosity)
+ strerr_warni4x("the s6 version of ", name, " is ", p->cmd) ;
+ xpathexec_run(argv[0], argv, envp) ;
+ }
+ else (*p->f)(argc, argv, envp) ;
+ strerr_dief1x(101, "can't happen: incorrect alias handler. Please submit a bug-report.") ;
+}
diff --git a/src/config/deps-exe/s6-frontend-config-preprocess b/src/config/deps-exe/s6-frontend-config-preprocess
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/config/deps-exe/s6-frontend-config-preprocess
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/config/s6-frontend-config-preprocess.c b/src/config/s6-frontend-config-preprocess.c
new file mode 100644
index 0000000..db09e24
--- /dev/null
+++ b/src/config/s6-frontend-config-preprocess.c
@@ -0,0 +1,286 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <skalibs/uint64.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/buffer.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/direntry.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/skamisc.h>
+#include <skalibs/avltree.h>
+
+#define USAGE "s6-frontend-config-preprocess file"
+#define dieusage() strerr_dieusage(100, USAGE)
+#define dienomem() strerr_diefu1sys(111, "stralloc_catb") ;
+#define MAXDEPTH 100
+
+static stralloc sa = STRALLOC_ZERO ;
+static unsigned int depth = 0 ;
+
+
+ /* Name storage */
+
+static stralloc namesa = STRALLOC_ZERO ;
+
+static void *name_dtok (uint32_t pos, void *aux)
+{
+ (void)aux ;
+ return namesa.s + pos ;
+}
+
+static int name_cmp (void const *a, void const *b, void *aux)
+{
+ (void)aux ;
+ return strcmp((char const *)a, (char const *)b) ;
+}
+
+static avltree namemap = AVLTREE_INIT(8, 3, 8, &name_dtok, &name_cmp, 0) ;
+
+
+ /* Directory sorting */
+
+static char *dname_cmp_base ;
+static int dname_cmp (void const *a, void const *b)
+{
+ return strcmp(dname_cmp_base + *(size_t *)a, dname_cmp_base + *(size_t *)b) ;
+}
+
+
+ /* Recursive inclusion functions */
+
+static int includefromhere (char const *, int) ;
+
+static inline void includecwd (int once)
+{
+ genalloc ga = GENALLOC_ZERO ; /* size_t */
+ DIR *dir ;
+ size_t sabase = sa.len ;
+ if (sagetcwd(&sa) < 0 || !stralloc_0(&sa)) dienomem() ;
+ dir = opendir(".") ;
+ if (!dir) strerr_diefu2sys(111, "opendir ", sa.s + sabase) ;
+
+ for (;;)
+ {
+ direntry *d ;
+ errno = 0 ;
+ d = readdir(dir) ;
+ if (!d) break ;
+ if (d->d_name[0] == '.') continue ;
+ if (!genalloc_catb(size_t, &ga, &sa.len, 1)) break ;
+ if (!stralloc_catb(&sa, d->d_name, strlen(d->d_name)+1)) break ;
+ }
+ dir_close(dir) ;
+ if (errno) strerr_diefu2sys(111, "readdir ", sa.s + sabase) ;
+
+ dname_cmp_base = sa.s ;
+ qsort(genalloc_s(size_t, &ga), genalloc_len(size_t, &ga), sizeof(size_t), &dname_cmp) ;
+
+ for (size_t i = 0 ; i < genalloc_len(size_t, &ga) ; i++)
+ if (!includefromhere(sa.s + genalloc_s(size_t, &ga)[i], once))
+ strerr_dief4sys(1, "in ", sa.s + sabase, ": unable to include ", sa.s + genalloc_s(size_t, &ga)[i]) ;
+
+ genalloc_free(size_t, &ga) ;
+ sa.len = sabase ;
+}
+
+static int include (char const *file, int once)
+{
+ size_t sabase = sa.len ;
+ size_t filelen = strlen(file) ;
+ if (!sadirname(&sa, file, filelen) || !stralloc_0(&sa)) dienomem() ;
+ if (chdir(sa.s + sabase) < 0) return 0 ;
+ sa.len = sabase ;
+ if (!sabasename(&sa, file, filelen)) dienomem() ;
+ {
+ char fn[sa.len + 1 - sabase] ;
+ memcpy(fn, sa.s + sabase, sa.len - sabase) ;
+ fn[sa.len - sabase] = 0 ;
+ sa.len = sabase ;
+ return includefromhere(fn, once) ;
+ }
+}
+
+static inline int idcmd (char const *s)
+{
+ static char const *commands[] =
+ {
+ "include",
+ "includeonce",
+ "includedir",
+ "includedironce",
+ 0
+ } ;
+ for (char const **p = commands ; *p ; p++)
+ if (!strcmp(s, *p)) return p - commands ;
+ return -1 ;
+}
+
+static inline unsigned char cclass (char c)
+{
+ static unsigned char const classtable[34] = "0444444443144344444444444444444432" ;
+ return (unsigned char)c < 34 ? classtable[(unsigned char)c] - '0' : 4 ;
+}
+
+static int includefromhere (char const *file, int once)
+{
+ size_t sabase = sa.len ;
+ if (sarealpath(&sa, file) < 0 || !stralloc_0(&sa)) return 0 ;
+
+ if (once)
+ {
+ uint32_t dummy ;
+ if (avltree_search(&namemap, sa.s + sabase, &dummy)) goto end ;
+ {
+ size_t cur = namesa.len ;
+ size_t filelen = strlen(file) ;
+ if (cur + filelen + 2 < cur || cur + filelen + 2 > UINT32_MAX)
+ strerr_dief3x(3, "in ", sa.s + sabase, ": too much nesting") ;
+ if (!stralloc_catb(&namesa, sa.s + sabase, sa.len - sabase)) dienomem() ;
+ if (!avltree_insert(&namemap, cur)) dienomem() ;
+ }
+ }
+
+ if (depth++ > MAXDEPTH)
+ strerr_dief3x(3, "in ", sa.s + sabase, ": too much nesting") ;
+
+ {
+ static unsigned char const table[8][5] =
+ {
+ { 0x08, 0x10, 0x02, 0x10, 0x10 },
+ { 0x08, 0x10, 0x11, 0x11, 0x11 },
+ { 0x08, 0x00, 0x03, 0x04, 0x25 },
+ { 0x08, 0x00, 0x03, 0x03, 0x03 },
+ { 0x09, 0x09, 0x09, 0x04, 0x25 },
+ { 0x09, 0x09, 0x09, 0x46, 0x25 },
+ { 0x0a, 0x0a, 0x07, 0x06, 0x27 },
+ { 0x88, 0x80, 0x27, 0x27, 0x27 }
+ } ;
+ stralloc localsa = STRALLOC_ZERO ;
+ uint64_t line = 1 ;
+ size_t sacur = sa.len ;
+ int cmd = -1 ;
+ buffer b ;
+ char buf[4096] ;
+ unsigned char state = 0 ;
+ int fd = open_readb(file) ;
+ if (fd < 0) strerr_diefu2sys(111, "open ", sa.s + sabase) ;
+ buffer_init(&b, &buffer_read, fd, buf, 4096) ;
+
+ if (buffer_put(buffer_1, "! 0 ", 4) < 4
+ || buffer_put(buffer_1, sa.s + sabase, sacur - 1 - sabase) < sacur - 1 - sabase
+ || buffer_put(buffer_1, "\n", 1) < 1)
+ strerr_diefu1sys(111, "write to stdout") ;
+
+ while (state < 8)
+ {
+ uint16_t what ;
+ char c = 0 ;
+ if (buffer_get(&b, &c, 1) < 0)
+ strerr_diefu2sys(111, "read from ", sa.s + sabase) ;
+ what = table[state][cclass((unsigned char)c)] ;
+ state = what & 0x000f ;
+ if (what & 0x0010)
+ if (buffer_put(buffer_1, &c, 1) < 1)
+ strerr_diefu1sys(111, "write to stdout") ;
+ if (what & 0x0020)
+ if (!stralloc_catb(&localsa, &c, 1)) dienomem() ;
+ if (what & 0x0040)
+ {
+ if (!stralloc_0(&localsa)) dienomem() ;
+ cmd = idcmd(localsa.s) ;
+ if (cmd < 0)
+ {
+ char fmt[UINT64_FMT] ;
+ fmt[uint64_fmt(fmt, line)] = 0 ;
+ strerr_dief6x(2, "in ", sa.s + sabase, " line ", fmt, ": unrecognized directive: ", localsa.s) ;
+ }
+ localsa.len = 0 ;
+ }
+ if (what & 0x0080)
+ {
+ int fdhere = open(".", O_RDONLY | O_DIRECTORY) ;
+ if (fdhere < 0)
+ strerr_dief3sys(111, "in ", sa.s + sabase, ": unable to open base directory: ") ;
+ if (!stralloc_0(&localsa)) dienomem() ;
+ if (cmd & 2)
+ {
+ if (chdir(localsa.s) < 0)
+ {
+ char fmt[UINT64_FMT] ;
+ fmt[uint64_fmt(fmt, line)] = 0 ;
+ strerr_dief6sys(111, "in ", sa.s + sabase, " line ", fmt, ": unable to chdir to ", localsa.s) ;
+ }
+ includecwd(cmd & 1) ;
+ }
+ else if (!include(localsa.s, cmd & 1))
+ {
+ char fmt[UINT64_FMT] ;
+ fmt[uint64_fmt(fmt, line)] = 0 ;
+ strerr_dief6sys(111, "in ", sa.s + sabase, " line ", fmt, ": unable to include ", localsa.s) ;
+ }
+ if (fchdir(fdhere) < 0)
+ strerr_dief3sys(111, "in ", sa.s + sabase, ": unable to fchdir back") ;
+ fd_close(fdhere) ;
+ localsa.len = 0 ;
+ {
+ char fmt[UINT64_FMT] ;
+ size_t fmtlen = uint64_fmt(fmt, line) ;
+ fmt[fmtlen++] = ' ' ;
+ if (buffer_put(buffer_1, "! ", 2) < 2
+ || buffer_put(buffer_1, fmt, fmtlen) < fmtlen
+ || buffer_put(buffer_1, sa.s + sabase, sacur - 1 - sabase) < sacur - 1 - sabase
+ || buffer_put(buffer_1, "\n", 1) < 1)
+ strerr_diefu1sys(111, "write to stdout") ;
+ }
+ }
+ if (c == '\n' && state <= 8) line++ ;
+ }
+ if (state > 8)
+ {
+ char fmt[UINT64_FMT] ;
+ fmt[uint64_fmt(fmt, line)] = 0 ;
+ strerr_dief5x(2, "in ", sa.s + sabase, " line ", fmt, ": syntax error: invalid ! line") ;
+ }
+ fd_close(fd) ;
+ stralloc_free(&localsa) ;
+ }
+
+ depth-- ;
+ end:
+ sa.len = sabase ;
+ return 1 ;
+}
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ PROG = "s6-frontend-config-preprocess" ;
+ {
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ int opt = subgetopt_r(argc, argv, "", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ }
+ if (!argc) dieusage() ;
+
+ if (!include(argv[0], 1)) strerr_diefu2sys(1, "preprocess ", argv[0]) ;
+ if (!buffer_flush(buffer_1))
+ strerr_diefu1sys(111, "write to stdout") ;
+ return 0 ;
+}
diff --git a/src/config/s6-frontend-config-preprocess.txt b/src/config/s6-frontend-config-preprocess.txt
new file mode 100644
index 0000000..e81c86e
--- /dev/null
+++ b/src/config/s6-frontend-config-preprocess.txt
@@ -0,0 +1,38 @@
+
+ Automaton for the preprocessor:
+
+
+class | 0 1 2 3 4
+st\ev | \0 \n ! space other
+
+START | print print print
+0 | END START CMD NORMAL NORMAL
+
+NORMAL | print print print print
+1 | END START NORMAL NORMAL NORMAL
+
+CMD | add
+2 | END START IGNORE CMD1 CMD2
+
+IGNORE |
+3 | END START IGNORE IGNORE IGNORE
+
+CMD1 | add
+4 | X X X CMD1 CMD2
+
+CMD2 | idcmd add
+5 | X X X ARG CMD2
+
+ARG | add
+6 | X X ARG1 ARG ARG1
+
+ARG1 | proc proc add add add
+7 | END START ARG1 ARG1 ARG1
+
+states: 0-7 plus END and X -> 4 bits
+actions: 4. -> 8 bits total, fits in a char.
+
+print 0x10 copies the character to stdout
+add 0x20 adds the character to the processing string
+idcmd 0x40 ids the processing string for an !include cmd
+proc 0x80 gets the filename and procs the include
diff --git a/tools/gen-deps.sh b/tools/gen-deps.sh
new file mode 100755
index 0000000..27e5b3e
--- /dev/null
+++ b/tools/gen-deps.sh
@@ -0,0 +1,93 @@
+#!/bin/sh -e
+
+. package/info
+
+echo '#'
+echo '# This file has been generated by tools/gen-deps.sh'
+echo '#'
+echo
+
+for dir in src/include/${package} src/* ; do
+ for file in $(ls -1 $dir | grep -- \\.h$) ; do
+ {
+ grep -F -- "#include <${package}/" < ${dir}/$file | cut -d'<' -f2 | cut -d'>' -f1 ;
+ grep -- '#include ".*\.h"' < ${dir}/$file | cut -d'"' -f2
+ } | sort -u | {
+ deps=
+ while read dep ; do
+ if echo $dep | grep -q "^${package}/" ; then
+ deps="$deps src/include/$dep"
+ elif test -f "${dir}/$dep" ; then
+ deps="$deps ${dir}/$dep"
+ else
+ deps="$deps src/include-local/$dep"
+ fi
+ done
+ if test -n "$deps" ; then
+ echo "${dir}/${file}:${deps}"
+ fi
+ }
+ done
+done
+
+for dir in src/* ; do
+ for file in $(ls -1 $dir | grep -- \\.c$) ; do
+ {
+ grep -F -- "#include <${package}/" < ${dir}/$file | cut -d'<' -f2 | cut -d'>' -f1 ;
+ grep -- '#include ".*\.h"' < ${dir}/$file | cut -d'"' -f2
+ } | sort -u | {
+ deps=" ${dir}/$file"
+ while read dep ; do
+ if echo $dep | grep -q "^${package}/" ; then
+ deps="$deps src/include/$dep"
+ elif test -f "${dir}/$dep" ; then
+ deps="$deps ${dir}/$dep"
+ else
+ deps="$deps src/include-local/$dep"
+ fi
+ done
+ o=$(echo $file | sed s/\\.c$/.o/)
+ lo=$(echo $file | sed s/\\.c$/.lo/)
+ echo "${dir}/${o} ${dir}/${lo}:${deps}"
+ }
+ done
+done
+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
+ 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 'ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)'
+ echo "lib${file}.a.xyzzy:$deps"
+ echo else
+ echo "lib${file}.a.xyzzy:$(echo "$deps" | sed 's/\.o/.lo/g')"
+ echo endif
+ echo "lib${file}.so.xyzzy: 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
+ deps=
+ libs=
+ while read dep ; do
+ if echo $dep | grep -q -- \\.o$ ; then
+ dep="src/$dir/$dep"
+ fi
+ if echo $dep | grep -q -e ^-l -e '^\${.*_LIB}' ; then
+ libs="$libs $dep"
+ else
+ deps="$deps $dep"
+ fi
+ done < src/$dir/deps-exe/$file
+ echo "$file: EXTRA_LIBS :=$libs"
+ echo "$file: src/$dir/$file.o$deps"
+ done
+done
diff --git a/tools/install.sh b/tools/install.sh
new file mode 100755
index 0000000..89f9428
--- /dev/null
+++ b/tools/install.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+usage() {
+ echo "usage: $0 [-D] [-l] [-m mode] src dst" 1>&2
+ exit 1
+}
+
+mkdirp=false
+symlink=false
+mode=0755
+
+while getopts Dlm: name ; do
+ case "$name" in
+ D) mkdirp=true ;;
+ l) symlink=true ;;
+ m) mode=$OPTARG ;;
+ ?) usage ;;
+ esac
+done
+shift $(($OPTIND - 1))
+
+test "$#" -eq 2 || usage
+src=$1
+dst=$2
+tmp="$dst.tmp.$$"
+
+case "$dst" in
+ */) echo "$0: $dst ends in /" 1>&2 ; exit 1 ;;
+esac
+
+set -C
+set -e
+
+if $mkdirp ; then
+ umask 022
+ case "$2" in
+ */*) mkdir -p "${dst%/*}" ;;
+ esac
+fi
+
+trap 'rm -f "$tmp"' EXIT INT QUIT TERM HUP
+
+umask 077
+
+if $symlink ; then
+ ln -s "$src" "$tmp"
+else
+ cat < "$1" > "$tmp"
+ chmod "$mode" "$tmp"
+fi
+
+mv -f "$tmp" "$dst"
+if test -d "$dst" ; then
+ rm -f "$dst/$(basename $tmp)"
+ if $symlink ; then
+ mkdir "$tmp"
+ ln -s "$src" "$tmp/$(basename $dst)"
+ mv -f "$tmp/$(basename $dst)" "${dst%/*}"
+ rmdir "$tmp"
+ else
+ echo "$0: $dst is a directory" 1>&2
+ exit 1
+ fi
+fi