summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--AUTHORS2
-rw-r--r--COPYING13
-rw-r--r--INSTALL153
-rw-r--r--Makefile131
-rw-r--r--README22
-rwxr-xr-xconfigure409
-rw-r--r--doc/index.html123
-rw-r--r--doc/s6-linux-init-maker.html276
-rw-r--r--doc/upgrade.html28
-rw-r--r--package/deps-build5
-rw-r--r--package/deps.mak8
-rw-r--r--package/info4
-rw-r--r--package/modes1
-rw-r--r--package/targets.mak6
-rw-r--r--src/init/deps-exe/s6-linux-init-maker1
-rw-r--r--src/init/s6-linux-init-maker.c377
-rwxr-xr-xtools/gen-deps.sh83
-rwxr-xr-xtools/install.sh64
19 files changed, 1711 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5c6415e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*.o
+*.a
+*.lo
+*.so
+*.so.*
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..463bc49
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,13 @@
+Copyright (c) 2015 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..3f7504b
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,153 @@
+Build Instructions
+------------------
+
+* Requirements
+ ------------
+
+ - A Linux-based system with a standard C development environment
+ - GNU make version 4.0 or later
+ - skalibs version 2.3.5.1 or later: http://skarnet.org/software/skalibs/
+ - execline version 2.1.2.2 or later: http://skarnet.org/software/execline/
+ - s6-portable-utils version 2.0.5.0 or later: http://skarnet.org/software/s6-portable-utils/
+ - s6-linux-utils version 2.0.2.0 or later: http://skarnet.org/software/s6-linux-utils/
+ - s6 version 2.1.4.0 or later: http://skarnet.org/software/s6/
+
+ Note that all those are build-time dependencies, and they are
+*also* run-time dependencies when you use the init binary created
+by s6-linux-init-maker.
+
+ This software is Linux-specific. It will run on a Linux kernel,
+version 2.6.32 or later. However, it should not be too hard to port to
+other Unix-like operating systems.
+
+
+* Standard usage
+ --------------
+
+ ./configure && make && sudo make install
+
+ will work for most users.
+ It will install the s6-linux-init-maker binary in /sbin.
+
+ 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.
+
+
+* 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, the standard environment variables are recognized.
+
+ The value of the CROSS_COMPILE environment variable will prefix the
+building tools' names. The --enable-cross option is preferred, see
+"Cross-compilation" below.
+
+ If the CC environment variable is set, its value will override compiler
+detection by configure.
+
+ The values of CFLAGS, CPPFLAGS and LDFLAGS will be appended to flags
+auto-detected by configure. To entirely override the flags set by
+configure, use make -e.
+
+ The value of LDLIBS will be appended by make to command lines that link
+an executable, even without the -e option.
+
+ The Makefile supports the DESTDIR convention for staging.
+
+
+* 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: http://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 --enable-cross=PREFIX option to configure, or simply
+--enable-cross if your default toolchain is a cross-compiling
+toolchain. And 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.
+
+
+* 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..b861d25
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,131 @@
+#
+# This Makefile requires GNU make.
+#
+# Do not make changes here.
+# Use the included .mak files.
+#
+
+it: all
+
+CC = $(error Please use ./configure first)
+
+STATIC_LIBS :=
+SHARED_LIBS :=
+INTERNAL_LIBS :=
+EXTRA_TARGETS :=
+
+-include config.mak
+include package/targets.mak
+include package/deps.mak
+
+version_m := $(basename $(version))
+version_M := $(basename $(version_m))
+version_l := $(basename $(version_M))
+CPPFLAGS_ALL := -iquote src/include-local -Isrc/include $(CPPFLAGS)
+CFLAGS_ALL := $(CFLAGS) -pipe -Wall
+CFLAGS_SHARED := -fPIC
+LDFLAGS_ALL := $(LDFLAGS)
+LDFLAGS_SHARED := -shared
+LDLIBS_ALL := $(LDLIBS)
+REALCC = $(CROSS_COMPILE)$(CC)
+AR := $(CROSS_COMPILE)ar
+RANLIB := $(CROSS_COMPILE)ranlib
+STRIP := $(CROSS_COMPILE)strip
+INSTALL := ./tools/install.sh
+
+ALL_BINS := $(LIBEXEC_TARGETS) $(BIN_TARGETS) $(SBIN_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 $(ALL_LIBS)),)
+ exec ${STRIP} -x -R .note -R .comment -R .note.GNU-stack $(ALL_LIBS)
+endif
+ifneq ($(strip $(ALL_BINS)),)
+ exec ${STRIP} -R .note -R .comment -R .note.GNU-stack $(ALL_BINS)
+endif
+
+install: install-dynlib install-libexec install-bin install-sbin install-lib install-include
+install-dynlib: $(SHARED_LIBS:lib%.so=$(DESTDIR)$(dynlibdir)/lib%.so)
+install-libexec: $(LIBEXEC_TARGETS:%=$(DESTDIR)$(libexecdir)/%)
+install-bin: $(BIN_TARGETS:%=$(DESTDIR)$(bindir)/%)
+install-sbin: $(SBIN_TARGETS:%=$(DESTDIR)$(sbindir)/%)
+install-lib: $(STATIC_LIBS:lib%.a=$(DESTDIR)$(libdir)/lib%.a)
+install-include: $(ALL_INCLUDES:src/include/$(package)/%.h=$(DESTDIR)$(includedir)/$(package)/%.h)
+install-data: $(ALL_DATA:src/etc/%=$(DESTDIR)$(datadir)/%)
+
+ifneq ($(exthome),)
+
+update:
+ exec $(INSTALL) -l $(notdir $(home)) $(DESTDIR)$(exthome)
+
+global-links: $(DESTDIR)$(exthome) $(SHARED_LIBS:lib%.so=$(DESTDIR)$(sproot)/library.so/lib%.so) $(BIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%) $(SBIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%)
+
+$(DESTDIR)$(sproot)/command/%: $(DESTDIR)$(home)/command/%
+ exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/command/$(<F) $@
+
+$(DESTDIR)$(sproot)/library.so/lib%.so: $(DESTDIR)$(dynlibdir)/lib%.so
+ 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
+ $(INSTALL) -D -m 755 $< $@.$(version) && \
+ $(INSTALL) -l $<.$(version) $@.$(version_m) && \
+ $(INSTALL) -l $<.$(version_m) $@.$(version_M) && \
+ $(INSTALL) -l $<.$(version_M) $@.$(version_l) && \
+ exec $(INSTALL) -l $<.$(version_l) $@
+
+$(DESTDIR)$(libexecdir)/% $(DESTDIR)$(bindir)/% $(DESTDIR)$(sbindir)/%: % 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
+ 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_ALL)
+
+lib%.a:
+ exec $(AR) rc $@ $^
+ exec $(RANLIB) $@
+
+lib%.so:
+ exec $(REALCC) -o $@ $(CFLAGS_ALL) $(CFLAGS_SHARED) $(LDFLAGS_ALL) $(LDFLAGS_SHARED) -Wl,-soname,$@.$(version_l) $^
+
+.PHONY: it all clean distclean tgz strip install install-dynlib install-bin install-sbin install-lib install-include install-data
+
+.DELETE_ON_ERROR:
diff --git a/README b/README
new file mode 100644
index 0000000..34c7440
--- /dev/null
+++ b/README
@@ -0,0 +1,22 @@
+s6-linux-init - an s6-based Linux init system
+---------------------------------------------
+
+ s6-linux-init is a suite of tools designed to provide an init program
+ for the Linux kernel - i.e., the first program run at boot time.
+
+ See http://skarnet.org/software/s6-linux-init/ for details.
+
+
+* Installation
+ ------------
+
+ See the INSTALL file.
+
+
+* Contact information
+ -------------------
+
+ Laurent Bercot <ska-skaware at skarnet.org>
+
+ Please use the <skaware at list.skarnet.org> mailing-list for
+questions about s6-linux-init.
diff --git a/configure b/configure
new file mode 100755
index 0000000..5244a37
--- /dev/null
+++ b/configure
@@ -0,0 +1,409 @@
+#!/bin/sh
+
+. 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=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR admin executables [EPREFIX/sbin]
+ --libexecdir=DIR package-scoped executables [EPREFIX/libexec]
+ --libdir=DIR static library files [PREFIX/lib/$package]
+ --includedir=DIR C header files [PREFIX/include]
+ --datadir=DIR global configuration files [PREFIX/etc]
+
+ 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]
+ --enable-slashpackage[=ROOT] assume /package installation at ROOT [disabled]
+ --enable-cross=CROSS prefix toolchain executable names with CROSS [none]
+
+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=$1
+}
+
+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 $CFLAGS_AUTO "$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 $LDFLAGS_AUTO -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="$CC"
+CFLAGS_AUTO="$CFLAGS"
+CPPFLAGS_AUTO="-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -O2 $CPPFLAGS"
+LDFLAGS_AUTO="$LDFLAGS"
+LDFLAGS_NOSHARED=
+prefix=
+exec_prefix='$prefix'
+dynlibdir='$prefix/lib'
+libexecdir='$exec_prefix/libexec'
+bindir='$exec_prefix/bin'
+sbindir='$exec_prefix/sbin'
+libdir='$prefix/lib/$package'
+includedir='$prefix/include'
+datadir='$prefix/etc'
+sysdeps='$prefix/lib/skalibs/sysdeps'
+manualsysdeps=false
+shared=false
+static=true
+slashpackage=false
+sproot=
+home=
+exthome=
+allstatic=true
+evenmorestatic=false
+addincpath=''
+addlibspath=''
+addlibdpath=''
+vpaths=''
+vpathd=''
+cross="$CROSS_COMPILE"
+
+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#*=} ;;
+ --sbindir=*) sbindir=${arg#*=} ;;
+ --libdir=*) libdir=${arg#*=} ;;
+ --includedir=*) includedir=${arg#*=} ;;
+ --datadir=*) datadir=${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-slashpackage=*) sproot=${arg#*=} ; slashpackage=true ; ;;
+ --enable-slashpackage) sproot= ; slashpackage=true ;;
+ --disable-slashpackage) sproot= ; slashpackage=false ;;
+ --enable-cross=*) cross=${arg#*=} ;;
+ --enable-cross) cross= ;;
+ --disable-cross) cross= ;;
+ --enable-*|--disable-*|--with-*|--without-*|--*dir=*|--build=*) ;;
+ --host=*|--target=*) target=${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 sbindir libdir includedir datadir sysdeps sproot skalibs ; 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
+ binprefix=${home}/command
+ extbinprefix=${exthome}/command
+ dynlibdir=${home}/library.so
+ libexecdir=$binprefix
+ bindir=$binprefix
+ sbindir=$binprefix
+ libdir=${home}/library
+ includedir=${home}/include
+ while read dep ; do
+ addincpath="$addincpath -I${sproot}${dep}/include"
+ vpaths="$vpaths ${sproot}${dep}/library"
+ addlibspath="$addlibspath -L${sproot}${dep}/library"
+ if $allstatic ; then : ; else
+ vpathd="$vpathd ${sproot}${dep}/library.so"
+ addlibdpath="$addlibdpath -L${sproot}${dep}/library.so"
+ fi
+ done < package/deps-build
+fi
+
+# Find a C compiler to use
+echo "checking for C compiler..."
+trycc ${cross}gcc
+trycc ${cross}c99
+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 $CFLAGS_AUTO -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..."
+test -n "$target" || target=$($CC_AUTO -dumpmachine 2>/dev/null) || target=unknown
+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
+
+rt_lib=$(cat $sysdeps/rt.lib)
+socket_lib=$(cat $sysdeps/socket.lib)
+sysclock_lib=$(cat $sysdeps/sysclock.lib)
+tainnow_lib=$(cat $sysdeps/tainnow.lib)
+util_lib=$(cat $sysdeps/util.lib)
+
+tryflag CFLAGS_AUTO -std=c99
+tryflag CFLAGS_AUTO -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_AUTO -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
+
+if $evenmorestatic ; then
+ LDFLAGS_NOSHARED=-static
+fi
+
+if $shared ; then
+ tryldflag LDFLAGS_AUTO -Wl,--hash-style=both
+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
+
+CPPFLAGS_AUTO="$CPPFLAGS_AUTO $addincpath"
+LDFLAGS_AUTO="$LDFLAGS_AUTO $addlibspath"
+$allstatic || LDFLAGS_AUTO="$LDFLAGS_AUTO $addlibdpath"
+
+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
+sbindir := $sbindir
+libdir := $libdir
+includedir := $includedir
+datadir := $datadir
+sysdeps := $sysdeps
+slashpackage := $slashpackage
+sproot := $sproot
+version := $version
+home := $home
+exthome := $exthome
+RT_LIB := ${rt_lib}
+SOCKET_LIB := ${socket_lib}
+SYSCLOCK_LIB := ${sysclock_lib}
+TAINNOW_LIB := ${tainnow_lib}
+UTIL_LIB := ${util_lib}
+
+CC := $CC_AUTO
+CFLAGS := $CFLAGS_AUTO
+CPPFLAGS := $CPPFLAGS_AUTO
+LDFLAGS := $LDFLAGS_AUTO
+LDFLAGS_NOSHARED := $LDFLAGS_NOSHARED
+CROSS_COMPILE := $cross
+
+vpath lib%a$vpaths
+EOF
+if $allstatic ; then
+ echo ".LIBPATTERNS := lib%.a"
+ echo "DO_ALLSTATIC := 1"
+ vpathd=
+fi
+ echo "vpath lib%.so$vpathd"
+if $static ; then
+ echo "DO_STATIC := 1"
+else
+ echo "DO_STATIC :="
+fi
+if $shared ; then
+ echo "DO_SHARED := 1"
+else
+ echo "DO_SHARED :="
+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"
+#define ${package_macro_name}_ETC "$datadir"
+EOF
+if $slashpackage ; then
+ echo "#define ${package_macro_name}_BINPREFIX \"$binprefix/\""
+ echo "#define ${package_macro_name}_EXTBINPREFIX \"$extbinprefix/\""
+ echo "#define ${package_macro_name}_LIBEXECPREFIX \"$binprefix/\""
+else
+ echo "#define ${package_macro_name}_BINPREFIX \"\""
+ echo "#define ${package_macro_name}_EXTBINPREFIX \"\""
+ echo "#define ${package_macro_name}_LIBEXECPREFIX \"$libexecdir/\""
+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..fc7055d
--- /dev/null
+++ b/doc/index.html
@@ -0,0 +1,123 @@
+<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-linux-init - tools for a Linux init system</title>
+ <meta name="Description" content="s6-linux-init - tools for a Linux init system" />
+ <meta name="Keywords" content="s6 linux init administration root laurent bercot ska skarnet" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> s6-linux-init </h1>
+
+<h2> What is it&nbsp;? </h2>
+
+<p>
+ s6-linux-init is a set of minimalistic tools to create and manage
+the init process on a Linux system - i.e. the first process created
+by the kernel at boot time.
+</p>
+
+<p>
+ s6-linux-init is meant to automate creation of scripts revolving
+around the use of other skarnet.org tools, especially s6, in order
+to provide a complete booting environment with integrated supervision
+and logging without having to hand-craft all the details.
+</p>
+
+<hr />
+
+<h2> Installation </h2>
+
+<h3> Requirements </h3>
+
+<ul>
+ <li> A Linux-based system with a standard C development environment </li>
+ <li> GNU make, version 4.0 or later </li>
+ <li> <a href="http://skarnet.org/software/skalibs/">skalibs</a> version
+2.3.5.1 or later </li>
+ <li> <a href="http://skarnet.org/software/execline/">execline</a> version
+2.1.2.2 or later </li>
+ <li> <a href="http://skarnet.org/software/s6-portable-utils/">s6-portable-utils</a> version
+2.0.5.0 or later </li>
+ <li> <a href="http://skarnet.org/software/s6-linux-utils/">s6-linux-utils</a> version
+2.0.2.0 or later </li>
+ <li> <a href="http://skarnet.org/software/s6/">s6</a> version
+2.1.4.0 or later </li>
+</ul>
+
+<p>
+When you <em>build</em> s6-linux-init, the
+ <a href="s6-linux-init-maker.html">s6-linux-init-maker</a> tool
+is created; then you <em>run</em> that tool to create an init script,
+and then you can <em>boot</em> your system on that init script.
+</p>
+
+<p>
+ The listed dependencies are all <em>build-time</em> dependencies and also
+<em>boot-time</em> dependencies, i.e. you need the tools installed to build
+s6-linux-init and to boot your system. There are no <em>run-time</em>
+dependencies, except skalibs if you linked against the shared version of
+the library.
+</p>
+
+<h3> Licensing </h3>
+
+<p>
+ s6-linux-utils 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-linux-init is
+<a href="s6-linux-init-0.0.1.0.tar.gz">0.0.1.0</a>. </li>
+ <li> Alternatively, you can checkout a copy of the s6-linux-init git repository:
+<pre> git clone git://git.skarnet.org/s6-linux-init </pre> </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-linux-init 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><a href="s6-linux-init-maker.html">The <tt>s6-linux-init-maker</tt> program</a></li>
+</ul>
+
+<h2> Related resources </h2>
+
+<ul>
+ <li> <tt>s6-linux-init</tt> is discussed on the
+<a href="http://skarnet.org/lists.html#skaware">skaware</a> mailing-list. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/s6-linux-init-maker.html b/doc/s6-linux-init-maker.html
new file mode 100644
index 0000000..3c27a2f
--- /dev/null
+++ b/doc/s6-linux-init-maker.html
@@ -0,0 +1,276 @@
+<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-linux-init: the s6-linux-init-maker program</title>
+ <meta name="Description" content="s6-linux-init: the s6-linux-init-maker program" />
+ <meta name="Keywords" content="s6 linux administration root init maker" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6-linux-init</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>s6-linux-init-maker</tt> program </h1>
+
+<p>
+<tt>s6-linux-init-maker</tt> reads configuration options on
+the command line, and outputs a directory to place in the
+root filesystem as well as a script suitable as an init program.
+</p>
+
+<p>
+ s6-linux-init-maker only writes scripts. At boot time, these
+scripts will call commands provided by other skarnet.org packages
+such as
+<a href="http://skarnet.org/software/execline/">execline</a> or
+<a href="http://skarnet.org/software/s6/">s6</a>. It is the
+responsibility of the administrator to make sure that all the
+dependencies are properly installed at boot time, and that the
+correct options have been given to s6-linux-init-maker so that
+the programs are found <em>on the root filesystem of the
+machine</em> - else the scripts will crash.
+</p>
+
+</p>
+
+<h2> Interface and usage </h2>
+
+<pre>
+ s6-linux-init-maker \
+ [ -c <em>basedir</em> ] \
+ [ -l <em>tmpfsdir</em> ] \
+ [ -b <em>execline_bindir</em> ] \
+ [ -u <em>log_user</em> ] \
+ [ -g <em>early_getty</em> ] \
+ [ -2 <em>stage2</em> ] \
+ [ -3 <em>stage3</em> ] \
+ [ -p <em>initial_path</em> ] \
+ [ -m <em>initial_umask</em> ] \
+ [ -t <em>timestamp_style</em> ] \
+ [ -d <em>dev_style</em> ] \
+ [ -e <em>initial_envvar</em> ] ... \
+ <em>dir</em> &gt; <em>stage1</em>
+</pre>
+
+<ul>
+ <li> s6-linux-init-maker should be run as root. </li>
+ <li> s6-linux-init-maker parses options on its command line. </li>
+ <li> It writes data into a directory <em>dir</em>, which must not
+exist beforehand. </li>
+ <li> It then prints a script to its standard output. </li>
+ <li> It exits 0 if everything went well, 100 if a user error occurred,
+and 111 if a problem occurred during the directory or script creation. </li>
+</ul>
+
+<p>
+ <em>dir</em> should then be copied by the administrator to the place
+declared as <em>basedir</em>. Be careful: it contains fifos, files with
+precise uid/gid permissions, and files with non-standard access rights,
+so be sure to copy it verbatim. The
+<a href="http://skarnet.org/software/s6-portable-utils/s6-hiercopy.html">s6-hiercopy</a>
+tool can do it, as well as the GNU or busybox <tt>cp -a</tt> command.
+</p>
+
+<p>
+ The <em>stage1</em> script printed by s6-linux-init-maker on its
+stdout is then suitable as an init program. The administrator should
+copy it to <tt>/sbin/init</tt> and make it executable.
+</p>
+
+<h2> Boot sequence </h2>
+
+<p>
+ When the kernel boots, it runs the <em>stage1</em> script, and this is
+what happens:
+</p>
+
+<ul>
+ <li> <em>stage1</em> is an
+<a href="http://skarnet.org/software/execline/">execline</a> script, so
+the first process run by the kernel is the
+<a href="http://skarnet.org/software/execline/execlineb.html">execlineb</a>
+program launcher. </li>
+ <li> <em>stage1</em> mounts a
+<a href="https://www.kernel.org/doc/Documentation/filesystems/tmpfs.txt">tmpfs</a>
+filesystem on <em>tmpfsdir</em>. </li>
+ <li> <em>stage1</em> copies <tt><em>basedir</em>/run-image</tt> verbatim to
+<em>tmpfsdir</em>. </li>
+ <li> <em>stage1</em> reads a global set of environment variables from the
+<tt><em>basedir</em>/env</tt>
+<a href="http://skarnet.org/software/s6/s6-envdir.html">environment directory</a>. </li>
+ <li> <em>stage1</em> forks a child that will block until
+<a href="http://skarnet.org/software/s6/s6-svscan.html">s6-svscan</a> is running. </li>
+ <li> <em>stage1</em> executes, as process 1, into
+<a href="http://skarnet.org/software/s6/s6-svscan.html">s6-svscan</a>,
+with <tt><em>tmpfsdir</em>/service</tt> as a
+<a href="http://skarnet.org/software/s6/scandir.html">scan directory</a>. </li>
+ <li> This scan directory already contains at least one service, which is the
+<em>catch-all logger</em>: error messages from the supervision tree, and
+from services that do not have a dedicated logger, are handled by a
+special <a href="http://skarnet.org/software/s6/s6-log.html">s6-log</a>
+instance and made available in <tt><em>tmpfsdir</em>/uncaught-logs</tt>
+instead of clogging the system console. </li>
+ <li> If the <tt>-g</tt> option has been given to s6-linux-init-maker, the
+scan directory will also contain a service for an early getty. </li>
+ <li> s6-svscan starts all the services defined in the scan directory,
+and unblocks the child forked by <em>stage1</em>. </li>
+ <li> This child executes into <em>stage2</em>. </li>
+</ul>
+
+<p>
+ <em>stage2</em> is the responsibility of the administrator - it will
+not be written automatically!
+It should
+contain all the necessary initialization sequence to bring up a proper
+system. When <em>stage2</em> is executed, the machine state is as follows:
+</p>
+
+<ul>
+ <li> <em>stage2</em>'s working directory is <tt>/</tt> and its stdin
+is <tt>/dev/null</tt>. <em>stage2</em>'s
+stdout and stderr both point to the pipe to the catch-all logger, so
+unless redirected, <em>stage2</em>'s output will be logged into the
+<tt><em>tmpfsdir/uncaught-logs</em></tt> directory. </li>
+ <li> The system has a valid device directory mounted on <tt>/dev</tt>.
+ <li> Depending on the kernel boot command line, the root filesystem
+may be in read-only mode. </li>
+ <li> There is a tmpfs available for root only in <em>tmpfsdir</em>. </li>
+ <li> <a href="http://skarnet.org/software/s6/s6-svscan.html">s6-svscan</a>
+is running as process 1. At any time, it is possible to make it supervise a long-lived
+process by linking the appropriate
+<a href="http://skarnet.org/software/s6/servicedir.html">service directory</a>
+into <tt><em>tmpfsdir</em>/service</tt>, then running the command
+<tt>s6-svscanctl -a <em>tmpfsdir</em>/service</tt>. Services without a
+dedicated logger will send their output to the catch-all logger. </li>
+ <li> A getty service may already be available. The point of this early
+getty is essentially to make it easier to debug if <em>stage2</em> fails. </li>
+</ul>
+
+<p>
+ There is <em>nothing else</em>. In particular, no filesystem has been
+mounted yet, including <tt>/proc</tt> and <tt>/sys</tt>; and no one-time
+initialization
+has been performed. The point of <em>stage1</em> is only to make it
+possible to run <em>stage2</em> with a logging infrastructure and a
+supervision infrastructure already available, and all the
+real machine and service initialization should happen in <em>stage2</em>.
+</p>
+
+<h2> Shutdown sequence </h2>
+
+<p>
+ When s6-svscan is told to exit via an appropriate
+<a href="http://skarnet.org/software/s6/s6-svscanctl.html">s6-svscanctl</a>
+command, it executes into the <em>stage3</em> script, which, like
+<em>stage2</em>, is the responsibility of the administrator. <em>stage3</em>
+is run in the following state:
+</p>
+
+<ul>
+ <li> It runs as process 1. (Doing so makes it easier to recover after
+killing all processes by <tt>kill -9 -1</tt> or
+<a href="http://skarnet.org/software/s6-portable-utils/s6-nuke.html">s6-nuke</a>). </li>
+ <li> Its working directory is <tt>/</tt> and its stdin is <tt>/dev/null</tt> </li>
+ <li> Its stdout and stderr are both <tt>/dev/console</tt> </li>
+ <li> Depending on the exact s6-svscanctl command that terminated s6-svscan,
+and what has happened before that command was sent, there may or may not be
+long-running services that remain alive. The catch-all logger and its
+supervisor will <em>always</em> be alive, which is not a problem because they
+do not hold any file descriptor to a filesystem that would need to be
+unmounted. </li>
+</ul>
+
+<h2> s6-linux-init-maker options </h2>
+
+<ul>
+ <li> <tt>-c</tt>&nbsp;<em>basedir</em>&nbsp;: at boot time, <em>stage1</em>
+will read its read-only data from <em>basedir</em>. After running
+s6-linux-init-maker, the administrator should make sure to copy the
+created directory <em>dir</em> to <em>basedir</em>. <em>basedir</em>
+must be absolute. Default is
+<strong><tt>/etc/s6</tt></strong>. </li> <p />
+
+ <li> <tt>-l</tt>&nbsp;<em>tmpfsdir</em>&nbsp;: at boot time, a tmpfs will
+be mounted on <em>tmpfsdir</em>. The directory should already exist in
+the root filesystem, and be empty. <em>tmpfsdir</em> must be absolute. Default is
+<strong><tt>/run</tt></strong>. </li> <p />
+
+ <li> <tt>-b</tt>&nbsp;<em>execline_bindir</em>&nbsp;: init is run by the kernel
+without a PATH, and since it is a script, it is necessary to tell it where
+to find the
+<a href="http://skarnet.org/software/execline/execlineb.html">execlineb</a>
+launcher and the first few early commands before PATH can be set.
+<em>execline_bindir</em> is the location where the execline binaries can be
+found. It must be absolute. Default is
+<strong><tt>/bin</tt></strong>. </li> <p />
+
+ <li> <tt>-u</tt>&nbsp;<em>log_user</em>&nbsp;: the catch-all
+logger will not run as root, but as <em>log_user</em>. Default is
+<strong><tt>nobody</tt></strong>. </li> <p />
+
+ <li> <tt>-g</tt>&nbsp;<em>early_getty</em>&nbsp;: if this option
+is set, s6-linux-init-maker will define a service that will run
+very early, before <em>stage2</em> is executed. This early service
+should be a getty, to allow logins even if <em>stage2</em> fails.
+<em>early_getty</em> should be a simple command line: for instance,
+<tt>"/sbin/getty 38400 tty1"</tt>. By default, no early service
+is defined. </li> <p />
+
+ <li> <tt>-2</tt>&nbsp;<em>stage2</em>&nbsp;: <em>stage2</em> is
+the location of the stage 2 script that will be run when the
+system has an operational supervision tree. It must be absolute. Default is
+<strong><tt>/etc/rc.init</tt></strong>. </li> <p />
+
+ <li> <tt>-3</tt>&nbsp;<em>stage3</em>&nbsp;: <em>stage3</em> is
+the location of the stage 3 script that will be run at the end of
+the machine lifetime, when s6-svscan is told to terminate.
+It must be absolute. Default is
+<strong><tt>/etc/rc.shutdown</tt></strong>. </li> <p />
+
+ <li> <tt>-p</tt>&nbsp;<em>initial_path</em>&nbsp;: the value to
+set the PATH environment variable to, for all the starting processes.
+This will be done as early as possible in <em>stage1</em>. Default is
+the value that has been compiled in
+<a href="http://skarnet.org/software/skalibs/">skalibs</a> via the
+<tt>--with-default-path</tt> configure option, i.e. by default
+<strong><tt>/usr/bin:/bin</tt></strong>. </li> <p />
+
+ <li> <tt>-m</tt>&nbsp;<em>initial_umask</em>&nbsp;: the value of
+the initial file umask for all the starting processes, in octal.
+Default is
+<strong><tt>022</tt></strong>. </li> <p />
+
+ <li> <tt>-t</tt>&nbsp;<em>timestamp_style</em>&nbsp;: how
+logs are timestamped by the catch-all logger. 0 means no
+timestamp, 1 means
+<a href="http://cr.yp.to/libtai/tai64.html">external TAI64N format</a>,
+2 means
+<a href="http://www.iso.org/iso/home/standards/iso8601.htm">ISO 8601 format</a>,
+and 3 means both. Default is
+<strong><tt>1</tt></strong>. </li> <p />
+
+ <li> <tt>-d</tt>&nbsp;<em>dev_style</em>&nbsp;: how <tt>/dev</tt> is
+handled on this system. 0 means a static <tt>/dev</tt>, 1 means
+devtmpfs but not automounted by the kernel at boot time, and 2 means
+devtmpfs automounted by the kernel at boot time. Default is
+<strong><tt>2</tt></strong>. </li> <p />
+
+ <li> <tt>-e</tt>&nbsp;<em>initial_envvar</em>&nbsp;: this option
+can be repeated. For every <em>initial_envvar</em>, s6-linux-init-maker
+will adjust the global environment directory in <em>dir</em>/env.
+<em>initial_envvar</em> must either be of the form <em>VAR</em>,
+to make sure that <em>VAR</em> does not appear in the global
+environment, or of the form <em>VAR=VALUE</em>, to add an
+environment variable <em>VAR</em> with the value <em>VALUE</em>.
+The TZ variable, for instance, is a good candidate to be set in
+the global environment. </li> <p />
+</ul>
+
+</body>
+</html>
diff --git a/doc/upgrade.html b/doc/upgrade.html
new file mode 100644
index 0000000..92acdfc
--- /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-linux-init: how to upgrade</title>
+ <meta name="Description" content="s6-linux-init: how to upgrade" />
+ <meta name="Keywords" content="s6-linux-init installation upgrade" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">s6-linux-init</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> What has changed in s6-linux-init </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..2e5eebc
--- /dev/null
+++ b/package/deps-build
@@ -0,0 +1,5 @@
+/package/prog/skalibs
+/package/admin/execline
+/package/admin/s6-portable-utils
+/package/admin/s6-linux-utils
+/package/admin/s6
diff --git a/package/deps.mak b/package/deps.mak
new file mode 100644
index 0000000..5e669fe
--- /dev/null
+++ b/package/deps.mak
@@ -0,0 +1,8 @@
+#
+# This file has been generated by tools/gen-deps.sh
+#
+
+src/init/s6-linux-init-maker.o src/init/s6-linux-init-maker.lo: src/init/s6-linux-init-maker.c
+
+s6-linux-init-maker: private EXTRA_LIBS :=
+s6-linux-init-maker: src/init/s6-linux-init-maker.o -lskarnet
diff --git a/package/info b/package/info
new file mode 100644
index 0000000..cb108ed
--- /dev/null
+++ b/package/info
@@ -0,0 +1,4 @@
+package=s6-linux-init
+version=0.0.1.0
+category=admin
+package_macro_name=S6_LINUX_INIT
diff --git a/package/modes b/package/modes
new file mode 100644
index 0000000..4b115b4
--- /dev/null
+++ b/package/modes
@@ -0,0 +1 @@
+s6-linux-init-maker 0700
diff --git a/package/targets.mak b/package/targets.mak
new file mode 100644
index 0000000..2330c89
--- /dev/null
+++ b/package/targets.mak
@@ -0,0 +1,6 @@
+BIN_TARGETS :=
+
+SBIN_TARGETS := \
+s6-linux-init-maker
+
+LIBEXEC_TARGETS :=
diff --git a/src/init/deps-exe/s6-linux-init-maker b/src/init/deps-exe/s6-linux-init-maker
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/init/deps-exe/s6-linux-init-maker
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/init/s6-linux-init-maker.c b/src/init/s6-linux-init-maker.c
new file mode 100644
index 0000000..a965cc0
--- /dev/null
+++ b/src/init/s6-linux-init-maker.c
@@ -0,0 +1,377 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pwd.h>
+#include <skalibs/config.h>
+#include <skalibs/uint64.h>
+#include <skalibs/uint.h>
+#include <skalibs/gidstuff.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/allreadwrite.h>
+#include <skalibs/buffer.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/skamisc.h>
+#include <execline/config.h>
+#include <s6-portable-utils/config.h>
+#include <s6-linux-utils/config.h>
+#include <s6/config.h>
+
+#define USAGE "s6-linux-init-maker [ -c basedir ] [ -l tmpfsdir ] [ -b execline_bindir ] [ -u log_user ] [ -g early_getty_cmd ] [ -2 stage2_script ] [ -3 stage3_script ] [ -p initial_path ] [ -m initial_umask ] [ -t timestamp_style ] [ -d dev_style ] [ -e initial_envvar ... ] dir"
+#define dieusage() strerr_dieusage(100, USAGE)
+#define dienomem() strerr_diefu1sys(111, "stralloc_catb") ;
+
+#define CRASH_SCRIPT \
+"#!" EXECLINE_EXTBINPREFIX "execlineb -P\n\n" \
+EXECLINE_EXTBINPREFIX "redirfd -r 0 /dev/console\n" \
+EXECLINE_EXTBINPREFIX "redirfd -w 1 /dev/console\n" \
+EXECLINE_EXTBINPREFIX "fdmove -c 2 1\n" \
+EXECLINE_EXTBINPREFIX "foreground { " \
+S6_PORTABLE_UTILS_EXTBINPREFIX "s6-echo -- " \
+"\"s6-svscan crashed. Dropping to an interactive shell.\" }\n" \
+"/bin/sh -i\n"
+
+#define BANNER1 "s6-init: stage 1"
+#define BANNER2 "s6-init: stage 2"
+
+static char const *slashrun = "/run" ;
+static char const *robase = "/etc/s6" ;
+static char const *init_script = "/etc/rc.init" ;
+static char const *shutdown_script = "/etc/rc.shutdown" ;
+static char const *bindir = "/bin" ;
+static char const *initial_path = SKALIBS_DEFAULTPATH ;
+static char const *early_getty = 0 ;
+static uid_t uncaught_logs_uid = 65534 ;
+static gid_t uncaught_logs_gid = 65534 ;
+static unsigned int initial_umask = 022 ;
+static unsigned int timestamp_style = 1 ;
+static unsigned int slashdev_style = 2 ;
+
+typedef int writetobuf_func_t (buffer *) ;
+typedef writetobuf_func_t *writetobuf_func_t_ref ;
+
+static int early_getty_script (buffer *b)
+{
+ if (buffer_puts(b, "#!" EXECLINE_EXTBINPREFIX "execlineb -P\n\n") < 0
+ || buffer_puts(b, early_getty) < 0
+ || buffer_put(b, "\n", 1) < 0)
+ return 0 ;
+ return 1 ;
+}
+
+static int s6_svscan_log_script (buffer *b)
+{
+ unsigned int sabase = satmp.len ;
+ char fmt[UINT64_FMT] ;
+ if (buffer_puts(b,
+ "#!" EXECLINE_EXTBINPREFIX "execlineb -P\n\n"
+ EXECLINE_EXTBINPREFIX "redirfd -rnb 0 fifo\n"
+ S6_EXTBINPREFIX "s6-applyuidgid -u ") < 0
+ || buffer_put(b, fmt, uint64_fmt(fmt, uncaught_logs_uid)) < 0
+ || buffer_puts(b, " -g ") < 0
+ || buffer_put(b, fmt, gid_fmt(fmt, uncaught_logs_gid)) < 0
+ || buffer_puts(b, " --\n" S6_EXTBINPREFIX "s6-log -bp -- ") < 0
+ || buffer_puts(b, timestamp_style & 1 ? "t " : "") < 0
+ || buffer_puts(b, timestamp_style & 2 ? "T " : "") < 0) return 0 ;
+ if (!string_quote(&satmp, slashrun, str_len(slashrun))) return 0 ;
+ if (buffer_put(b, satmp.s + sabase, satmp.len - sabase) < 0)
+ {
+ satmp.len = sabase ;
+ return 0 ;
+ }
+ satmp.len = sabase ;
+ if (buffer_puts(b, "/uncaught-logs\n") < 0) return 0 ;
+ return 1 ;
+}
+
+static int finish_script (buffer *b)
+{
+ unsigned int sabase = satmp.len ;
+ if (buffer_puts(b,
+ "#!" EXECLINE_EXTBINPREFIX "execlineb -S0\n\n"
+ EXECLINE_EXTBINPREFIX "cd /\n"
+ EXECLINE_EXTBINPREFIX "redirfd -w 2 /dev/console\n"
+ EXECLINE_EXTBINPREFIX "fdmove -c 1 2\n"
+ EXECLINE_EXTBINPREFIX "wait { }\n") < 0
+ || !string_quote(&satmp, shutdown_script, str_len(shutdown_script))) return 0 ;
+ if (buffer_put(b, satmp.s + sabase, satmp.len - sabase) < 0)
+ {
+ satmp.len = sabase ;
+ return 0 ;
+ }
+ satmp.len = sabase ;
+ if (buffer_puts(b, " ${@}\n") < 0) return 0 ;
+ return 1 ;
+}
+
+static void cleanup (char const *base)
+{
+ int e = errno ;
+ rm_rf(base) ;
+ errno = e ;
+}
+
+static void auto_dir (char const *base, char const *dir, uid_t uid, gid_t gid, unsigned int mode)
+{
+ unsigned int clen = str_len(base) ;
+ unsigned int dlen = str_len(dir) ;
+ char fn[clen + dlen + 2] ;
+ byte_copy(fn, clen, base) ;
+ fn[clen] = dlen ? '/' : 0 ;
+ byte_copy(fn + clen + 1, dlen + 1, dir) ;
+ if (mkdir(fn, mode) < 0
+ || ((uid || gid) && (chown(fn, uid, gid) < 0 || chmod(fn, mode) < 0)))
+ {
+ cleanup(base) ;
+ strerr_diefu2sys(111, "mkdir ", fn) ;
+ }
+}
+
+static void auto_file (char const *base, char const *file, char const *s, unsigned int n, int executable)
+{
+ unsigned int clen = str_len(base) ;
+ unsigned int flen = str_len(file) ;
+ char fn[clen + flen + 2] ;
+ byte_copy(fn, clen, base) ;
+ fn[clen] = '/' ;
+ byte_copy(fn + clen + 1, flen + 1, file) ;
+ if (!openwritenclose_unsafe(fn, s, n)
+ || (executable && chmod(fn, 0755) < 0))
+ {
+ cleanup(base) ;
+ strerr_diefu2sys(111, "write to ", fn) ;
+ }
+}
+
+static void auto_fifo (char const *base, char const *fifo)
+{
+ unsigned int baselen = str_len(base) ;
+ unsigned int fifolen = str_len(fifo) ;
+ char fn[baselen + fifolen + 2] ;
+ byte_copy(fn, baselen, base) ;
+ fn[baselen] = '/' ;
+ byte_copy(fn + baselen + 1, fifolen + 1, fifo) ;
+ if (mkfifo(fn, 0600) < 0)
+ {
+ cleanup(base) ;
+ strerr_diefu2sys(111, "mkfifo ", fn) ;
+ }
+}
+
+static void auto_script (char const *base, char const *file, writetobuf_func_t_ref scriptf)
+{
+ char buf[4096] ;
+ buffer b ;
+ int fd ;
+ unsigned int baselen = str_len(base) ;
+ unsigned int filelen = str_len(file) ;
+ char fn[baselen + filelen + 2] ;
+ byte_copy(fn, baselen, base) ;
+ fn[baselen] = '/' ;
+ byte_copy(fn + baselen + 1, filelen + 1, file) ;
+ fd = open_trunc(fn) ;
+ if (fd < 0 || ndelay_off(fd) < 0 || fchmod(fd, 0755) < 0)
+ {
+ cleanup(base) ;
+ strerr_diefu3sys(111, "open ", fn, " for script writing") ;
+ }
+ buffer_init(&b, &fd_writesv, fd, buf, 4096) ;
+ if (!(*scriptf)(&b) || !buffer_flush(&b))
+ {
+ cleanup(base) ;
+ strerr_diefu2sys(111, "write to ", fn) ;
+ }
+ close(fd) ;
+}
+
+static void make_image (char const *base)
+{
+ auto_dir(base, "run-image", 0, 0, 0755) ;
+ auto_dir(base, "run-image/uncaught-logs", uncaught_logs_uid, uncaught_logs_gid, 02700) ;
+ auto_dir(base, "run-image/service", 0, 0, 0755) ;
+ auto_dir(base, "run-image/service/.s6-svscan", 0, 0, 0755) ;
+ auto_file(base, "run-image/service/.s6-svscan/crash", CRASH_SCRIPT, sizeof(CRASH_SCRIPT) - 1, 1) ;
+ auto_script(base, "run-image/service/.s6-svscan/finish", &finish_script) ;
+ auto_dir(base, "run-image/service/s6-svscan-log", 0, 0, 0755) ;
+ auto_fifo(base, "run-image/service/s6-svscan-log/fifo") ;
+ auto_script(base, "run-image/service/s6-svscan-log/run", &s6_svscan_log_script) ;
+ if (early_getty)
+ {
+ auto_dir(base, "run-image/service/early-getty", 0, 0, 0755) ;
+ auto_script(base, "run-image/service/early-getty/run", &early_getty_script) ;
+ }
+}
+
+static void make_env (char const *base, char const *modif, unsigned int modiflen)
+{
+ auto_dir(base, "env", 0, 0, 0755) ;
+ while (modiflen)
+ {
+ unsigned int len = str_len(modif) ;
+ unsigned int pos = byte_chr(modif, len, '=') ;
+ char fn[5 + pos] ;
+ byte_copy(fn, 4, "env/") ;
+ byte_copy(fn + 4, pos, modif) ;
+ fn[4 + pos] = 0 ;
+
+ if (pos + 1 < len) auto_file(base, fn, modif + pos + 1, len - pos - 1, 0) ;
+ else if (pos + 1 == len) auto_file(base, fn, "\n", 1, 0) ;
+ else auto_file(base, fn, "", 0, 0) ;
+ modif += len+1 ; modiflen -= len+1 ;
+ }
+}
+
+static int make_init_script (buffer *b)
+{
+ unsigned int sabase = satmp.len, pos, pos2 ;
+ char fmt[UINT_OFMT] ;
+ if (buffer_puts(b, "#!") < 0
+ || buffer_puts(b, bindir) < 0
+ || buffer_puts(b, "/execlineb -P\n\n") < 0
+ || buffer_puts(b, bindir) < 0
+ || buffer_puts(b, "/export PATH ") < 0
+ || !string_quote(&satmp, initial_path, str_len(initial_path))) return 0 ;
+ if (buffer_put(b, satmp.s + sabase, satmp.len - sabase) < 0) goto err ;
+ satmp.len = sabase ;
+ if (buffer_put(b, "\n", 1) < 0
+ || buffer_puts(b, bindir) < 0
+ || buffer_puts(b, "/cd /\n"
+ EXECLINE_EXTBINPREFIX "umask 0") < 0
+ || buffer_put(b, fmt, uint_ofmt(fmt, initial_umask)) < 0
+ || buffer_puts(b, "\n"
+ EXECLINE_EXTBINPREFIX "if { "
+ S6_PORTABLE_UTILS_EXTBINPREFIX "s6-echo -- \"" BANNER1 "\" }\n"
+ EXECLINE_EXTBINPREFIX "if { "
+ S6_LINUX_UTILS_EXTBINPREFIX "s6-mount -nwt tmpfs -o mode=0755 tmpfs ") < 0
+ || !string_quote(&satmp, slashrun, str_len(slashrun))) return 0 ;
+ pos = satmp.len ;
+ if (buffer_put(b, satmp.s + sabase, pos - sabase) < 0
+ || buffer_puts(b, " }\n"
+ EXECLINE_EXTBINPREFIX "if { "
+ S6_PORTABLE_UTILS_EXTBINPREFIX "s6-hiercopy ") < 0
+ || !string_quote(&satmp, robase, str_len(robase))) return 0 ;
+ pos2 = satmp.len ;
+ if (buffer_put(b, satmp.s + pos, pos2 - pos) < 0
+ || buffer_puts(b, "/run-image ") < 0
+ || buffer_put(b, satmp.s + sabase, pos - sabase) < 0
+ || buffer_puts(b, " }\n") < 0) goto err ;
+ if (slashdev_style == 1)
+ {
+ if (buffer_puts(b,
+ EXECLINE_EXTBINPREFIX "if { "
+ S6_LINUX_UTILS_EXTBINPREFIX "s6-mount -nt devtmpfs dev /dev }\n") < 0)
+ goto err ;
+ }
+ if (buffer_puts(b,
+ EXECLINE_EXTBINPREFIX "redirfd -r 0 /dev/null\n"
+ S6_EXTBINPREFIX "s6-envdir -I -- ") < 0
+ || buffer_put(b, satmp.s + pos, pos2 - pos) < 0
+ || buffer_puts(b, "/env\n"
+ EXECLINE_EXTBINPREFIX "background\n{\n "
+ S6_EXTBINPREFIX "s6-setsid --\n "
+ EXECLINE_EXTBINPREFIX "redirfd -w 2 ") < 0
+ || buffer_put(b, satmp.s + sabase, pos - sabase) < 0
+ || buffer_puts(b, "/service/s6-svscan-log/fifo\n "
+ EXECLINE_EXTBINPREFIX "if { "
+ S6_PORTABLE_UTILS_EXTBINPREFIX "s6-echo -- \"" BANNER2 "\" }\n "
+ EXECLINE_EXTBINPREFIX "fdmove -c 1 2\n ") < 0
+ || !string_quote(&satmp, init_script, str_len(init_script))
+ || buffer_put(b, satmp.s + pos2, satmp.len - pos2) < 0
+ || buffer_puts(b, "\n}\n"
+ EXECLINE_EXTBINPREFIX "unexport !\n"
+ EXECLINE_EXTBINPREFIX "redirfd -wnb 1 ") < 0
+ || buffer_put(b, satmp.s + sabase, pos - sabase) < 0
+ || buffer_puts(b,
+ "/service/s6-svscan-log/fifo\n"
+ EXECLINE_EXTBINPREFIX "fdmove -c 2 1\n"
+ EXECLINE_EXTBINPREFIX "cd ") < 0
+ || buffer_put(b, satmp.s + sabase, pos - sabase) < 0
+ || buffer_puts(b, "/service\n") < 0) goto err ;
+ if (sizeof(S6_EXTBINPREFIX) > 1)
+ {
+ if (buffer_puts(b, EXECLINE_EXTBINPREFIX "exec -a s6-svscan --\n") < 0)
+ goto err ;
+ }
+ if (buffer_puts(b, S6_EXTBINPREFIX "s6-svscan -t0\n") < 0) goto err ;
+ return 1 ;
+ err:
+ satmp.len = sabase ;
+ return 0 ;
+}
+
+int main (int argc, char const *const *argv)
+{
+ char const *catchall_user = "nobody" ;
+ stralloc modif = STRALLOC_ZERO ;
+ PROG = "s6-linux-init-maker" ;
+ {
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ register int opt = subgetopt_r(argc, argv, "c:l:b:u:g:2:3:p:m:t:d:e:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 'c' : robase = l.arg ; break ;
+ case 'l' : slashrun = l.arg ; break ;
+ case 'b' : bindir = l.arg ; break ;
+ case 'u' : catchall_user = l.arg ; break ;
+ case 'g' : early_getty = l.arg ; break ;
+ case '2' : init_script = l.arg ; break ;
+ case '3' : shutdown_script = l.arg ; break ;
+ case 'p' : initial_path = l.arg ; break ;
+ case 'm' : if (!uint0_oscan(l.arg, &initial_umask)) dieusage() ; break ;
+ case 't' : if (!uint0_scan(l.arg, &timestamp_style)) dieusage() ; break ;
+ case 'd' : if (!uint0_scan(l.arg, &slashdev_style)) dieusage() ; break ;
+ case 'e' : if (!stralloc_catb(&modif, l.arg, str_len(l.arg) + 1)) dienomem() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ }
+ if (!argc) dieusage() ;
+
+ if (robase[0] != '/')
+ strerr_dief3x(100, "base directory ", robase, " is not absolute") ;
+ if (slashrun[0] != '/')
+ strerr_dief3x(100, "tmpfs directory ", slashrun, " is not absolute") ;
+ if (bindir[0] != '/')
+ strerr_dief3x(100, "initial location for binaries ", bindir, " is not absolute") ;
+ if (init_script[0] != '/')
+ strerr_dief3x(100, "stage 2 script location ", init_script, " is not absolute") ;
+ if (shutdown_script[0] != '/')
+ strerr_dief3x(100, "stage 3 script location ", shutdown_script, " is not absolute") ;
+ if (timestamp_style > 3)
+ strerr_dief1x(100, "-t timestamp_style must be 0, 1, 2 or 3") ;
+ if (slashdev_style > 2)
+ strerr_dief1x(100, "-d dev_style must be 0, 1 or 2") ;
+
+
+ {
+ struct passwd *pw = getpwnam(catchall_user) ;
+ if (!pw)
+ {
+ if (errno)
+ strerr_diefu2sys(111, "getpwnam for ", catchall_user) ;
+ else
+ strerr_dief3x(100, "getpwnam for ", catchall_user, ": no such user") ;
+ }
+ uncaught_logs_uid = pw->pw_uid ;
+ uncaught_logs_gid = pw->pw_gid ;
+ }
+
+ if (mkdir(argv[0], 0755) < 0)
+ strerr_diefu2sys(111, "mkdir ", argv[0]) ;
+
+ make_env(argv[0], modif.s, modif.len) ;
+ stralloc_free(&modif) ;
+ make_image(argv[0]) ;
+ if (!make_init_script(buffer_1) || !buffer_flush(buffer_1))
+ strerr_diefu1sys(111, "write to stdout") ;
+ return 0 ;
+}
diff --git a/tools/gen-deps.sh b/tools/gen-deps.sh
new file mode 100755
index 0000000..4615f28
--- /dev/null
+++ b/tools/gen-deps.sh
@@ -0,0 +1,83 @@
+#!/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=
+ while read dep ; do
+ deps="$deps src/$dir/$dep"
+ done < src/$dir/deps-lib/$file
+ echo "lib$file.a:$deps"
+ echo "lib${file}.so:$(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 '^\${.*_LIB}' ; then
+ libs="$libs $dep"
+ else
+ deps="$deps $dep"
+ fi
+ done < src/$dir/deps-exe/$file
+ echo "$file: private 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