From ed9dadb2778ab4ff7683622907e22ed8c561bfda Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Mon, 30 Dec 2019 23:27:32 +0000 Subject: Initial commit. --- .gitignore | 5 + AUTHORS | 2 + COPYING | 13 + INSTALL | 174 ++++++++ Makefile | 151 +++++++ NEWS | 6 + README | 25 ++ configure | 509 ++++++++++++++++++++++ doc/index.html | 149 +++++++ doc/quickstart.html | 26 ++ doc/s6-frontend-alias.html | 41 ++ doc/s6-frontend-config-preprocess.html | 87 ++++ doc/upgrade.html | 28 ++ package/deps-build | 4 + package/deps.mak | 17 + package/info | 4 + package/modes | 4 + package/targets.mak | 75 ++++ src/alias/deps-exe/s6-frontend-alias | 1 + src/alias/deps-exe/s6-frontend-alias-chpst | 1 + src/alias/deps-exe/s6-frontend-alias-sv | 3 + src/alias/s6-frontend-alias-chpst.c | 347 +++++++++++++++ src/alias/s6-frontend-alias-sv.c | 377 ++++++++++++++++ src/alias/s6-frontend-alias.c | 235 ++++++++++ src/config/deps-exe/s6-frontend-config-preprocess | 1 + src/config/s6-frontend-config-preprocess.c | 286 ++++++++++++ src/config/s6-frontend-config-preprocess.txt | 38 ++ tools/gen-deps.sh | 93 ++++ tools/install.sh | 64 +++ 29 files changed, 2766 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 INSTALL create mode 100644 Makefile create mode 100644 NEWS create mode 100644 README create mode 100755 configure create mode 100644 doc/index.html create mode 100644 doc/quickstart.html create mode 100644 doc/s6-frontend-alias.html create mode 100644 doc/s6-frontend-config-preprocess.html create mode 100644 doc/upgrade.html create mode 100644 package/deps-build create mode 100644 package/deps.mak create mode 100644 package/info create mode 100644 package/modes create mode 100644 package/targets.mak create mode 100644 src/alias/deps-exe/s6-frontend-alias create mode 100644 src/alias/deps-exe/s6-frontend-alias-chpst create mode 100644 src/alias/deps-exe/s6-frontend-alias-sv create mode 100644 src/alias/s6-frontend-alias-chpst.c create mode 100644 src/alias/s6-frontend-alias-sv.c create mode 100644 src/alias/s6-frontend-alias.c create mode 100644 src/config/deps-exe/s6-frontend-config-preprocess create mode 100644 src/config/s6-frontend-config-preprocess.c create mode 100644 src/config/s6-frontend-config-preprocess.txt create mode 100755 tools/gen-deps.sh create mode 100755 tools/install.sh 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 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 + +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/$( + + Please use the 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 </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 <&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 @@ + + + + + + s6-frontend - a frontend to the s6 ecosystem + + + + + + +

+Software
+skarnet.org +

+ +

s6-frontend

+ +

What is it ?

+ +

+ s6-frontend is still in development. +

+ +

+ s6-frontend is a frontend to the s6 ecosystem. It is made of +several parts: +

+ +
    +
  • A set of user-friendly commands, making it easier to manage a +s6-based system for people who are used to other tools.
  • +
  • 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 +s6, +s6-linux-init and +s6-rc. 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.
  • +
  • A prepackaged set of configuration files, implementing policy, +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.
  • +
+ +

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

+ +
+ + + +
+

Installation

+ +

Requirements

+ +
    +
  • A Linux-based system with a standard C development environment
  • +
  • GNU make, version 3.81 or later
  • +
  • skalibs version +2.9.1.0 or later
  • +
  • execline version +2.6.0.0 or later
  • +
  • s6 version +2.9.0.1 or later
  • +
  • s6-rc version +0.5.1.1 or later
  • +
  • s6-linux-init version +1.0.3.1 or later
  • +
+ +

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

+ +

Licensing

+ +

+ s6-frontend is free software. It is available under the +ISC license. +

+ +

Download

+ +
    +
  • The current released version of s6-frontend is +0.0.1.0. (unavailable while in development)
  • +
  • Alternatively, you can checkout a copy of the +s6-frontend +git repository: +
     git clone git://git.skarnet.org/s6-frontend 
  • +
  • There's also a +GitHub mirror +of the s6-frontend git repository.
  • +
+ +

Compilation

+ +
    +
  • See the enclosed INSTALL file for installation details.
  • +
+ +

Upgrade notes

+ +
    +
  • This page lists the differences to be aware of between +the previous versions of s6-frontend and the current one.
  • +
+ +
+ +

Reference

+ +

Commands

+ +

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

+ + + +

Related resources

+ +
    +
  • s6-frontend is discussed on the +supervision mailing-list.
  • +
  • There is a #s6 IRC channel on Freenode. Sometimes people +are there and even answer questions.
  • +
+ + + 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 @@ + + + + + + s6-frontend: quickstart and FAQ + + + + + + +

+s6-frontend
+Software
+skarnet.org +

+ +

Quickstart and FAQ for s6-frontend

+ +

+ (To be written.) +

+ + + 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 @@ + + + + + + s6-frontend: the s6-frontend-alias program + + + + + + +

+s6-frontend
+Software
+skarnet.org +

+ +

The s6-frontend-alias program

+ +

+s6-frontend-alias +

+ +

Interface

+ +
+     s6-frontend-alias
+
+ +

+

+ +

Options

+ +
    +
  • -v : verbose.
  • +
+ + + 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 @@ + + + + + + s6-frontend: the s6-frontend-config-preprocess program + + + + + + +

+s6
+Software
+skarnet.org +

+ +

The s6-frontend-config-preprocess program

+ +

+ s6-frontend-config-preprocess 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. +

+ +

Interface

+ +
+     s6-frontend-config-preprocess file
+
+ +

+ s6-frontend-config-preprocess reads file and prints it +to stdout. It removes lines starting with !!. +

+ +

+ When it finds a !include or !includeonce directive +in file, it replaces it with the contents of the included +file - recursively preprocessed. +

+ +

+ When it finds a !includedir or !includedironce +directive in file, 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. +

+ +

+ !includeonce and !includedironce only print +a file (resp. a directory) the first time they encounter it, and +silently ignore subsequent instances. !include and +!includedir directives will happily include the same +files several times. +

+ +

+ To avoid loops, a nesting limit exists. s6-frontend-config-preprocess +will fail if there are too many nested inclusions. +

+ +

Exit codes

+ +
    +
  • 0: success
  • +
  • 1: syntax error in a configuration file
  • +
  • 2: other error in a configuration file
  • +
  • 3: too many nested inclusions
  • +
  • 100: usage error
  • +
  • 111: system call failed
  • +
+ +

Notes

+ +
    +
  • s6-frontend-config-preprocess is not meant to be +called directly by the user. It is normally invoked by +s6-frontend-config-parse. +However, the binary is made available for debugging purposes.
  • +
+ + + 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 @@ + + + + + + s6-frontend: how to upgrade + + + + + + +

+s6-frontend
+Software
+skarnet.org +

+ +

What has changed in s6-frontend

+ +

in 0.0.1.0

+ +
    +
  • Initial release.
  • +
+ + + 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 -- cgit v1.3.1