summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--AUTHORS1
-rw-r--r--Makefile.am24
-rw-r--r--NEWS18
-rw-r--r--README18
-rw-r--r--bootstrap.conf7
-rwxr-xr-xbuild-aux/gen-lists-of-programs.sh7
-rwxr-xr-xbuild-aux/gen-single-binary.sh110
-rw-r--r--configure.ac76
-rw-r--r--doc/coreutils.texi19
-rw-r--r--man/coreutils.x4
-rw-r--r--man/local.mk153
-rw-r--r--po/POTFILES.in1
-rw-r--r--src/.gitignore1
-rw-r--r--src/coreutils-arch.c32
-rw-r--r--src/coreutils-dir.c32
-rw-r--r--src/coreutils-vdir.c32
-rw-r--r--src/coreutils.c205
-rw-r--r--src/kill.c6
-rw-r--r--src/local.mk61
-rw-r--r--src/readlink.c2
-rw-r--r--src/shuf.c2
-rw-r--r--src/timeout.c8
-rw-r--r--src/truncate.c2
-rwxr-xr-xtests/install/basic-1.sh10
-rw-r--r--tests/local.mk3
-rwxr-xr-xtests/misc/coreutils.sh36
-rwxr-xr-xtests/misc/env.sh15
-rwxr-xr-xtests/misc/help-version.sh2
29 files changed, 744 insertions, 149 deletions
diff --git a/.gitignore b/.gitignore
index 558577d23..02a61e81f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -134,6 +134,7 @@
/m4/xsize.m4
/maint.mk
/man/*.1
+/man/dynamic-deps.mk
/po/*.gmo
/po/*.po
/po/.gitignore
@@ -155,10 +156,15 @@
/po/remove-potcdate.sed
/po/remove-potcdate.sin
/po/stamp-po
+/src/coreutils.h
+/src/coreutils_symlinks
+/src/coreutils_shebangs
/src/cu-progs.mk
/src/fs-latest-magic.h
+/src/libsinglebin_*.a
/src/make-prime-list
/src/primes.h
+/src/single-binary.mk
/src/version.c
/src/version.h
/stamp-h1
diff --git a/AUTHORS b/AUTHORS
index df21e90ac..0296830b3 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -12,6 +12,7 @@ chown: David MacKenzie, Jim Meyering
chroot: Roland McGrath
cksum: Q. Frank Xia
comm: Richard M. Stallman, David MacKenzie
+coreutils: Alex Deymo
cp: Torbjörn Granlund, David MacKenzie, Jim Meyering
csplit: Stuart Kemp, David MacKenzie
cut: David M. Ihnat, David MacKenzie, Jim Meyering
diff --git a/Makefile.am b/Makefile.am
index e88dc9c02..fb4af2723 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -50,6 +50,7 @@ EXTRA_DIST = \
bootstrap \
bootstrap.conf \
build-aux/gen-lists-of-programs.sh \
+ build-aux/gen-single-binary.sh \
cfg.mk \
dist-check.mk \
maint.mk \
@@ -57,6 +58,7 @@ EXTRA_DIST = \
thanks-gen
gen_progs_lists = $(top_srcdir)/build-aux/gen-lists-of-programs.sh
+gen_single_binary = $(top_srcdir)/build-aux/gen-single-binary.sh
# Keep these in sync with bootstrap.conf:bootstrap_post_import_hook().
# Use '$(top_srcdir)/m4' and '$(srcdir)/src' for the benefit of non-GNU
@@ -70,6 +72,10 @@ $(srcdir)/src/cu-progs.mk: $(gen_progs_lists)
$(AM_V_GEN)rm -f $@ $@-t \
&& $(SHELL) $(gen_progs_lists) --automake >$@-t \
&& chmod a-w $@-t && mv -f $@-t $@
+$(srcdir)/src/single-binary.mk: $(gen_single_binary) $(srcdir)/src/local.mk
+ $(AM_V_GEN)rm -f $@ $@-t \
+ && $(SHELL) $(gen_single_binary) $(srcdir)/src/local.mk >$@-t \
+ && chmod a-w $@-t && mv -f $@-t $@
ACLOCAL_AMFLAGS = -I m4
@@ -180,6 +186,24 @@ check-git-hook-script-sync:
rm -rf $$t; \
test $$fail = 0
+# If we are building a single-binary, create symlinks or shebangs for
+# the selected tools when installing.
+install-exec-hook:
+ $(AM_V_at)ctrans=$$(printf coreutils | sed -e "$(transform)"); \
+ for p in $(single_binary_progs); do \
+ ptrans=$$(printf '%s' "$$p" | sed -e "$(transform)"); \
+ rm -f $(DESTDIR)$(bindir)/$$ptrans$(EXEEXT) || exit $$?; \
+ if test "x$(single_binary_install_type)" = xshebangs; then \
+ printf '#!%s --coreutils-prog-shebang=%s\n' \
+ $(bindir)/$$ctrans$(EXEEXT) $$p \
+ >$(DESTDIR)$(bindir)/$$ptrans$(EXEEXT) || exit $$?; \
+ chmod a+x,a-w $(DESTDIR)$(bindir)/$$ptrans$(EXEEXT) || exit $$?;\
+ else \
+ $(LN_S) -s $$ctrans$(EXEEXT) \
+ $(DESTDIR)$(bindir)/$$ptrans$(EXEEXT) || exit $$?; \
+ fi \
+ done
+
noinst_LIBRARIES =
MOSTLYCLEANFILES =
CLEANFILES =
diff --git a/NEWS b/NEWS
index 4e90b793b..2bd739683 100644
--- a/NEWS
+++ b/NEWS
@@ -101,6 +101,24 @@ GNU coreutils NEWS -*- outline -*-
od accepts a new option: --endian=TYPE to handle inputs with different byte
orders, or to provide consistent output on systems with disparate endianness.
+ configure accepts the new option --enable-single-binary to build all the
+ selected programs in a single binary called "coreutils". The selected
+ programs can still be called directly using symlinks to "coreutils" or
+ shebangs with the option --coreutils-prog= passed to this program. The
+ install behavior is determined by the option --enable-single-binary=symlinks
+ or --enable-single-binary=shebangs (the default). With the symlinks option,
+ you can't make a second symlink to any program because that will change the
+ name of the called program, which is used by coreutils to determine the
+ desired program. The shebangs option doesn't suffer from this problem, but
+ the /proc/$pid/cmdline file might not be updated on all the platforms. The
+ functionality of each program is not affected but this single binary will
+ depend on all the required dynamic libraries even to run simple programs.
+ If you desire to build some tools outside the single binary file, you can
+ pass the option --enable-single-binary-exceptions=PROG_LIST with the comma
+ separated list of programs you want to build separately. This flag
+ considerably reduces the overall size of the installed binaries which makes
+ it suitable for embedded system.
+
** Changes in behavior
chroot with an argument of "/" no longer implicitly changes the current
diff --git a/README b/README
index fa1a42966..bd0bce590 100644
--- a/README
+++ b/README
@@ -7,15 +7,15 @@ arbitrary limits.
The programs that can be built with this package are:
- [ arch base64 basename cat chcon chgrp chmod chown chroot cksum comm cp
- csplit cut date dd df dir dircolors dirname du echo env expand expr
- factor false fmt fold groups head hostid hostname id install join kill
- link ln logname ls md5sum mkdir mkfifo mknod mktemp mv nice nl nohup
- nproc numfmt od paste pathchk pinky pr printenv printf ptx pwd readlink
- realpath rm rmdir runcon seq sha1sum sha224sum sha256sum sha384sum sha512sum
- shred shuf sleep sort split stat stdbuf stty sum sync tac tail tee test
- timeout touch tr true truncate tsort tty uname unexpand uniq unlink
- uptime users vdir wc who whoami yes
+ [ arch base64 basename cat chcon chgrp chmod chown chroot cksum comm
+ coreutils cp csplit cut date dd df dir dircolors dirname du echo env
+ expand expr factor false fmt fold groups head hostid hostname id install
+ join kill link ln logname ls md5sum mkdir mkfifo mknod mktemp mv nice nl
+ nohup nproc numfmt od paste pathchk pinky pr printenv printf ptx pwd
+ readlink realpath rm rmdir runcon seq sha1sum sha224sum sha256sum sha384sum
+ sha512sum shred shuf sleep sort split stat stdbuf stty sum sync tac tail
+ tee test timeout touch tr true truncate tsort tty uname unexpand uniq
+ unlink uptime users vdir wc who whoami yes
See the file NEWS for a list of major changes in the current release.
diff --git a/bootstrap.conf b/bootstrap.conf
index 98e83bbfd..c0b5f0233 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -346,6 +346,13 @@ bootstrap_post_import_hook ()
# Massage lib/gnulib.mk before using it later in the bootstrapping process.
build-aux/prefix-gnulib-mk --lib-name=$gnulib_name lib/$gnulib_mk
+
+ # Regenerate src/single-binary.mk
+ (mkf=src/single-binary.mk tmp=single-binary.tmp \
+ && rm -f $mkf $tmp \
+ && build-aux/gen-single-binary.sh src/local.mk >$tmp \
+ && chmod a-w $tmp \
+ && mv -f $tmp $mkf)
}
diff --git a/build-aux/gen-lists-of-programs.sh b/build-aux/gen-lists-of-programs.sh
index bf63ee30a..c95e59815 100755
--- a/build-aux/gen-lists-of-programs.sh
+++ b/build-aux/gen-lists-of-programs.sh
@@ -17,6 +17,7 @@ set -e
# use "--enable-install-program=A,B" when invoking configure.
disabled_by_default_progs='
arch
+ coreutils
hostname
'
@@ -178,6 +179,12 @@ END
echo default__progs += $progsdir/$p
done
;;
+ 1,--list-progs)
+ for p in $disabled_by_default_progs $build_if_possible_progs \
+ $normal_progs; do
+ echo $p
+ done
+ ;;
*)
echo "$0: invalid usage" >&2; exit 2
;;
diff --git a/build-aux/gen-single-binary.sh b/build-aux/gen-single-binary.sh
new file mode 100755
index 000000000..463570656
--- /dev/null
+++ b/build-aux/gen-single-binary.sh
@@ -0,0 +1,110 @@
+#!/bin/sh
+
+# Generate the list of rules for the single-binary option based on all the other
+# binaries found in src/local.mk.
+#
+# We need to duplicate the specific rules to build each program into a new
+# static library target. We can't reuse the existing target since we need to
+# create a .a file instead of linking the program. We can't do this at
+# ./configure since the file names need to be available when automake runs
+# to let it generate all the required rules in Makefile.in. The configure
+# step will select which ones will be used to build, but they need to be
+# generated beforehand.
+#
+# Instead of maintaining a duplicated list of rules, we generate the
+# single-binary required rules based on the normal configuration found on
+# src/local.mk with this script.
+
+if test "x$1" = "x"; then
+ echo "Usage: $0 path/to/src/local.mk" >&2
+ exit 1
+fi
+
+set -e
+
+LOCAL_MK=$1
+GEN_LISTS_OF_PROGRAMS="`dirname "$0"`/gen-lists-of-programs.sh"
+
+ALL_PROGRAMS=$($GEN_LISTS_OF_PROGRAMS --list-progs \
+ | grep -v -F -e coreutils -e libstdbuf.so \
+ | tr '[' '_')
+
+# Compute default SOURCES. automake will assume the source file for the
+# src_${cmd} target to be src/${cmd}.c, but we will add rules to generate
+# the lib src_libsinglebin_${cmd}_a which won't match the autogenerated source
+# file. This loop will initialize the default source file and will be reset
+# later if needed.
+for cmd in $ALL_PROGRAMS; do
+ eval "src_${cmd}_SOURCES=src/${cmd}.c"
+done
+
+# Load actual values from src/local.mk. This will read all the variables from
+# the local.mk matching the src_${cmd}_... case.
+while read l; do
+ if echo "$l" | grep -E '^src_\w+ +\+?=' > /dev/null; then
+ var=$(echo $l | cut -f 1 -d ' ')
+ value=$(echo $l | cut -f 2- -d =)
+ if [ "$value" != " \$(LDADD)" ]; then
+ oldvalue=""
+ if echo $l | grep -F '+=' >/dev/null; then
+ eval "oldvalue=\${$var}"
+ fi
+ eval "$var='$oldvalue "${value//\'/\'\"\'\"\'}"'"
+ fi
+ fi
+done < $LOCAL_MK
+
+me=`echo "$0" | sed 's,.*/,,'`
+echo "## Automatically generated by $me. DO NOT EDIT BY HAND!"
+
+# Override the sources for dir and vdir. We use a smaller version of dir and
+# vdir that relies on the ls main.
+src_dir_SOURCES="src/coreutils-dir.c"
+src_dir_LDADD+=" src/libsinglebin_ls.a"
+echo src_libsinglebin_dir_a_DEPENDENCIES = src/libsinglebin_ls.a
+src_vdir_SOURCES="src/coreutils-vdir.c"
+src_vdir_LDADD+=" src/libsinglebin_ls.a"
+echo src_libsinglebin_vdir_a_DEPENDENCIES = src/libsinglebin_ls.a
+
+# Override the sources for arch likewise, using the main from uname.
+src_arch_SOURCES="src/coreutils-arch.c"
+src_arch_LDADD+=" src/libsinglebin_uname.a"
+echo src_libsinglebin_arch_a_DEPENDENCIES = src/libsinglebin_uname.a
+
+for cmd in $ALL_PROGRAMS; do
+ echo "# Command $cmd"
+ echo noinst_LIBRARIES += src/libsinglebin_${cmd}.a
+ base="src_libsinglebin_${cmd}_a"
+ # SOURCES
+ var=src_${cmd}_SOURCES
+ eval "value=\$$var"
+ echo "${base}_SOURCES = $value"
+
+ # LDADD
+ var=src_${cmd}_LDADD
+ eval "value=\$$var"
+ if [ "x$value" != "x" ]; then
+ echo "${base}_ldadd = $value"
+ fi
+
+ # CFLAGS
+ # Hack any other program defining a main() replacing its main by
+ # _single_binary_main_$PROGRAM_NAME.
+ echo "${base}_CFLAGS = \"-Dmain=_single_binary_main_${cmd}(int, char**) " \
+ "ATTRIBUTE_NORETURN; int _single_binary_main_${cmd}\" " \
+ "-Dusage=_usage_${cmd} \$(src_coreutils_CFLAGS)"
+ var=src_${cmd}_CFLAGS
+ eval "value=\$$var"
+ if [ "x$value" != "x" ]; then
+ echo "${base}_CFLAGS += $value"
+ fi
+
+ # CPPFLAGS
+ var=src_${cmd}_CPPFLAGS
+ eval "value=\$$var"
+ if [ "x$value" != "x" ]; then
+ echo "${base}_CPPFLAGS = $value"
+ fi
+done
+
+exit 0
diff --git a/configure.ac b/configure.ac
index 01098cf34..b50f6e14c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -213,6 +213,36 @@ if test "$gl_gcc_warnings" = yes; then
AC_SUBST([GNULIB_TEST_WARN_CFLAGS])
fi
+AC_ARG_ENABLE([single-binary],
+ [AS_HELP_STRING([--enable-single-binary=[shebangs|symlinks]],
+ [Compile all the tools in a single binary, reducing the overall size.
+ When compiled this way, shebangs (default when enabled) or symlinks are
+ installed for each tool that points to the single binary.])],
+ [gl_single_binary=no ;
+ case $enableval in
+ yes) gl_single_binary=shebangs ;;
+ no|shebangs|symlinks) gl_single_binary=$enableval ;;
+ *) AC_MSG_ERROR([bad value $enableval for single-binary option.
+ Options are: symlinks, shebangs, no.]) ;;
+ esac],
+ [gl_single_binary=no]
+)
+AC_ARG_ENABLE([single-binary-exceptions],
+ [AS_HELP_STRING([--enable-single-binary-exceptions=PROG_LIST],
+ [When used with --enable-single-binary, exclude the PROG_LIST from
+ it, so these programs are compiled as separated files
+ (comma-separated, default none))])],
+ [gl_single_binary_exceptions=$enableval],
+ [gl_single_binary_exceptions=]
+)
+if test "$gl_single_binary" = 'symlinks'; then
+ if ! test "`echo ls | sed \"$program_transform_name\"`" = 'ls'; then
+ AC_MSG_ERROR([program name transformations are not currently supported
+ with --enable-single-binary=symlinks.])
+ fi
+fi
+AM_CONDITIONAL([SINGLE_BINARY], [test "$gl_single_binary" != no])
+
AC_FUNC_FORK
optional_bin_progs=
@@ -479,6 +509,52 @@ man1_MANS=`
# a distribution tarball.
EXTRA_MANS=`for p in $no_install_progs_default; do echo man/$p.1; done`
+# Replace all the programs by the single binary and symlinks if specified.
+single_binary_progs=
+single_binary_libs=
+single_binary_deps=
+single_binary_install_type=
+if test "$gl_single_binary" != no; then
+ man1_MANS="$man1_MANS man/coreutils.1"
+ # Convert the list to a space separated list
+ gl_single_binary_exceptions=`echo $gl_single_binary_exceptions | tr ',' ' '`
+
+ single_binary_progs=`echo $optional_bin_progs`
+ optional_bin_progs="coreutils"
+ for prog in $gl_single_binary_exceptions; do
+ # Fail if requested to exclude a program than was not part of coreutils.
+ case " $single_binary_progs " in
+ *" $prog "*)
+ gl_REMOVE_PROG([single_binary_progs], [$prog]) ;
+ gl_ADD_PROG([optional_bin_progs], [$prog]) ;;
+ *) AC_MSG_ERROR(['$prog' is not being compiled.]) ;;
+ esac
+ done
+
+ # single_binary_libs holds the list of libs required by the selected
+ # programs, such as for example -lrt.
+ single_binary_libs=`
+ for p in $single_binary_progs; do
+ # Convert '[' to '_'
+ test x"$p" = x'@<:@' && p='_'
+ printf '$(src_libsinglebin_%s_a_ldadd) ' "$p"
+ done`
+ # single_binary_deps holds the list of libsinglebin_*.a files that have the
+ # compiled code of each selected program in a "library" format.
+ single_binary_deps=`
+ for p in $single_binary_progs; do
+ # Convert '[' to '_'
+ test x"$p" = x'@<:@' && p='_'
+ printf 'src/libsinglebin_%s.a ' "$p"
+ done`
+ single_binary_install_type="$gl_single_binary"
+fi
+AC_SUBST([single_binary_progs], [$single_binary_progs])
+AC_SUBST([single_binary_libs], [$single_binary_libs])
+AC_SUBST([single_binary_deps], [$single_binary_deps])
+AC_SUBST([single_binary_install_type], [$single_binary_install_type])
+
+
# The programs built and installed by "make && make install".
# Since this is AC_SUBST'd, Automake won't be able to perform rewrite
# with $(EXEEXT) appending on it, so we have to do it ourselves -- in
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 96220c350..19a523d8e 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -47,6 +47,7 @@
* chroot: (coreutils)chroot invocation. Specify the root directory.
* cksum: (coreutils)cksum invocation. Print POSIX CRC checksum.
* comm: (coreutils)comm invocation. Compare sorted files by line.
+* coreutils: (coreutils)coreutils invocation. Multi-call program.
* cp: (coreutils)cp invocation. Copy files.
* csplit: (coreutils)csplit invocation. Split by context.
* cut: (coreutils)cut invocation. Print selected parts of lines.
@@ -229,6 +230,7 @@ Common Options
* Traversing symlinks:: Traversing symlinks to directories
* Treating / specially:: Treating / specially
* Standards conformance:: Standards conformance
+* coreutils invocation:: Multi-call binary invocation
Output of entire files
@@ -771,6 +773,7 @@ name.
* Treating / specially:: --preserve-root and --no-preserve-root.
* Special built-in utilities:: @command{break}, @command{:}, @dots{}
* Standards conformance:: Conformance to the POSIX standard.
+* coreutils invocation:: Multi-call binary invocation.
@end menu
@@ -1494,6 +1497,22 @@ that assumes an older version of POSIX and uses @samp{sort +1}
or @samp{tail +10}, you can work around any compatibility problems by setting
@samp{_POSIX2_VERSION=199209} in your environment.
+@node coreutils invocation
+@section @command{coreutils}: Multi-call binary
+
+@pindex multicall
+@cindex combined
+@cindex calling combined multi-call binary
+
+@command{coreutils} invokes an individual utility, either
+implicitly selected by the last component of @samp{argv[0]},
+or by explicitly calling @command{coreutils} with the
+@option{--coreutils-prog} option. Synopsis:
+
+@example
+coreutils @option{--coreutils-prog=PROGRAM} @dots{}
+@end example
+
@node Output of entire files
@chapter Output of entire files
diff --git a/man/coreutils.x b/man/coreutils.x
new file mode 100644
index 000000000..a7a487999
--- /dev/null
+++ b/man/coreutils.x
@@ -0,0 +1,4 @@
+[NAME]
+coreutils \- single binary for coreutils programs
+[DESCRIPTION]
+.\" Add any additional description here
diff --git a/man/local.mk b/man/local.mk
index 7ce426bb6..0f0b66e25 100644
--- a/man/local.mk
+++ b/man/local.mk
@@ -35,13 +35,6 @@ ALL_MANS = $(man1_MANS) $(EXTRA_MANS)
CLEANFILES += $(ALL_MANS)
-# This is required because we have subtle inter-directory dependencies:
-# in order to generate all man pages, even those for which we don't
-# install a binary, require that all programs be built at distribution
-# time. We can't use 'dist-hook' for this, since it would run too late:
-# the manpages must be generated before the distdir is created and filled.
-$(EXTRA_MANS): $(all_programs)
-
# This is a kludge to remove generated 'man/*.1' from a non-srcdir build.
# Without this, "make distcheck" might fail.
distclean-local:
@@ -59,114 +52,34 @@ mandeps += $(top_srcdir)/src/system.h
$(ALL_MANS): $(mandeps)
-# Most prog.1 man pages depend on src/prog. List the exceptions:
-# Note that dir and vdir are exceptions only if you consider the name
-# of the .c file upon which they depend: ls.c.
-man/arch.1: src/uname
-man/dir.1: src/dir
-man/install.1: src/ginstall
-man/vdir.1: src/vdir
-
-man/base64.1: src/base64
-man/basename.1: src/basename
-man/cat.1: src/cat
-man/chcon.1: src/chcon
-man/chgrp.1: src/chgrp
-man/chmod.1: src/chmod
-man/chown.1: src/chown
-man/chroot.1: src/chroot
-man/cksum.1: src/cksum
-man/comm.1: src/comm
-man/cp.1: src/cp
-man/csplit.1: src/csplit
-man/cut.1: src/cut
-man/date.1: src/date
-man/dd.1: src/dd
-man/df.1: src/df
-man/dircolors.1: src/dircolors
-man/dirname.1: src/dirname
-man/du.1: src/du
-man/echo.1: src/echo
-man/env.1: src/env
-man/expand.1: src/expand
-man/expr.1: src/expr
-man/factor.1: src/factor
-man/false.1: src/false
-man/fmt.1: src/fmt
-man/fold.1: src/fold
-man/groups.1: src/groups
-man/head.1: src/head
-man/hostid.1: src/hostid
-man/hostname.1: src/hostname
-man/id.1: src/id
-man/join.1: src/join
-man/kill.1: src/kill
-man/link.1: src/link
-man/ln.1: src/ln
-man/logname.1: src/logname
-man/ls.1: src/ls
-man/md5sum.1: src/md5sum
-man/mkdir.1: src/mkdir
-man/mkfifo.1: src/mkfifo
-man/mknod.1: src/mknod
-man/mktemp.1: src/mktemp
-man/mv.1: src/mv
-man/nice.1: src/nice
-man/nl.1: src/nl
-man/nohup.1: src/nohup
-man/nproc.1: src/nproc
-man/numfmt.1: src/numfmt
-man/od.1: src/od
-man/paste.1: src/paste
-man/pathchk.1: src/pathchk
-man/pinky.1: src/pinky
-man/pr.1: src/pr
-man/printenv.1: src/printenv
-man/printf.1: src/printf
-man/ptx.1: src/ptx
-man/pwd.1: src/pwd
-man/readlink.1: src/readlink
-man/realpath.1: src/realpath
-man/rm.1: src/rm
-man/rmdir.1: src/rmdir
-man/runcon.1: src/runcon
-man/seq.1: src/seq
-man/sha1sum.1: src/sha1sum
-man/sha224sum.1: src/sha224sum
-man/sha256sum.1: src/sha256sum
-man/sha384sum.1: src/sha384sum
-man/sha512sum.1: src/sha512sum
-man/shred.1: src/shred
-man/shuf.1: src/shuf
-man/sleep.1: src/sleep
-man/sort.1: src/sort
-man/split.1: src/split
-man/stat.1: src/stat
-man/stdbuf.1: src/stdbuf
-man/stty.1: src/stty
-man/sum.1: src/sum
-man/sync.1: src/sync
-man/tac.1: src/tac
-man/tail.1: src/tail
-man/tee.1: src/tee
-man/test.1: src/test
-man/timeout.1: src/timeout
-man/touch.1: src/touch
-man/tr.1: src/tr
-man/true.1: src/true
-man/truncate.1: src/truncate
-man/tsort.1: src/tsort
-man/tty.1: src/tty
-man/uname.1: src/uname
-man/unexpand.1: src/unexpand
-man/uniq.1: src/uniq
-man/unlink.1: src/unlink
-man/uptime.1: src/uptime
-man/users.1: src/users
-man/wc.1: src/wc
-man/who.1: src/who
-man/whoami.1: src/whoami
-man/yes.1: src/yes
+# Most prog.1 man pages depend on src/$prog, except when they are part of a
+# single binary, in which case they depend on src/coreutils. The exceptions
+# are handled by converting $name to $prog on the following code.
+# $(ALL_MANS) includes the $(EXTRA_MANS) so even the programs that are not
+# being installed will have the right dependency for the manpages.
+CLEANFILES += man/dynamic-deps.mk
+man/dynamic-deps.mk: Makefile
+ $(AM_V_GEN)rm -f $@ $@-t
+ $(AM_V_at)for man in $(ALL_MANS); do \
+ name=$${man:4: -2} ; # Space is important \
+ case $$name in \
+ arch) prog='uname';; \
+ install) prog='ginstall';; \
+ test) prog='[';; \
+ *) prog=$$name;; \
+ esac; \
+ case " $(single_binary_progs) " in \
+ *" $$prog "*) \
+ echo $$man: src/coreutils$(EXEEXT);; \
+ *) \
+ echo $$man: src/$$prog$(EXEEXT);; \
+ esac \
+ done > $@-t \
+ && chmod a-w $@-t \
+ && mv $@-t $@
+
+# Include the generated man dependencies.
+-include man/dynamic-deps.mk
.x.1:
$(AM_V_GEN)name=`echo $@ | sed 's|.*/||; s|\.1$$||'` || exit 1; \
@@ -174,9 +87,9 @@ man/yes.1: src/yes
## creating 'install.1'. Similarly, ensure that it uses the 'src/[' binary
## to create 'test.1'.
case $$name in \
- install) prog='ginstall';; \
- test) prog='[';; \
- *) prog=$$name;; \
+ install) prog='ginstall'; argv=$$name;; \
+ test) prog='['; argv='[';; \
+ *) prog=$$name; argv=$$prog;; \
esac; \
## Note the use of $$t/$*, rather than just '$*' as in other packages.
## That is necessary to avoid failures for programs that are also shell
@@ -185,11 +98,11 @@ man/yes.1: src/yes
&& t=$*.td \
&& rm -rf $$t \
&& $(MKDIR_P) $$t \
- && (cd $$t && $(LN_S) '$(abs_top_builddir)/src/'$$prog $$name) \
+ && (cd $$t && $(LN_S) '$(abs_top_builddir)/src/'$$prog $$argv) \
&& $(run_help2man) \
--source='$(PACKAGE_STRING)' \
--include=$(srcdir)/man/$$name.x \
- --output=$$t/$$name.1 $$t/$$name \
+ --output=$$t/$$name.1 $$t/$$argv \
--info-page='coreutils \(aq'$$name' invocation\(aq' \
&& sed \
-e 's|$*\.td/||g' \
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 07bbdd88a..d380deedc 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -45,6 +45,7 @@ src/chroot.c
src/cksum.c
src/comm.c
src/copy.c
+src/coreutils.c
src/cp.c
src/csplit.c
src/cut.c
diff --git a/src/.gitignore b/src/.gitignore
index e273bb867..e8bccbae5 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -12,6 +12,7 @@ chown
chroot
cksum
comm
+coreutils
cp
csplit
cut
diff --git a/src/coreutils-arch.c b/src/coreutils-arch.c
new file mode 100644
index 000000000..899cc937b
--- /dev/null
+++ b/src/coreutils-arch.c
@@ -0,0 +1,32 @@
+/* arch -- wrapper to uname with the right uname_mode.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Written by Alex Deymo <deymo@chromium.org>. */
+
+#include <config.h>
+#include "system.h"
+
+#include "uname.h"
+/* Ensure that the main for uname is declared even if the tool is not being
+ built in this single-binary. */
+int _single_binary_main_uname (int argc, char** argv) ATTRIBUTE_NORETURN;
+int _single_binary_main_arch (int argc, char** argv) ATTRIBUTE_NORETURN;
+
+int _single_binary_main_arch (int argc, char** argv)
+{
+ uname_mode = UNAME_ARCH;
+ _single_binary_main_uname (argc, argv);
+}
diff --git a/src/coreutils-dir.c b/src/coreutils-dir.c
new file mode 100644
index 000000000..4b488f415
--- /dev/null
+++ b/src/coreutils-dir.c
@@ -0,0 +1,32 @@
+/* dir -- wrapper to ls with the right ls_mode.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Written by Alex Deymo <deymo@chromium.org>. */
+
+#include <config.h>
+#include "system.h"
+
+#include "ls.h"
+/* Ensure that the main for ls is declared even if the tool is not being built
+ in this single-binary. */
+int _single_binary_main_ls (int argc, char** argv) ATTRIBUTE_NORETURN;
+int _single_binary_main_dir (int argc, char** argv) ATTRIBUTE_NORETURN;
+
+int _single_binary_main_dir (int argc, char** argv)
+{
+ ls_mode = LS_MULTI_COL;
+ _single_binary_main_ls (argc, argv);
+}
diff --git a/src/coreutils-vdir.c b/src/coreutils-vdir.c
new file mode 100644
index 000000000..036367f6d
--- /dev/null
+++ b/src/coreutils-vdir.c
@@ -0,0 +1,32 @@
+/* vdir -- wrapper to ls with the right ls_mode.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Written by Alex Deymo <deymo@chromium.org>. */
+
+#include <config.h>
+#include "system.h"
+
+#include "ls.h"
+/* Ensure that the main for ls is declared even if the tool is not being built
+ in this single-binary. */
+int _single_binary_main_ls (int argc, char** argv) ATTRIBUTE_NORETURN;
+int _single_binary_main_vdir (int argc, char** argv) ATTRIBUTE_NORETURN;
+
+int _single_binary_main_vdir (int argc, char** argv)
+{
+ ls_mode = LS_LONG_FORMAT;
+ _single_binary_main_ls (argc, argv);
+}
diff --git a/src/coreutils.c b/src/coreutils.c
new file mode 100644
index 000000000..c459b1d62
--- /dev/null
+++ b/src/coreutils.c
@@ -0,0 +1,205 @@
+/* Copyright (C) 2014 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* coreutils.c aggregates the functionality of every other tool into a single
+ binary multiplexed by the value of argv[0]. This is enabled by passing
+ --enable-single-binary to configure.
+
+ Written by Alex Deymo <deymo@chromium.org>. */
+
+#include <config.h>
+#include <getopt.h>
+#include <stdio.h>
+#if HAVE_PRCTL
+# include <sys/prctl.h>
+#endif
+
+#include "system.h"
+#include "error.h"
+#include "quote.h"
+
+#ifdef SINGLE_BINARY
+/* Declare the main function on each one of the selected tools. This name
+ needs to match the one passed as CFLAGS on single-binary.mk (generated
+ by gen-single-binary.sh). */
+# define SINGLE_BINARY_PROGRAM(prog_name_str, main_name) \
+ int _single_binary_main_##main_name (int, char**) ATTRIBUTE_NORETURN;
+# include "coreutils.h"
+# undef SINGLE_BINARY_PROGRAM
+#endif
+
+/* The official name of this program (e.g., no 'g' prefix). */
+#define PROGRAM_NAME "coreutils"
+
+#define AUTHORS \
+ proper_name ("Alex Deymo")
+
+void
+launch_program (const char *prog_name, int prog_argc, char **prog_argv);
+
+static struct option const long_options[] =
+{
+ {GETOPT_HELP_OPTION_DECL},
+ {GETOPT_VERSION_OPTION_DECL},
+ {NULL, 0, NULL, 0}
+};
+
+
+void
+usage (int status)
+{
+ if (status != EXIT_SUCCESS)
+ emit_try_help ();
+ else
+ {
+ printf (_("\
+Usage: %s --coreutils-prog=PROGRAM_NAME [PARAMETERS]... \n"),
+ program_name);
+ fputs (_("\
+Execute the PROGRAM_NAME built-in program with the given PARAMETERS.\n\
+\n"), stdout);
+ fputs (HELP_OPTION_DESCRIPTION, stdout);
+ fputs (VERSION_OPTION_DESCRIPTION, stdout);
+
+ printf ("\n\
+Built-in programs:\n"
+#ifdef SINGLE_BINARY
+/* XXX: Ideally we#d like to present "install" here, not "ginstall". */
+# define SINGLE_BINARY_PROGRAM(prog_name_str, main_name) " " prog_name_str
+# include "coreutils.h"
+# undef SINGLE_BINARY_PROGRAM
+#endif
+ "\n");
+
+ printf (_("\
+\n\
+Use: '%s --coreutils-prog=PROGRAM_NAME --help' for individual program help.\n"),
+ program_name);
+ emit_ancillary_info ();
+ }
+ exit (status);
+}
+
+void
+launch_program (const char *prog_name, int prog_argc, char **prog_argv)
+{
+ int (*prog_main)(int, char **) = NULL;
+
+ /* Ensure that at least one parameter was passed. */
+ if (!prog_argc || !prog_argv || !prog_argv[0] || !prog_name)
+ return;
+
+#ifdef SINGLE_BINARY
+ if (false);
+ /* Lookup the right main program. */
+# define SINGLE_BINARY_PROGRAM(prog_name_str, main_name) \
+ else if (STREQ (prog_name_str, prog_name)) \
+ prog_main = _single_binary_main_##main_name;
+# include "coreutils.h"
+# undef SINGLE_BINARY_PROGRAM
+#endif
+
+ if (! prog_main)
+ return;
+
+#if HAVE_PRCTL && defined PR_SET_NAME
+ /* Not being able to set the program name is not a fatal error. */
+ prctl (PR_SET_NAME, prog_argv[0]);
+#endif
+#if HAVE_PRCTL && defined PR_SET_MM_ARG_START
+ /* Shift the beginning of the command line to prog_argv[0] (if set) so
+ /proc/pid/cmdline reflects the right value. */
+ prctl (PR_SET_MM_ARG_START, prog_argv[0]);
+#endif
+
+ exit ((*prog_main) (prog_argc, prog_argv));
+}
+
+int
+main (int argc, char **argv)
+{
+ char *prog_name = last_component (argv[0]);
+ int optc;
+
+ /* Map external name to internal name. */
+ char ginstall[] = "ginstall";
+ if (STREQ (prog_name, "install"))
+ prog_name = ginstall;
+
+ /* If this program is called directly as "coreutils" or if the value of
+ argv[0] is an unknown tool (which "coreutils" is), we proceed and parse
+ the options. */
+ launch_program (prog_name, argc, argv);
+
+ /* No known program was selected via argv[0]. Try parsing the first
+ argument as --coreutils-prog=PROGRAM to determine the program. The
+ invocation for this case should be:
+ path/to/coreutils --coreutils-prog=someprog someprog ...
+ The third argument is what the program will see as argv[0]. */
+
+ if (argc >= 2)
+ {
+ size_t nskip = 0;
+ char *arg_name = NULL;
+
+ /* If calling coreutils directly, the "script" name isn't passed.
+ Distinguish the two cases with a -shebang suffix. */
+ if (STRPREFIX (argv[1], "--coreutils-prog="))
+ {
+ nskip = 1;
+ arg_name = prog_name = argv[1] + strlen ("--coreutils-prog=");
+ }
+ else if (STRPREFIX (argv[1], "--coreutils-prog-shebang="))
+ {
+ nskip = 2;
+ prog_name = argv[1] + strlen ("--coreutils-prog-shebang=");
+ if (argc >= 3)
+ arg_name = last_component (argv[2]);
+ else
+ arg_name = prog_name;
+ }
+
+ if (nskip)
+ {
+ argv[nskip] = arg_name; /* XXX: Discards any specified path. */
+ launch_program (prog_name, argc - nskip, argv + nskip);
+ error (EXIT_FAILURE, 0, _("unknown program %s"), quote (prog_name));
+ }
+ }
+
+ /* No known program was selected. From here on, we behave like any other
+ coreutils program. */
+ initialize_main (&argc, &argv);
+ set_program_name (argv[0]);
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+ atexit (close_stdout);
+
+ if ((optc = getopt_long (argc, argv, "", long_options, NULL)) != -1)
+ switch (optc)
+ {
+ case_GETOPT_HELP_CHAR;
+
+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
+ }
+
+ /* Only print the error message when no options have been passed
+ to coreutils. */
+ if (optind == 1 && prog_name && !STREQ (prog_name, "coreutils"))
+ error (0, 0, _("unknown program %s"), quote (prog_name));
+
+ usage (EXIT_FAILURE);
+}
diff --git a/src/kill.c b/src/kill.c
index 4ab86a48f..724667e0e 100644
--- a/src/kill.c
+++ b/src/kill.c
@@ -306,7 +306,7 @@ main (int argc, char **argv)
usage (EXIT_FAILURE);
}
- return (list
- ? list_signals (table, optind < argc ? argv + optind : NULL)
- : send_signals (signum, argv + optind));
+ exit (list
+ ? list_signals (table, optind < argc ? argv + optind : NULL)
+ : send_signals (signum, argv + optind));
}
diff --git a/src/local.mk b/src/local.mk
index 865dd7452..e35d28688 100644
--- a/src/local.mk
+++ b/src/local.mk
@@ -42,6 +42,7 @@ noinst_PROGRAMS = \
noinst_HEADERS = \
src/chown-core.h \
src/copy.h \
+ src/coreutils.h \
src/cp-hash.h \
src/dircolors.h \
src/fiemap.h \
@@ -105,6 +106,9 @@ src_cksum_LDADD = $(LDADD)
src_comm_LDADD = $(LDADD)
src_nproc_LDADD = $(LDADD)
src_cp_LDADD = $(LDADD)
+if !SINGLE_BINARY
+src_coreutils_LDADD = $(LDADD)
+endif
src_csplit_LDADD = $(LDADD)
src_cut_LDADD = $(LDADD)
src_date_LDADD = $(LDADD)
@@ -150,6 +154,7 @@ src_mv_LDADD = $(LDADD)
src_nice_LDADD = $(LDADD)
src_nl_LDADD = $(LDADD)
src_nohup_LDADD = $(LDADD)
+src_numfmt_LDADD = $(LDADD)
src_od_LDADD = $(LDADD)
src_paste_LDADD = $(LDADD)
src_pathchk_LDADD = $(LDADD)
@@ -395,6 +400,46 @@ src_libstdbuf_so_LDADD = $(LIBINTL)
src_libstdbuf_so_LDFLAGS = -shared
src_libstdbuf_so_CFLAGS = -fPIC $(AM_CFLAGS)
+BUILT_SOURCES += src/coreutils.h
+if SINGLE_BINARY
+# Single binary dependencies
+src_coreutils_CFLAGS = -DSINGLE_BINARY $(AM_CFLAGS)
+#src_coreutils_LDFLAGS = $(AM_LDFLAGS)
+src_coreutils_LDADD = $(single_binary_deps) $(LDADD) $(single_binary_libs)
+src_coreutils_DEPENDENCIES = $(LDADD) $(single_binary_deps)
+
+include $(top_srcdir)/src/single-binary.mk
+
+# Creates symlinks or shebangs to the installed programs when building
+# coreutils single binary.
+EXTRA_src_coreutils_DEPENDENCIES = src/coreutils_$(single_binary_install_type)
+endif SINGLE_BINARY
+
+CLEANFILES += src/coreutils_symlinks
+src/coreutils_symlinks: Makefile
+ $(AM_V_GEN)touch $@
+ $(AM_V_at)for i in $(single_binary_progs); do \
+ rm -f src/$$i$(EXEEXT) || exit $$?; \
+ $(LN_S) -s coreutils$(EXEEXT) src/$$i$(EXEEXT) || exit $$?; \
+ done
+
+CLEANFILES += src/coreutils_shebangs
+src/coreutils_shebangs: Makefile
+ $(AM_V_GEN)touch $@
+ $(AM_V_at)for i in $(single_binary_progs); do \
+ rm -f src/$$i$(EXEEXT) || exit $$?; \
+ printf '#!%s --coreutils-prog-shebang=%s\n' \
+ $(abs_top_builddir)/src/coreutils$(EXEEXT) $$i \
+ >src/$$i$(EXEEXT) || exit $$?; \
+ chmod a+x,a-w src/$$i$(EXEEXT) || exit $$?; \
+ done
+
+clean-local:
+ $(AM_V_at)for i in $(single_binary_progs); do \
+ rm -f src/$$i$(EXEEXT) || exit $$?; \
+ done
+
+
BUILT_SOURCES += src/dircolors.h
src/dircolors.h: src/dcgen src/dircolors.hin
$(AM_V_GEN)rm -f $@ $@-t
@@ -515,6 +560,22 @@ src/version.h: Makefile
$(AM_V_at)chmod a-w $@t
$(AM_V_at)mv $@t $@
+# Generates a list of macro invocations like:
+# SINGLE_BINARY_PROGRAM(program_name_str, main_name)
+# once for each program list on $(single_binary_progs). Note that
+# for [ the macro invocation is:
+# SINGLE_BINARY_PROGRAM("[", _)
+CLEANFILES += src/coreutils.h
+src/coreutils.h: Makefile
+ $(AM_V_GEN)rm -f $@
+ $(AM_V_at)for prog in $(single_binary_progs); do \
+ prog=`basename $$prog`; \
+ main=`echo $$prog | tr '[' '_'`; \
+ echo "SINGLE_BINARY_PROGRAM(\"$$prog\", $$main)"; \
+ done | sort > $@t
+ $(AM_V_at)chmod a-w $@t
+ $(AM_V_at)mv $@t $@
+
DISTCLEANFILES += src/version.c src/version.h
MAINTAINERCLEANFILES += $(BUILT_SOURCES)
diff --git a/src/readlink.c b/src/readlink.c
index d63f07b40..f46d948e1 100644
--- a/src/readlink.c
+++ b/src/readlink.c
@@ -174,5 +174,5 @@ main (int argc, char **argv)
}
}
- return status;
+ exit (status);
}
diff --git a/src/shuf.c b/src/shuf.c
index 915f7b7a5..2505be6f1 100644
--- a/src/shuf.c
+++ b/src/shuf.c
@@ -622,5 +622,5 @@ main (int argc, char **argv)
}
#endif
- return EXIT_SUCCESS;
+ exit (EXIT_SUCCESS);
}
diff --git a/src/timeout.c b/src/timeout.c
index 23d894159..68baa23ce 100644
--- a/src/timeout.c
+++ b/src/timeout.c
@@ -440,7 +440,7 @@ main (int argc, char **argv)
if (monitored_pid == -1)
{
error (0, errno, _("fork system call failed"));
- return EXIT_CANCELED;
+ exit (EXIT_CANCELED);
}
else if (monitored_pid == 0)
{ /* child */
@@ -455,7 +455,7 @@ main (int argc, char **argv)
/* exit like sh, env, nohup, ... */
exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
error (0, errno, _("failed to run command %s"), quote (argv[0]));
- return exit_status;
+ exit (exit_status);
}
else
{
@@ -500,8 +500,8 @@ main (int argc, char **argv)
}
if (timed_out && !preserve_status)
- return EXIT_TIMEDOUT;
+ exit (EXIT_TIMEDOUT);
else
- return status;
+ exit (status);
}
}
diff --git a/src/truncate.c b/src/truncate.c
index 44d0b9670..f31250920 100644
--- a/src/truncate.c
+++ b/src/truncate.c
@@ -420,5 +420,5 @@ main (int argc, char **argv)
}
}
- return errors ? EXIT_FAILURE : EXIT_SUCCESS;
+ exit (errors ? EXIT_FAILURE : EXIT_SUCCESS);
}
diff --git a/tests/install/basic-1.sh b/tests/install/basic-1.sh
index 9835d463e..0c0d1de86 100755
--- a/tests/install/basic-1.sh
+++ b/tests/install/basic-1.sh
@@ -46,13 +46,17 @@ is not readable, so skipping the remaining tests in this file."
cp "$just_built_dd" . || fail=1
cp $dd $dd2 || fail=1
-strip $dd2 \
- || warn_ "WARNING!!! Your strip command doesn't seem to work,
+strip=-s
+if ! strip $dd2; then
+ ! test -e $abs_top_builddir/src/coreutils \
+ && warn_ "WARNING!!! Your strip command doesn't seem to work,
so skipping the test of install's --strip option."
+ strip=
+fi
# This test would fail with 3.16s when using versions of strip that
# don't work on read-only files (the one from binutils works fine).
-ginstall -s -c -m 555 $dd $dir || fail=1
+ginstall $strip -c -m 555 $dd $dir || fail=1
# Make sure the source file is still around.
test -f $dd || fail=1
diff --git a/tests/local.mk b/tests/local.mk
index 86050dc79..e0f1f84ee 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -65,7 +65,7 @@ TESTS_ENVIRONMENT = \
abs_top_builddir='$(abs_top_builddir)' \
abs_top_srcdir='$(abs_top_srcdir)' \
abs_srcdir='$(abs_srcdir)' \
- built_programs='$(built_programs)' \
+ built_programs='$(built_programs) $(single_binary_progs)' \
host_os=$(host_os) \
host_triplet='$(host_triplet)' \
srcdir='$(srcdir)' \
@@ -249,6 +249,7 @@ all_tests = \
tests/pr/pr-tests.pl \
tests/misc/pwd-option.sh \
tests/misc/chcon-fail.sh \
+ tests/misc/coreutils.sh \
tests/misc/cut.pl \
tests/misc/cut-huge-range.sh \
tests/misc/wc.pl \
diff --git a/tests/misc/coreutils.sh b/tests/misc/coreutils.sh
new file mode 100755
index 000000000..a22bc9f64
--- /dev/null
+++ b/tests/misc/coreutils.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+# Verify behavior of separate coreutils multicall binary
+
+# Copyright (C) 2014 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ coreutils
+
+test -s "$abs_top_builddir/src/coreutils.h" \
+ || skip_ "multicall binary is disabled"
+
+# Yes outputs all its params so is good to verify argv manipulations
+echo 'y' > exp
+coreutils --coreutils-prog=yes | head -n10 | uniq > out
+compare exp out || fail=1
+
+# Ensure if incorrect program passed, we diagnose
+echo "coreutils: unknown program 'blah'" > exp
+coreutils --coreutils-prog='blah' --help 2>err && fail=1
+compare exp err || fail=1
+
+Exit $fail
diff --git a/tests/misc/env.sh b/tests/misc/env.sh
index c4b97377a..883c58f54 100755
--- a/tests/misc/env.sh
+++ b/tests/misc/env.sh
@@ -20,6 +20,10 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ env
+# A simple shebang program to call "echo" from symlinks like "./-u" or "./--".
+echo "#!$abs_top_builddir/src/echo simple_echo" > simple_echo \
+ || framework_failure_
+chmod a+x simple_echo || framework_failure_
# Verify clearing the environment
a=1
@@ -105,9 +109,10 @@ export PATH
# Use -- to end options (but not variable assignments).
# On some systems, execve("-i") invokes a shebang script ./-i on PATH as
# '/bin/sh -i', rather than '/bin/sh -- -i', which doesn't do what we want.
-# Avoid the issue by using an executable rather than a script.
+# Avoid the issue by using a shebang to 'echo' passing a second parameter
+# before the '-i'. See the definition of simple_echo before.
# Test -u, rather than -i, to minimize PATH problems.
-ln -s "$abs_top_builddir/src/echo" ./-u || framework_failure_
+ln -s "simple_echo" ./-u || framework_failure_
case $(env -u echo echo good) in
good) ;;
*) fail=1 ;;
@@ -117,16 +122,16 @@ case $(env -u echo -- echo good) in
*) fail=1 ;;
esac
case $(env -- -u pass) in
- pass) ;;
+ *pass) ;;
*) fail=1 ;;
esac
# After options have ended, the first argument not containing = is a program.
env a=b -- true
test $? = 127 || fail=1
-ln -s "$abs_top_builddir/src/echo" ./-- || framework_failure_
+ln -s "simple_echo" ./-- || framework_failure_
case $(env a=b -- true || echo fail) in
- true) ;;
+ *true) ;;
*) fail=1 ;;
esac
diff --git a/tests/misc/help-version.sh b/tests/misc/help-version.sh
index b4939f7af..0598557f2 100755
--- a/tests/misc/help-version.sh
+++ b/tests/misc/help-version.sh
@@ -239,7 +239,7 @@ parted_setup () { args="-s $tmp_in mklabel gpt"
# something more than --help or --version.
for i in $built_programs; do
# Skip these.
- case $i in chroot|stty|tty|false|chcon|runcon) continue;; esac
+ case $i in chroot|stty|tty|false|chcon|runcon|coreutils) continue;; esac
rm -rf $tmp_in $tmp_in2 $tmp_dir $tmp_out $bigZ_in $zin $zin2
echo z |gzip > $zin