about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--INSTALL23
-rw-r--r--Makefile30
-rw-r--r--NEWS3
-rwxr-xr-xconfigure9
-rw-r--r--doc/index.html11
-rw-r--r--doc/s6-linux-utils.html53
-rw-r--r--doc/upgrade.html2
-rw-r--r--package/modes1
-rw-r--r--package/targets.mak36
-rwxr-xr-xtools/gen-multicall.sh86
11 files changed, 232 insertions, 24 deletions
diff --git a/.gitignore b/.gitignore
index b360b5b..6231133 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,8 @@
 /lib*.so.xyzzy
 /config.mak
 /src/include/s6-linux-utils/config.h
+/src/multicall/s6-linux-utils.c
+/s6-linux-utils
 /rngseed
 /s6-chroot
 /s6-freeramdisk
diff --git a/INSTALL b/INSTALL
index c4d428d..5a8fa61 100644
--- a/INSTALL
+++ b/INSTALL
@@ -163,3 +163,26 @@ without relying on a PATH search.
  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.
+
+
+* Multicall binary
+  ----------------
+
+ Starting with version 2.6.1.0, the s6-linux-utils package comes
+with an alternative build in the form of a multicall binary, simply
+called "s6-linux-utils", that includes the functionality of *all*
+the other binaries; it switches functionalities depending on the name
+it is called with, or the subcommand it is given:
+"s6-linux-utils s6-ps -H" will print a tree of the current running
+processes, same as "s6-ps -H" if s6-ps is a link to the
+s6-linux-utils program.
+
+ To use this, use the --enable-multicall option to configure. Only
+the s6-linux-utils binary will be built, and other programs will be
+created as symbolic links to s6-linux-utils at installation time.
+
+ The multicall setup saves a lot of disk space, at the price of
+am unnoticeable amount of CPU usage. RAM usage is about equivalent
+and difficult to assess. The setup is meant for embedded devices
+or small distributions with a focus on saving disk space.
+
diff --git a/Makefile b/Makefile
index cd6c7f0..0fc3d40 100644
--- a/Makefile
+++ b/Makefile
@@ -17,8 +17,9 @@ CC = $(error Please use ./configure first)
 STATIC_LIBS :=
 SHARED_LIBS :=
 INTERNAL_LIBS :=
-EXTRA_TARGETS :=
 LIB_DEFS :=
+BIN_SYMLINKS :=
+EXTRA_TEMP :=
 
 define library_definition
 LIB$(firstword $(subst =, ,$(1))) := lib$(lastword $(subst =, ,$(1))).$(if $(DO_ALLSTATIC),a,so).xyzzy
@@ -53,14 +54,14 @@ RANLIB := $(CROSS_COMPILE)ranlib
 STRIP := $(CROSS_COMPILE)strip
 INSTALL := ./tools/install.sh
 
-ALL_BINS := $(LIBEXEC_TARGETS) $(BIN_TARGETS)
+ALL_BINS := $(BIN_TARGETS) $(LIBEXEC_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)
+	@exec rm -f $(ALL_LIBS) $(ALL_BINS) $(EXTRA_TEMP) $(wildcard src/*/*.o src/*/*.lo)
 
 distclean: clean
 	@exec rm -f config.mak src/include/$(package)/config.h
@@ -84,7 +85,7 @@ 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-bin: $(BIN_TARGETS:%=$(DESTDIR)$(bindir)/%) $(BIN_SYMLINKS:%=$(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)/%)
@@ -96,7 +97,7 @@ $(DESTDIR)$(exthome): $(DESTDIR)$(home)
 
 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/%)
+global-links: $(DESTDIR)$(exthome) $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M)) $(BIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%) $(BIN_SYMLINKS:%=$(DESTDIR)$(sproot)/command/%)
 
 $(DESTDIR)$(sproot)/command/%: $(DESTDIR)$(home)/command/%
 	exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/command/$(<F) $@
@@ -116,11 +117,20 @@ $(DESTDIR)$(dynlibdir)/lib%.so $(DESTDIR)$(dynlibdir)/lib%.so.$(version_M): lib%
 	$(INSTALL) -l $(@F).$(version) $@.$(version_M) && \
 	exec $(INSTALL) -l $(@F).$(version_M) $@
 
-$(DESTDIR)$(libexecdir)/% $(DESTDIR)$(bindir)/%: % package/modes
-	exec $(INSTALL) -D -m 600 $< $@
-	grep -- ^$(@F) < package/modes | { read name mode owner && \
-	if [ x$$owner != x ] ; then chown -- $$owner $@ ; fi && \
-	chmod $$mode $@ ; }
+$(LIBEXEC_TARGETS:%=$(DESTDIR)$(libexecdir)/%): $(DESTDIR)$(libexecdir)/%: % package/modes
+$(BIN_TARGETS:%=$(DESTDIR)$(bindir)/%): $(DESTDIR)$(bindir)/%: % package/modes
+$(LIBEXEC_TARGETS:%=$(DESTDIR)$(libexecdir)/%) $(BIN_TARGETS:%=$(DESTDIR)$(bindir)/%):
+	grep -- ^$(@F) < package/modes | { read name mode og && \
+	if [ x$$og != x ] ; then og="-O $${og}" ; fi && \
+	$(INSTALL) -D -m $$mode $$og $< $@ ; }
+
+define install_symlink_rule
+$(DESTDIR)$(bindir)/$(1): $(DESTDIR)$(bindir)/$$(SYMLINK_TARGET_$(1))
+endef
+
+$(foreach x,$(BIN_SYMLINKS),$(eval $(call install_symlink_rule,$(x))))
+$(BIN_SYMLINKS:%=$(DESTDIR)$(bindir)/%):
+	exec $(INSTALL) -l $(SYMLINK_TARGET_$(@F)) $@
 
 $(DESTDIR)$(libdir)/lib%.a: lib%.a.xyzzy
 	exec $(INSTALL) -D -m 644 $< $@
diff --git a/NEWS b/NEWS
index 72f64ca..975e523 100644
--- a/NEWS
+++ b/NEWS
@@ -3,7 +3,8 @@ Changelog for s6-linux-utils.
 In 2.6.1.0
 ----------
 
- - s6-mount: support for relatime and norelatime options.
+ - s6-mount: modernize option support.
+ - New multicall binary: s6-linux-utils.
 
 
 In 2.6.0.1
diff --git a/configure b/configure
index f407635..359d7fc 100755
--- a/configure
+++ b/configure
@@ -47,6 +47,7 @@ Optional features:
                                   hardcode absolute BINDIR/foobar paths instead [disabled]
   --enable-nsss                 use the nsss library for user information [disabled]
   --with-seed-dir=DIR           make DIR the default rngseed directory [/var/lib/rngseed]
+  --enable-multicall            build a multicall binary [disabled]
 
 EOF
 exit 0
@@ -150,6 +151,7 @@ allpic=true
 slashpackage=false
 abspath=false
 usensss=false
+multicall=false
 sproot=
 home=
 exthome=
@@ -194,6 +196,8 @@ for arg ; do
     --disable-absolute-paths|--enable-absolute-paths=no) abspath=false ;;
     --enable-nsss|--enable-nsss=yes) usensss=true ;;
     --disable-nsss|--enable-nsss=no) usensss=false ;;
+    --enable-multicall|--enable-multicall=yes) multicall=true ;;
+    --disable-multicall|--enable-multicall=no) multicall=false ;;
     --with-seed-file=*) seed=${arg#*=} ;;
     --enable-*|--disable-*|--with-*|--without-*|--*dir=*) ;;
     --host=*|--target=*) target=${arg#*=} ;;
@@ -451,6 +455,11 @@ else
   echo "LIBNSSS :="
   echo "MAYBEPTHREAD_LIB :="
 fi
+if $multicall ; then
+  echo "MULTICALL := 1"
+else
+  echo "MULTICALL :="
+fi
 
 exec 1>&3 3>&-
 echo "  ... done."
diff --git a/doc/index.html b/doc/index.html
index d46cf3d..898b002 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -77,6 +77,8 @@ of the s6-linux-utils git repository. </li>
 
 <ul>
  <li> See the enclosed INSTALL file for installation details. </li>
+ <li> Starting with version 2.6.1.0, you can use the
+<tt>--enable-multicall</tt> configure option to save disk space. </li>
 </ul>
 
 <h3> Upgrade notes </h3>
@@ -99,6 +101,9 @@ the previous versions of s6-linux-utils and the current one. </li>
 126 if they fail to execute into a program for another reason.
 </p>
 
+<p>
+ (Miscellaneous tools)
+</p>
 <ul>
 <li><a href="rngseed.html">The <tt>rngseed</tt> program</a></li>
 <li><a href="s6-chroot.html">The <tt>s6-chroot</tt> program</a></li>
@@ -112,6 +117,12 @@ the previous versions of s6-linux-utils and the current one. </li>
 <li><a href="s6-swapon.html">The <tt>s6-swapon</tt> program</a></li>
 <li><a href="s6-umount.html">The <tt>s6-umount</tt> program</a></li>
 </ul>
+<p>
+ (Multicall configuration)
+</p>
+<ul>
+ <li> The <a href="s6-linux-utils.html"><tt>s6-linux-utils</tt></a> multicall binary </li>
+</ul>
 
 <h2> Related resources </h2>
 
diff --git a/doc/s6-linux-utils.html b/doc/s6-linux-utils.html
new file mode 100644
index 0000000..d366937
--- /dev/null
+++ b/doc/s6-linux-utils.html
@@ -0,0 +1,53 @@
+<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-utils: the s6-linux-utils multicall binary</title>
+    <meta name="Description" content="s6-linux-utils: the s6-linux-utils multicall binary" />
+    <meta name="Keywords" content="s6-linux-utils command multicall" />
+    <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
+  </head>
+<body>
+
+<p>
+<a href="index.html">s6-linux-utils</a><br />
+<a href="//skarnet.org/software/">Software</a><br />
+<a href="//skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>s6-linux-utils</tt> multicall binary </h1>
+
+<p>
+The <tt>s6-linux-utils</tt> program is only available when the
+<tt>--enable-multicall</tt> option has been given to the <tt>configure</tt>
+program at build time. In this configuration, <tt>s6-linux-utils</tt> is
+a multicall binary implementing the functionality of <em>all</em>
+the programs in the s6-linux-utils package; and the other programs, instead
+of being executables of their own, are symbolic links to the
+s6-linux-utils binary.
+</p>
+
+<h2> Interface </h2>
+
+<pre>
+     s6-linux-utils <em>subcommand</em> <em>subcommand_arguments...</em>
+</pre>
+
+<p>
+ s6-linux-utils will run the <em>subcommand</em> will its arguments. For
+instance, <tt>s6-linux-utils s6-ps -H</tt> will run the equivalent of the
+<a href="s6-ps.html">s6-ps</a> program, so this command will print a
+tree of the currently running processes.
+</p>
+
+<p>
+ Alternatively, if s6-linux-utils is called with the name of an existing
+command, it will run the equivalent of that command. For instance,
+if the <tt>/usr/bin/s6-ps</tt> file is a (hard or symbolic) link to
+the <tt>s6-linux-utils</tt> binary, <tt>/usr/bin/s6-ps -H</tt> will print
+a tree of the currently running processes.
+</p>
+
+</body>
+</html>
diff --git a/doc/upgrade.html b/doc/upgrade.html
index 79e9ef1..eaa7187 100644
--- a/doc/upgrade.html
+++ b/doc/upgrade.html
@@ -23,6 +23,8 @@
 <ul>
  <li> <a href="//skarnet.org/software/skalibs/">skalibs</a>
 dependency bumped to 2.13.1.0. </li>
+ <li> New <a href="s6-linux-utils.html">s6-linux-utils</a>
+multicall binary. </li>
 </ul>
 
 <h2> in 2.6.0.1 </h2>
diff --git a/package/modes b/package/modes
index 46b4623..aad1e20 100644
--- a/package/modes
+++ b/package/modes
@@ -9,3 +9,4 @@ s6-ps			0755
 s6-swapoff		0744
 s6-swapon		0744
 s6-umount		0755
+s6-linux-utils		0755
diff --git a/package/targets.mak b/package/targets.mak
index fb7af4c..6403a9b 100644
--- a/package/targets.mak
+++ b/package/targets.mak
@@ -1,14 +1,24 @@
-BIN_TARGETS := \
-rngseed \
-s6-chroot \
-s6-freeramdisk \
-s6-hostname \
-s6-logwatch \
-s6-mount \
-s6-pivotchroot \
-s6-ps \
-s6-swapoff \
-s6-swapon \
-s6-umount
-
 LIBEXEC_TARGETS :=
+
+ifeq ($(MULTICALL),1)
+
+BIN_TARGETS := $(package)
+BIN_SYMLINKS := $(notdir $(wildcard src/$(package)/deps-exe/*))
+EXTRA_TEMP := src/multicall/$(package).c
+
+define symlink_definition
+SYMLINK_TARGET_$(1) := $(package)
+endef
+$(foreach name,$(BIN_SYMLINKS),$(eval $(call symlink_definition,$(name))))
+
+src/multicall/$(package).c: tools/gen-multicall.sh src/$(package)/deps-exe
+	./tools/gen-multicall.sh $(package) > src/multicall/$(package).c
+
+src/multicall/$(package).o: src/multicall/$(package).c src/include/$(package)/config.h
+
+else
+
+BIN_TARGETS := $(notdir $(wildcard src/$(package)/deps-exe/*))
+BIN_SYMLINKS :=
+
+endif
diff --git a/tools/gen-multicall.sh b/tools/gen-multicall.sh
new file mode 100755
index 0000000..843f4df
--- /dev/null
+++ b/tools/gen-multicall.sh
@@ -0,0 +1,86 @@
+#!/bin/sh -e
+
+P="$1"
+p=`echo $P | tr - _`
+
+echo '/* ISC license. */'
+echo
+echo '#include <skalibs/nonposix.h>'
+echo
+{ echo '#include <string.h>' ; echo '#include <stdlib.h>' ; cat src/$P/*.c | grep '^#include <' | grep -vF '<skalibs/' | grep -vF '<linux/' | grep -vF "<$P/" ; } | sort -u
+
+cat <<EOF
+
+#include <linux/random.h>
+
+#include <skalibs/skalibs.h>
+
+#include <$P/config.h>
+#include "s6ps.h"
+
+typedef int main_func (int, char const *const *, char const *const *) ;
+typedef main_func *main_func_ref ;
+
+typedef struct multicall_app_s multicall_app, *multicall_app_ref ;
+struct multicall_app_s
+{
+  char const *name ;
+  main_func_ref mainf ;
+} ;
+
+static int multicall_app_cmp (void const *a, void const *b)
+{
+  char const *name = a ;
+  multicall_app const *p = b ;
+  return strcmp(name, p->name) ;
+}
+EOF
+
+for i in `ls -1 src/$P/deps-exe` ; do
+  j=`echo $i | tr - _`
+  echo
+  grep -v '^#include ' < src/$P/${i}.c | grep -vF '/* ISC license. */' | sed -e "s/int main (.*)$/int ${j}_main (int argc, char const *const *argv, char const *const *envp)/"
+  echo
+  echo '#undef USAGE'
+  echo '#undef dieusage'
+  echo '#undef dienomem'
+done
+
+cat <<EOF
+
+static int ${p}_main (int, char const *const *, char const *const *) ;
+
+static multicall_app const multicall_apps[] =
+{
+EOF
+
+for i in `{ echo $P ; ls -1 src/$P/deps-exe ; } | sort` ; do
+  j=`echo $i | tr - _`
+  echo "  { .name = \"${i}\", .mainf = &${j}_main },"
+done
+
+cat <<EOF
+} ;
+
+#define USAGE "$P subcommand [ arguments... ]"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+static int ${p}_main (int argc, char const *const *argv, char const *const *envp)
+{
+  multicall_app const *p ;
+  PROG = "$P" ;
+  if (argc < 2) dieusage() ;
+  p = bsearch(argv[1], multicall_apps, sizeof(multicall_apps) / sizeof(multicall_app), sizeof(multicall_app), &multicall_app_cmp) ;
+  if (!p) strerr_dief2x(100, "unknown subcommand: ", argv[1]) ;
+  return (*(p->mainf))(argc-1, argv+1, envp) ;
+}
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+  multicall_app const *p ;
+  char const *name = strrchr(argv[0], '/') ;
+  if (name) name++ ; else name = argv[0] ;
+  p = bsearch(name, multicall_apps, sizeof(multicall_apps) / sizeof(multicall_app), sizeof(multicall_app), &multicall_app_cmp) ;
+  return p ? (*(p->mainf))(argc, argv, envp) : ${p}_main(argc, argv, envp) ;
+}
+EOF