Don't require test wrappers to preserve environment variables

Message ID Pine.LNX.4.64.1405211643220.13941@digraph.polyomino.org.uk
State Superseded
Headers

Commit Message

Joseph Myers May 21, 2014, 4:44 p.m. UTC
  One wart in the original support for test wrappers for cross testing,
as noted in
<https://sourceware.org/ml/libc-alpha/2012-10/msg00722.html>, is the
requirement for test wrappers to pass a poorly-defined set of
environment variables from the build system to the system running the
glibc under test.  Although some variables are passed explicitly via
$(test-wrapper-env), including LD_* variables that simply can't be
passed implicitly because of the side effects they'd have on the build
system's dynamic linker, others are passed implicitly, including
variables such as GCONV_PATH and LOCPATH that could potentially affect
the build system's libc (so effectively relying on any such effects
not breaking the wrappers).  In addition, the code in
cross-test-ssh.sh for preserving environment variables is fragile (it
depends on how bash formats a list of exported variables, and could
well break for multi-line variable definitions where the contents
contain things looking like other variable definitions).

This patch moves to explicitly passing environment variables via
$(test-wrapper-env).  Makefile variables that previously used
$(test-wrapper) are split up into -before-env and -after-env parts
that can be passed separately to the various .sh files used in
testing, so those files can then insert environment settings between
the two parts.  A further motivation for this is to make the comment
default environment settings in make-test-out (currently
GCONV_PATH=$(common-objpfx)iconvdata LC_ALL=C) into a separate
makefile variable that can also be passed to scripts, rather than many
scripts duplicating those settings (for testing an installed glibc, it
would be desirable to have the GCONV_PATH setting on just one place,
so just that one place needs to support it pointing to an installed
sysroot instead of the build tree).  I think it will also make sense
to have a default LOCPATH setting in once place as well rather than
all the tests needing locales repeating that individually.

Where environment variable settings such as LC_ALL=C seemed plausibly
relevant on both systems for cross testing, I left the existing
settings in the scripts as well as having those variables passed
explicitly to $(test-wrapper-env), so they remain set on both systems.

One issue with this patch is that it's no longer so easy to pass
TIMEOUTFACTOR through for cross testing.  Do people think
cross-test-ssh.sh should special-case passing through that variable
(but a whitelist of variables to pass in place of the previous
blacklist of variables not to pass), or would it be better for it to
have a --timeoutfactor command-line option that causes it to set
TIMEOUTFACTOR on the remote system?

Tested x86_64 (native) and powerpc32 (cross).

2014-05-21  Joseph Myers  <joseph@codesourcery.com>

	* Makeconfig (run-program-prefix-before-env): New variable.
	(run-program-prefix-after-env): Likewise.
	(built-program-cmd-before-env): Likewise.
	(built-program-cmd-after-env): Likewise.
	(test-program-prefix-before-env): Likewise.
	(test-program-prefix-after-env): Likewise.
	(test-program-cmd-before-env): Likewise.
	(test-program-cmd-after-env): Likewise.
	* scripts/cross-test-ssh.sh (env_blacklist): Remove variable.
	(help): Do not mention environment variables.
	(blacklist_exports): Remove function.
	(exports): Remove variable.
	(command): Do not include ${exports}.
	* manual/install.texi (Configuring and compiling): Do not mention
	test wrappers preserving environment variables.
	* INSTALL: Regenerated.
	* catgets/Makefile ($(objpfx)test1.cat): Use
	$(built-program-cmd-before-env) and
	$(built-program-cmd-after-env).
	($(objpfx)test2.cat): Likewise.
	($(objpfx)de/libc.cat): Likewise.
	($(objpfx)test-gencat.out): Use $(test-program-cmd-before-env) and
	$(test-program-cmd-after-env).
	($(objpfx)sample.SJIS.cat): Use $(built-program-cmd-before-env)
	and $(built-program-cmd-after-env).
	* catgets/test-gencat.sh: Use test_program_cmd_before_env and
	test_program_cmd_after_env arguments.
	* iconvdata/Makefile ($(objpfx)iconv-test.out): Use
	$(test-wrapper-env).
	($(objpfx)tst-tables.out): Use $(test-program-prefix-before-env)
	and $(test-program-prefix-after-env).
	* iconvdata/run-iconv-test.sh: Use test_wrapper_env argument.
	* iconvdata/tst-table.sh: Use test_program_prefix_before_env and
	test_program_prefix_after_env arguments.
	* iconvdata/tst-tables.sh: Likewise.
	* intl/Makefile ($(objpfx)tst-gettext.out): Use
	$(test-program-prefix-before-env) and
	$(test-program-prefix-after-env).
	($(objpfx)tst-translit.out): Likewise.
	($(objpfx)tst-gettext2.out): Likewise.
	($(objpfx)tst-gettext4.out): Likewise.
	($(objpfx)tst-gettext6.out): Likewise.
	* intl/tst-gettext.sh: Use test_program_prefix_before_env and
	test_program_prefix_after_env arguments.
	* intl/tst-gettext2.sh: Likewise.
	* intl/tst-gettext4.sh: Likewise.
	* intl/tst-gettext6.sh: Likewise.
	* intl/tst-translit.sh: Likewise.
	* localedata/Makefile ($(objpfx)sort-test.out): Use
	$(test-program-prefix-before-env) and
	$(test-program-prefix-after-env).
	($(objpfx)tst-fmon.out): Use $(run-program-prefix-before-env),
	$(run-program-prefix-after-env), $(test-program-prefix-before-env)
	and $(test-program-prefix-after-env).
	($(objpfx)tst-numeric.out): Use $(test-program-prefix-before-env)
	and $(test-program-prefix-after-env).
	($(objpfx)tst-locale.out): Use $(built-program-cmd-before-env) and
	$(built-program-cmd-after-env).
	($(objpfx)tst-rpmatch.out): Use $(test-program-cmd-before-env) and
	$(test-program-cmd-after-env).
	($(objpfx)tst-trans.out): Use $(run-program-prefix-before-env),
	$(run-program-prefix-after-env), $(test-program-prefix-before-env)
	and $(test-program-prefix-after-env).
	($(objpfx)tst-mbswcs.out): Use $(test-program-prefix-before-env)
	and $(test-program-prefix-after-env).
	($(objpfx)tst-ctype.out): Use $(test-program-cmd-before-env) and
	$(test-program-cmd-after-env).
	($(objpfx)tst-wctype.out): Likewise.
	($(objpfx)tst-langinfo.out): Likewise.
	($(objpfx)tst-langinfo-static.out): Likewise.
	* localedata/sort-test.sh: Use test_program_prefix_before_env and
	test_program_prefix_after_env arguments.
	* localedata/tst-ctype.sh: Use tst_ctype_before_env and
	tst_ctype_after_env arguments.
	* localedata/tst-fmon.sh: Use run_program_prefix_before_env,
	run_program_prefix_after_env, test_program_prefix_before_env and
	test_program_prefix_after_env arguments.
	* localedata/tst-langinfo.sh: Use tst_langinfo_before_env and
	tst_langinfo_after_env arguments.
	* localedata/tst-locale.sh: Use localedef_before_env and
	localedef_after_env arguments.
	* localedata/tst-mbswcs.sh: Use test_program_prefix_before_env and
	test_program_prefix_after_env arguments.
	* localedata/tst-numeric.sh: Likewise.
	* localedata/tst-rpmatch.sh: Use tst_rpmatch_before_env and
	tst_rpmatch_after_env arguments.
	* localedata/tst-trans.sh: Use run_program_prefix_before_env,
	run_program_prefix_after_env, test_program_prefix_before_env and
	test_program_prefix_after_env arguments.
	* localedata/tst-wctype.sh: Use tst_wctype_before_env and
	tst_wctype_after_env arguments.
	* malloc/Makefile: Use $(test-program-prefix-before-env) and
	$(test-program-prefix-after-env).
	* malloc/tst-mtrace.sh: Use test_program_prefix_before_env and
	test_program_prefix_after_env arguments.
	* nptl/tst-tls6.sh: Set LC_ALL=C and LANG=C explicitly with each
	use of ${test_wrapper_env}.
	* posix/Makefile ($(objpfx)wordexp-tst.out): Use
	$(test-program-prefix-before-env) and
	$(test-program-prefix-after-env).
	* posix/wordexp-tst.sh: Use test_program_prefix_before_env and
	test_program_prefix_after_env arguments.
	* stdio-common/Makefile ($(objpfx)tst-printf.out): Use
	$(test-program-prefix-before-env) and
	$(test-program-prefix-after-env).
	* stdio-common/tst-printf.sh: Use test_program_prefix_before_env
	and test_program_prefix_after_env arguments.
	* stdlib/Makefile ($(objpfx)tst-fmtmsg.out): Use
	$(test-program-prefix-before-env) and
	$(test-program-prefix-after-env).
	* stdlib/tst-fmtmsg.sh: Use test_program_prefix_before_env and
	test_program_prefix_after_env arguments.  Split $test calls into
	$test_pre and $test.
  

Comments

Roland McGrath May 23, 2014, 10:27 p.m. UTC | #1
I didn't closely vet the individual changes or that the log entries match.
I certainly support the thrust of the change.

I'd be a bit happier if the Makeconfig definitions used each other more and
duplicated each other less.  (If we can get to having fewer of them
altogether, that would be good too.)  For example, why is it not now:

test-wrapper = $(test-program-prefix-before-env) $(test-program-prefix-after-env)

?  Such simplifications could be done later, though.

> Where environment variable settings such as LC_ALL=C seemed plausibly
> relevant on both systems for cross testing, I left the existing
> settings in the scripts as well as having those variables passed
> explicitly to $(test-wrapper-env), so they remain set on both systems.

Any place where the environment variables on the build system matter, there
should be a comment explicitly saying that they do and why.  If there are
cases where you're just not sure that they don't matter, then add a generic
comment like "# ??? LC_ALL setting on build side might matter; figure out
whether and why." so that someone who wants to put the time into
understanding that particular test setup better can find the place easily
and then either remove the setting and comment or replace the comment with
one that gives specific rationale.

> One issue with this patch is that it's no longer so easy to pass
> TIMEOUTFACTOR through for cross testing.  Do people think
> cross-test-ssh.sh should special-case passing through that variable
> (but a whitelist of variables to pass in place of the previous
> blacklist of variables not to pass), or would it be better for it to
> have a --timeoutfactor command-line option that causes it to set
> TIMEOUTFACTOR on the remote system?

I think the command line option is better.  Having a simple rule that no
magic environment bits from the build host implicitly affect the test host
seems the least error-prone in the long run.


Thanks,
Roland
  
Joseph Myers May 23, 2014, 11:07 p.m. UTC | #2
On Fri, 23 May 2014, Roland McGrath wrote:

> Any place where the environment variables on the build system matter, there
> should be a comment explicitly saying that they do and why.  If there are

There are some places where there are such comments but they are clearly 
wrong.  E.g., posix/getconf.sh says

# Since we use `sort' we must make sure to use the same locale everywhere.

but that looks like it was cut-and-pasted from another test, maybe 
globtest.sh - getconf.sh does not use sort.
  

Patch

diff --git a/INSTALL b/INSTALL
index f49fad4..0f0d37b 100644
--- a/INSTALL
+++ b/INSTALL
@@ -241,13 +241,12 @@  be visible at the same locations on both the build system and HOSTNAME.
    In general, when testing the GNU C Library, `test-wrapper' may be set
 to the name and arguments of any program to run newly built binaries.
 This program must preserve the arguments to the binary being run, its
-working directory, all environment variables set as part of testing and
-the standard input, output and error file descriptors.  If
-`TEST-WRAPPER env' will not work to run a program with environment
-variables set, then `test-wrapper-env' must be set to a program that
-runs a newly built program with environment variable assignments in
-effect, those assignments being specified as `VAR=VALUE' before the
-name of the program to be run.
+working directory and the standard input, output and error file
+descriptors.  If `TEST-WRAPPER env' will not work to run a program with
+environment variables set, then `test-wrapper-env' must be set to a
+program that runs a newly built program with environment variable
+assignments in effect, those assignments being specified as `VAR=VALUE'
+before the name of the program to be run.
 
 Installing the C Library
 ========================
diff --git a/Makeconfig b/Makeconfig
index 2df4c88..f830967 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -635,12 +635,20 @@  endif
 # that, executed on the build system on which "make" is run, runs that
 # program.
 run-program-prefix = $(test-wrapper) $(run-via-rtld-prefix)
+# Like $(run-program-prefix), but separate parts before and after a
+# list of environment variables.
+run-program-prefix-before-env = $(test-wrapper-env)
+run-program-prefix-after-env = $(run-via-rtld-prefix)
 # $(built-program-cmd) is a command that, executed on the build system
 # on which "make" is run, runs the newly built program that is the
 # second dependency of the makefile target in which
 # $(built-program-cmd) is used.
 built-program-cmd = $(test-wrapper) \
 		    $(run-via-rtld-prefix) $(built-program-file)
+# Like $(built-program-cmd), but separate parts before and after a
+# list of environment variables.
+built-program-cmd-before-env = $(test-wrapper-env)
+built-program-cmd-after-env = $(run-via-rtld-prefix) $(built-program-file)
 # $(host-built-program-cmd) is a command that, executed on the host
 # for which the library is built, runs the newly built program that is
 # the second dependency of the makefile target in which
@@ -661,12 +669,16 @@  endif
 # $(test-program-prefix) is a command that, when prepended to the name
 # of a test program built with the newly built library, produces a command
 # that, executed on the build system on which "make" is run, runs that
-# test program.
+# test program.  $(test-program-prefix-before-env) and
+# $(test-program-prefix-after-env) are similar, before and after a
+# list of environment variables.
 
 # $(test-program-cmd) is a command that, executed on the build system
 # on which "make" is run, runs the newly built test program that is the
 # second dependency of the makefile target in which
-# $(test-program-cmd) is used.
+# $(test-program-cmd) is used.  $(test-program-cmd-before-env) and
+# $(test-program-cmd-after-env) are similar, before and after a list
+# of environment variables.
 
 # $(host-test-program-cmd) is a command that, executed on the host
 # for which the library is built, runs the newly built test program that
@@ -676,12 +688,20 @@  endif
 ifeq (yes,$(build-hardcoded-path-in-tests))
 test-via-rtld-prefix =
 test-program-prefix = $(test-wrapper)
+test-program-prefix-before-env = $(test-wrapper-env)
+test-program-prefix-after-env =
 test-program-cmd = $(test-wrapper) $(built-program-file)
+test-program-cmd-before-env = $(test-wrapper-env)
+test-program-cmd-after-env = $(built-program-file)
 host-test-program-cmd = $(built-program-file)
 else
 test-via-rtld-prefix = $(run-via-rtld-prefix)
 test-program-prefix = $(run-program-prefix)
+test-program-prefix-before-env = $(run-program-prefix-before-env)
+test-program-prefix-after-env = $(run-program-prefix-after-env)
 test-program-cmd = $(built-program-cmd)
+test-program-cmd-before-env = $(built-program-cmd-before-env)
+test-program-cmd-after-env = $(built-program-cmd-after-env)
 host-test-program-cmd = $(host-built-program-cmd)
 endif
 
diff --git a/catgets/Makefile b/catgets/Makefile
index ed06508..80a7049 100644
--- a/catgets/Makefile
+++ b/catgets/Makefile
@@ -61,19 +61,23 @@  ifeq ($(run-built-tests),yes)
 # This test just checks whether the program produces any error or not.
 # The result is not tested.
 $(objpfx)test1.cat: test1.msg $(objpfx)gencat
+	$(built-program-cmd-before-env) \
 	LC_ALL=hr_HR.ISO-8859-2 LOCPATH=$(common-objpfx)localedata \
 	GCONV_PATH=$(common-objpfx)iconvdata \
-	$(built-program-cmd) -H $(objpfx)test1.h $@ $<; \
+	$(built-program-cmd-after-env) -H $(objpfx)test1.h $@ $<; \
 	$(evaluate-test)
 $(objpfx)test2.cat: test2.msg $(objpfx)gencat
+	$(built-program-cmd-before-env) \
 	LOCPATH=$(common-objpfx)localedata \
 	GCONV_PATH=$(common-objpfx)iconvdata \
-	$(built-program-cmd) -H $(objpfx)test2.h $@ $<; \
+	$(built-program-cmd-after-env) -H $(objpfx)test2.h $@ $<; \
 	$(evaluate-test)
 $(objpfx)de/libc.cat: $(objpfx)de.msg $(objpfx)gencat
 	$(make-target-directory)
+	$(built-program-cmd-before-env) \
 	LC_ALL=de_DE.ISO-8859-1 LOCPATH=$(common-objpfx)localedata \
-	GCONV_PATH=$(common-objpfx)iconvdata $(built-program-cmd) $@ $<; \
+	GCONV_PATH=$(common-objpfx)iconvdata \
+	$(built-program-cmd-after-env) $@ $<; \
 	$(evaluate-test)
 $(objpfx)tst-catgets.out: $(objpfx)de/libc.cat
 
@@ -83,11 +87,14 @@  $(objpfx)de.msg: xopen-msg.awk $(..)po/de.po
 
 $(objpfx)test-gencat.out: test-gencat.sh $(objpfx)test-gencat \
 			  $(objpfx)sample.SJIS.cat
-	$(SHELL) $< $(common-objpfx) '$(test-program-cmd)'; \
+	$(SHELL) $< $(common-objpfx) '$(test-program-cmd-before-env)' \
+		 '$(test-program-cmd-after-env)'; \
 	$(evaluate-test)
 
 $(objpfx)sample.SJIS.cat: sample.SJIS $(objpfx)gencat
+	$(built-program-cmd-before-env) \
 	GCONV_PATH=$(common-objpfx)iconvdata LC_ALL=C \
-	$(built-program-cmd) -H $(objpfx)test-gencat.h < $(word 1,$^) > $@; \
+	$(built-program-cmd-after-env) -H $(objpfx)test-gencat.h \
+				       < $(word 1,$^) > $@; \
 	$(evaluate-test)
 endif
diff --git a/catgets/test-gencat.sh b/catgets/test-gencat.sh
index 08e47af..d419ff3 100755
--- a/catgets/test-gencat.sh
+++ b/catgets/test-gencat.sh
@@ -20,12 +20,14 @@ 
 set -e
 
 common_objpfx=$1
-test_program_cmd=$2
+test_program_cmd_before_env=$2
+test_program_cmd_after_env=$3
 
 # Run the test program.
-LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}iconvdata \
-NLSPATH=${common_objpfx}catgets/%N.%c.cat LC_ALL=ja_JP.SJIS \
-  ${test_program_cmd} \
+${test_program_cmd_before_env} \
+  LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}iconvdata \
+  NLSPATH=${common_objpfx}catgets/%N.%c.cat LC_ALL=ja_JP.SJIS \
+  ${test_program_cmd_after_env} \
     > ${common_objpfx}catgets/test-gencat.out
 
 # Compare with the expected result.
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index 60d8bd3..f58f0ef 100644
--- a/iconvdata/Makefile
+++ b/iconvdata/Makefile
@@ -300,14 +300,15 @@  $(objpfx)tst-iconv7.out: $(objpfx)gconv-modules \
 $(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \
 			 $(addprefix $(objpfx),$(modules.so)) \
 			 $(common-objdir)/iconv/iconv_prog TESTS
-	$(SHELL) $< $(common-objdir) '$(test-wrapper)' > $@; \
+	$(SHELL) $< $(common-objdir) '$(test-wrapper-env)' > $@; \
 	$(evaluate-test)
 
 $(objpfx)tst-tables.out: tst-tables.sh $(objpfx)gconv-modules \
 			 $(addprefix $(objpfx),$(modules.so)) \
 			 $(objpfx)tst-table-from $(objpfx)tst-table-to
 	$(SHELL) $< $(common-objpfx) $(common-objpfx)iconvdata/ \
-		'$(test-program-prefix)' > $@; \
+		 '$(test-program-prefix-before-env)' \
+		 '$(test-program-prefix-after-env)' > $@; \
 	$(evaluate-test)
 
 do-tests-clean common-mostlyclean: tst-tables-clean
diff --git a/iconvdata/run-iconv-test.sh b/iconvdata/run-iconv-test.sh
index e23f60d..e104e72 100755
--- a/iconvdata/run-iconv-test.sh
+++ b/iconvdata/run-iconv-test.sh
@@ -21,7 +21,7 @@ 
 set -e
 
 codir=$1
-test_wrapper="$2"
+test_wrapper_env="$2"
 
 # We use always the same temporary file.
 temp1=$codir/iconvdata/iconv-test.xxx
@@ -31,8 +31,7 @@  trap "rm -f $temp1 $temp2" 1 2 3 15
 
 # We must tell the iconv(1) program where the modules we want to use can
 # be found.
-GCONV_PATH=$codir/iconvdata
-export GCONV_PATH
+env=GCONV_PATH=$codir/iconvdata
 
 # We have to have some directories in the library path.
 LIBPATH=$codir:$codir/iconvdata
@@ -40,7 +39,7 @@  LIBPATH=$codir:$codir/iconvdata
 # How the start the iconv(1) program.
 ICONV='$codir/elf/ld.so --library-path $LIBPATH --inhibit-rpath ${from}.so \
        $codir/iconv/iconv_prog'
-ICONV="$test_wrapper $ICONV"
+ICONV="$test_wrapper_env $env $ICONV"
 
 # Which echo?
 if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
diff --git a/iconvdata/tst-table.sh b/iconvdata/tst-table.sh
index c68a3b9..3f9873a 100755
--- a/iconvdata/tst-table.sh
+++ b/iconvdata/tst-table.sh
@@ -23,12 +23,12 @@ 
 
 common_objpfx=$1
 objpfx=$2
-test_program_prefix=$3
-charset=$4
-charmap=$5
+test_program_prefix_before_env=$3
+test_program_prefix_after_env=$4
+charset=$5
+charmap=$6
 
-GCONV_PATH=${common_objpfx}iconvdata
-export GCONV_PATH
+env="GCONV_PATH=${common_objpfx}iconvdata LC_ALL=C"
 LC_ALL=C
 export LC_ALL
 
@@ -60,12 +60,12 @@  else
 fi
 
 # iconv in one direction.
-${test_program_prefix} \
+${test_program_prefix_before_env} ${env} ${test_program_prefix_after_env} \
 ${objpfx}tst-table-from ${charset} \
   > ${objpfx}tst-${charset}.table
 
 # iconv in the other direction.
-${test_program_prefix} \
+${test_program_prefix_before_env} ${env} ${test_program_prefix_after_env} \
 ${objpfx}tst-table-to ${charset} | sort \
   > ${objpfx}tst-${charset}.inverse.table
 
diff --git a/iconvdata/tst-tables.sh b/iconvdata/tst-tables.sh
index 116d88e..06e77f3 100755
--- a/iconvdata/tst-tables.sh
+++ b/iconvdata/tst-tables.sh
@@ -23,7 +23,8 @@ 
 
 common_objpfx=$1
 objpfx=$2
-test_program_prefix=$3
+test_program_prefix_before_env=$3
+test_program_prefix_after_env=$4
 
 status=0
 
@@ -262,7 +263,8 @@  while read charset charmap; do
   if test "$charset" = GB18030; then echo "This might take a while" 1>&2; fi
   case ${charset} in \#*) continue;; esac
   echo -n "Testing ${charset}" 1>&2
-  if ./tst-table.sh ${common_objpfx} ${objpfx} "${test_program_prefix}" \
+  if ./tst-table.sh ${common_objpfx} ${objpfx} \
+      "${test_program_prefix_before_env}" "${test_program_prefix_after_env}" \
       ${charset} ${charmap} < /dev/null; then
     echo 1>&2
   else
diff --git a/intl/Makefile b/intl/Makefile
index f11449d..6a59a2b 100644
--- a/intl/Makefile
+++ b/intl/Makefile
@@ -81,22 +81,25 @@  $(objpfx)mtrace-tst-gettext.out: $(objpfx)tst-gettext.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-gettext.mtrace > $@; \
 	$(evaluate-test)
 $(objpfx)tst-gettext.out: tst-gettext.sh $(objpfx)tst-gettext
-	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' \
+	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+	  '$(test-program-prefix-after-env)' \
 	  $(common-objpfx)intl/ $(objpfx)tst-gettext.mtrace; \
 	$(evaluate-test)
 $(objpfx)tst-translit.out: tst-translit.sh $(objpfx)tst-translit
-	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' \
-	  $(common-objpfx)intl/; \
+	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+	  '$(test-program-prefix-after-env)' $(common-objpfx)intl/; \
 	$(evaluate-test)
 $(objpfx)tst-gettext2.out: tst-gettext2.sh $(objpfx)tst-gettext2
-	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' \
-	  $(common-objpfx)intl/; \
+	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+	  '$(test-program-prefix-after-env)' $(common-objpfx)intl/; \
 	$(evaluate-test)
 $(objpfx)tst-gettext4.out: tst-gettext4.sh $(objpfx)tst-gettext4
-	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' $(common-objpfx)intl/; \
+	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+	  '$(test-program-prefix-after-env)' $(common-objpfx)intl/; \
 	$(evaluate-test)
 $(objpfx)tst-gettext6.out: tst-gettext6.sh $(objpfx)tst-gettext6
-	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' $(common-objpfx)intl/; \
+	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+	  '$(test-program-prefix-after-env)' $(common-objpfx)intl/; \
 	$(evaluate-test)
 
 $(objpfx)tst-codeset.out: $(codeset_mo)
diff --git a/intl/tst-gettext.sh b/intl/tst-gettext.sh
index 0483e2b..89e2509 100755
--- a/intl/tst-gettext.sh
+++ b/intl/tst-gettext.sh
@@ -20,9 +20,10 @@ 
 set -e
 
 common_objpfx=$1
-test_program_prefix=$2
-objpfx=$3
-malloc_trace=$4
+test_program_prefix_before_env=$2
+test_program_prefix_after_env=$3
+objpfx=$4
+malloc_trace=$5
 
 LC_ALL=C
 export LC_ALL
@@ -47,14 +48,11 @@  msgfmt -o ${objpfx}domaindir/existing-locale/LC_MESSAGES/existing-domain.mo \
 msgfmt -o ${objpfx}domaindir/existing-locale/LC_TIME/existing-time-domain.mo \
        -f ../po/de.po
 
-GCONV_PATH=${common_objpfx}iconvdata
-export GCONV_PATH
-LOCPATH=${common_objpfx}localedata
-export LOCPATH
-
 # Now run the test.
-MALLOC_TRACE=$malloc_trace LOCPATH=${objpfx}localedir:$LOCPATH \
-${test_program_prefix} \
+${test_program_prefix_before_env} \
+MALLOC_TRACE=$malloc_trace LC_ALL=C GCONV_PATH=${common_objpfx}iconvdata \
+LOCPATH=${objpfx}localedir:${common_objpfx}localedata \
+${test_program_prefix_after_env} \
 ${objpfx}tst-gettext > ${objpfx}tst-gettext.out ${objpfx}domaindir
 
 exit $?
diff --git a/intl/tst-gettext2.sh b/intl/tst-gettext2.sh
index 44821d2..b745193 100644
--- a/intl/tst-gettext2.sh
+++ b/intl/tst-gettext2.sh
@@ -20,8 +20,9 @@ 
 set -e
 
 common_objpfx=$1
-test_program_prefix=$2
-objpfx=$3
+test_program_prefix_before_env=$2
+test_program_prefix_after_env=$3
+objpfx=$4
 
 LC_ALL=C
 export LC_ALL
@@ -61,13 +62,10 @@  msgfmt -o ${objpfx}domaindir/lang1/LC_MESSAGES/tstlang.mo \
 msgfmt -o ${objpfx}domaindir/lang2/LC_MESSAGES/tstlang.mo \
        tstlang2.po
 
-GCONV_PATH=${common_objpfx}iconvdata
-export GCONV_PATH
-LOCPATH=${objpfx}domaindir
-export LOCPATH
-
 # Now run the test.
-${test_program_prefix} \
+${test_program_prefix_before_env} \
+LC_ALL=C GCONV_PATH=${common_objpfx}iconvdata LOCPATH=${objpfx}domaindir \
+${test_program_prefix_after_env} \
 ${objpfx}tst-gettext2 > ${objpfx}tst-gettext2.out ${objpfx}domaindir &&
 cmp ${objpfx}tst-gettext2.out - <<EOF
 String1 - Lang1: 1st string
diff --git a/intl/tst-gettext4.sh b/intl/tst-gettext4.sh
index fc975df..1f0c564 100755
--- a/intl/tst-gettext4.sh
+++ b/intl/tst-gettext4.sh
@@ -21,8 +21,9 @@ 
 set -e
 
 common_objpfx=$1
-test_program_prefix=$2
-objpfx=$3
+test_program_prefix_before_env=$2
+test_program_prefix_after_env=$3
+objpfx=$4
 
 LC_ALL=C
 export LC_ALL
@@ -34,11 +35,10 @@  mkdir -p ${objpfx}domaindir/fr_FR/LC_MESSAGES
 msgfmt -o ${objpfx}domaindir/de_DE/LC_MESSAGES/multithread.mo tst-gettext4-de.po
 msgfmt -o ${objpfx}domaindir/fr_FR/LC_MESSAGES/multithread.mo tst-gettext4-fr.po
 
-GCONV_PATH=${common_objpfx}iconvdata
-export GCONV_PATH
-LOCPATH=${common_objpfx}localedata
-export LOCPATH
-
-${test_program_prefix} ${objpfx}tst-gettext4 > ${objpfx}tst-gettext4.out
+${test_program_prefix_before_env} \
+LC_ALL=C \
+GCONV_PATH=${common_objpfx}iconvdata LOCPATH=${common_objpfx}localedata \
+${test_program_prefix_after_env} \
+${objpfx}tst-gettext4 > ${objpfx}tst-gettext4.out
 
 exit $?
diff --git a/intl/tst-gettext6.sh b/intl/tst-gettext6.sh
index 70cbcbe..ffeba57 100644
--- a/intl/tst-gettext6.sh
+++ b/intl/tst-gettext6.sh
@@ -20,8 +20,9 @@ 
 set -e
 
 common_objpfx=$1
-test_program_prefix=$2
-objpfx=$3
+test_program_prefix_before_env=$2
+test_program_prefix_after_env=$3
+objpfx=$4
 
 LC_ALL=C
 export LC_ALL
@@ -31,11 +32,10 @@  mkdir -p ${objpfx}domaindir/ja_JP/LC_MESSAGES
 # Populate it.
 msgfmt -o ${objpfx}domaindir/ja_JP/LC_MESSAGES/tstgettext6.mo ../po/ja.po
 
-GCONV_PATH=${common_objpfx}iconvdata
-export GCONV_PATH
-LOCPATH=${common_objpfx}localedata
-export LOCPATH
-
-${test_program_prefix} ${objpfx}tst-gettext6 > ${objpfx}tst-gettext6.out
+${test_program_prefix_before_env} \
+LC_ALL=C \
+GCONV_PATH=${common_objpfx}iconvdata LOCPATH=${common_objpfx}localedata \
+${test_program_prefix_after_env} \
+${objpfx}tst-gettext6 > ${objpfx}tst-gettext6.out
 
 exit $?
diff --git a/intl/tst-translit.sh b/intl/tst-translit.sh
index 4803340..e2bb6e1 100755
--- a/intl/tst-translit.sh
+++ b/intl/tst-translit.sh
@@ -20,8 +20,9 @@ 
 set -e
 
 common_objpfx=$1
-test_program_prefix=$2
-objpfx=$3
+test_program_prefix_before_env=$2
+test_program_prefix_after_env=$3
+objpfx=$4
 
 LC_ALL=C
 export LC_ALL
@@ -32,12 +33,10 @@  mkdir -p ${objpfx}localedir/existing-locale/LC_MESSAGES
 msgfmt -o ${objpfx}domaindir/existing-locale/LC_MESSAGES/translit.mo \
        translit.po
 
-GCONV_PATH=${common_objpfx}iconvdata
-export GCONV_PATH
-LOCPATH=${common_objpfx}localedata
-export LOCPATH
-
-${test_program_prefix} \
+${test_program_prefix_before_env} \
+LC_ALL=C \
+GCONV_PATH=${common_objpfx}iconvdata LOCPATH=${common_objpfx}localedata \
+${test_program_prefix_after_env} \
 ${objpfx}tst-translit > ${objpfx}tst-translit.out ${objpfx}domaindir
 
 exit $?
diff --git a/localedata/Makefile b/localedata/Makefile
index 48ec3de..52d1b7b 100644
--- a/localedata/Makefile
+++ b/localedata/Makefile
@@ -151,60 +151,74 @@  $(addsuffix .out,$(addprefix $(objpfx),$(tests))): %: \
 
 $(objpfx)sort-test.out: sort-test.sh $(objpfx)collate-test $(objpfx)xfrm-test \
 		       $(test-input-data) $(addprefix $(objpfx),$(CTYPE_FILES))
-	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' $(test-input) \
+	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+	  '$(test-program-prefix-after-env)' $(test-input) \
 	  > $@; \
 	$(evaluate-test)
 $(objpfx)tst-fmon.out: tst-fmon.sh $(objpfx)tst-fmon tst-fmon.data \
 		       $(objpfx)sort-test.out \
 		       $(addprefix $(objpfx),$(CTYPE_FILES))
-	$(SHELL) $< $(common-objpfx) '$(run-program-prefix)' \
-		'$(test-program-prefix)' tst-fmon.data  \
+	$(SHELL) $< $(common-objpfx) '$(run-program-prefix-before-env)' \
+		 '$(run-program-prefix-after-env)' \
+		 '$(test-program-prefix-before-env)' \
+		 '$(test-program-prefix-after-env)' tst-fmon.data  \
 	  > $@; \
 	$(evaluate-test)
 $(objpfx)tst-numeric.out: tst-numeric.sh $(objpfx)tst-numeric tst-numeric.data \
 		       $(objpfx)sort-test.out \
 		       $(addprefix $(objpfx),$(CTYPE_FILES))
-	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' tst-numeric.data \
+	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+		 '$(test-program-prefix-after-env)' tst-numeric.data \
 	  > $@; \
 	$(evaluate-test)
 $(objpfx)tst-locale.out: tst-locale.sh $(common-objpfx)locale/localedef \
 			 $(ld-test-srcs) $(addprefix $(objpfx),$(CTYPE_FILES))
-	$(SHELL) $< $(common-objpfx) '$(built-program-cmd)' > $@; \
+	$(SHELL) $< $(common-objpfx) '$(built-program-cmd-before-env)' \
+		 '$(built-program-cmd-after-env)' > $@; \
 	$(evaluate-test)
 $(objpfx)tst-rpmatch.out: tst-rpmatch.sh $(objpfx)tst-rpmatch \
 			  $(objpfx)tst-fmon.out \
 			  $(addprefix $(objpfx),$(CTYPE_FILES))
-	$(SHELL) $< $(common-objpfx) '$(test-program-cmd)' > $@; \
+	$(SHELL) $< $(common-objpfx) '$(test-program-cmd-before-env)' \
+		 '$(test-program-cmd-after-env)' > $@; \
 	$(evaluate-test)
 $(objpfx)tst-trans.out: tst-trans.sh $(objpfx)tst-trans \
 			$(addprefix $(objpfx),$(CTYPE_FILES))
-	$(SHELL) $< $(common-objpfx) '$(run-program-prefix)' '$(test-program-prefix)'; \
+	$(SHELL) $< $(common-objpfx) '$(run-program-prefix-before-env)' \
+		 '$(run-program-prefix-after-env)' \
+		 '$(test-program-prefix-before-env)' \
+		 '$(test-program-prefix-after-env)'; \
 	$(evaluate-test)
 $(objpfx)tst-mbswcs.out: tst-mbswcs.sh $(objpfx)tst-mbswcs1 \
 			 $(objpfx)tst-mbswcs2 $(objpfx)tst-mbswcs3 \
 			 $(objpfx)tst-mbswcs4 $(objpfx)tst-mbswcs5 \
 			 $(addprefix $(objpfx),$(CTYPE_FILES))
-	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
+	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+		 '$(test-program-prefix-after-env)'; \
 	$(evaluate-test)
 $(objpfx)tst-ctype.out: tst-ctype.sh $(objpfx)tst-ctype \
 			$(objpfx)sort-test.out \
 			$(addprefix $(objpfx),$(CTYPE_FILES))
-	$(SHELL) $< $(common-objpfx) '$(test-program-cmd)'; \
+	$(SHELL) $< $(common-objpfx) '$(test-program-cmd-before-env)' \
+		 '$(test-program-cmd-after-env)'; \
 	$(evaluate-test)
 $(objpfx)tst-wctype.out: tst-wctype.sh $(objpfx)tst-wctype \
 			$(objpfx)sort-test.out tst-wctype.input \
 			$(addprefix $(objpfx),$(CTYPE_FILES))
-	$(SHELL) $< $(common-objpfx) '$(test-program-cmd)'; \
+	$(SHELL) $< $(common-objpfx) '$(test-program-cmd-before-env)' \
+		 '$(test-program-cmd-after-env)'; \
 	$(evaluate-test)
 $(objpfx)tst-langinfo.out: tst-langinfo.sh $(objpfx)tst-langinfo \
 			$(objpfx)sort-test.out \
 			$(addprefix $(objpfx),$(CTYPE_FILES))
-	$(SHELL) $< $(common-objpfx) '$(test-program-cmd)' > $@; \
+	$(SHELL) $< $(common-objpfx) '$(test-program-cmd-before-env)' \
+		 '$(test-program-cmd-after-env)' > $@; \
 	$(evaluate-test)
 $(objpfx)tst-langinfo-static.out: tst-langinfo.sh $(objpfx)tst-langinfo-static \
 			$(objpfx)sort-test.out \
 			$(addprefix $(objpfx),$(CTYPE_FILES))
-	$(SHELL) $< $(common-objpfx) '$(test-program-cmd)' > $@; \
+	$(SHELL) $< $(common-objpfx) '$(test-program-cmd-before-env)' \
+		 '$(test-program-cmd-after-env)' > $@; \
 	$(evaluate-test)
 $(objpfx)tst-digits.out: $(objpfx)tst-locale.out
 $(objpfx)tst-mbswcs6.out: $(addprefix $(objpfx),$(CTYPE_FILES))
diff --git a/localedata/sort-test.sh b/localedata/sort-test.sh
index 8a7ca89..b4b0ffc 100644
--- a/localedata/sort-test.sh
+++ b/localedata/sort-test.sh
@@ -20,7 +20,8 @@ 
 set -e
 
 common_objpfx=$1; shift
-test_program_prefix=$1; shift
+test_program_prefix_before_env=$1; shift
+test_program_prefix_after_env=$1; shift
 lang=$*
 
 id=${PPID:-100}
@@ -31,8 +32,9 @@  status=0
 for l in $lang; do
   here=0
   cns=`echo $l | sed 's/\(.*\)[.][^.]*/\1/'`
-  LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}/iconvdata \
-   LC_ALL=$l ${test_program_prefix} \
+  ${test_program_prefix_before_env} \
+   LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}/iconvdata \
+   LC_ALL=$l ${test_program_prefix_after_env} \
    ${common_objpfx}localedata/collate-test $id < $cns.in \
    > ${common_objpfx}localedata/$cns.out || here=1
   cmp -s $cns.in ${common_objpfx}localedata/$cns.out || here=1
@@ -44,8 +46,9 @@  for l in $lang; do
     status=1
   fi
 
-  LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}/iconvdata \
-   LC_ALL=$l ${test_program_prefix} \
+  ${test_program_prefix_before_env} \
+   LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}/iconvdata \
+   LC_ALL=$l ${test_program_prefix_after_env} \
    ${common_objpfx}localedata/xfrm-test $id < $cns.in \
    > ${common_objpfx}localedata/$cns.xout || here=1
   cmp -s $cns.in ${common_objpfx}localedata/$cns.xout || here=1
diff --git a/localedata/tst-ctype.sh b/localedata/tst-ctype.sh
index 472f8dc..05222c9 100755
--- a/localedata/tst-ctype.sh
+++ b/localedata/tst-ctype.sh
@@ -20,7 +20,8 @@ 
 set -e
 
 common_objpfx=$1; shift
-tst_ctype=$1; shift
+tst_ctype_before_env=$1; shift
+tst_ctype_after_env=$1; shift
 status=0
 
 # Run the test programs.
@@ -31,8 +32,9 @@  for loc in C de_DE.ISO-8859-1 de_DE.UTF-8 en_US.ANSI_X3.4-1968 ja_JP.EUC-JP; do
   else
     input=/dev/null
   fi
+  ${tst_ctype_before_env} \
   LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}iconvdata \
-  LC_ALL=$loc ${tst_ctype} < $input \
+  LC_ALL=$loc ${tst_ctype_after_env} < $input \
     >> ${common_objpfx}localedata/tst-ctype.out || status=1
 done
 
diff --git a/localedata/tst-fmon.sh b/localedata/tst-fmon.sh
index e68aa96..0e29e5a 100755
--- a/localedata/tst-fmon.sh
+++ b/localedata/tst-fmon.sh
@@ -21,9 +21,11 @@ 
 set -e
 
 common_objpfx=$1
-run_program_prefix=$2
-test_program_prefix=$3
-datafile=$4
+run_program_prefix_before_env=$2
+run_program_prefix_after_env=$3
+test_program_prefix_before_env=$4
+test_program_prefix_after_env=$5
+datafile=$6
 
 here=`pwd`
 
@@ -33,9 +35,10 @@  lang=`sed -e '/^#/d' -e '/^$/d' -e '/^C	/d' -e '/^tstfmon/d' -e 's/^\([^	]*\).*/
 for cns in `cd ./tst-fmon-locales && ls tstfmon_*`; do
     cn=tst-fmon-locales/$cns
     fn=charmaps/ISO-8859-1
+    ${run_program_prefix_before_env} \
     I18NPATH=. GCONV_PATH=${common_objpfx}iconvdata \
     LOCPATH=${common_objpfx}localedata LC_ALL=C LANGUAGE=C \
-    ${run_program_prefix} ${common_objpfx}locale/localedef \
+    ${run_program_prefix_after_env} ${common_objpfx}locale/localedef \
     --quiet -i $cn -f $fn ${common_objpfx}localedata/$cns
 done
 
@@ -46,9 +49,10 @@  while IFS="	" read locale format value expect; do
     case "$locale" in '#'*) continue ;; esac
     if [ -n "$format" ]; then
 	expect=`echo "$expect" | sed 's/^\"\(.*\)\"$/\1/'`
+	${test_program_prefix_before_env} \
 	LOCPATH=${common_objpfx}localedata \
 	GCONV_PATH=${common_objpfx}/iconvdata \
-	${test_program_prefix} ${common_objpfx}localedata/tst-fmon \
+	${test_program_prefix_after_env} ${common_objpfx}localedata/tst-fmon \
 	"$locale" "$format" "$value" "$expect" < /dev/null ||
 	errcode=$?
     fi
diff --git a/localedata/tst-langinfo.sh b/localedata/tst-langinfo.sh
index bd489d0..6dd506a 100755
--- a/localedata/tst-langinfo.sh
+++ b/localedata/tst-langinfo.sh
@@ -20,7 +20,8 @@ 
 set -e
 
 common_objpfx=$1
-tst_langinfo=$2
+tst_langinfo_before_env=$2
+tst_langinfo_after_env=$3
 
 # Run the test program.
 cat <<"EOF" |
@@ -339,7 +340,8 @@  ja_JP.EUC-JP         NOEXPR      ^([nN
 # ja_JP.EUC-JP         CRNCYSTR    JPY
 ja_JP.EUC-JP         CODESET     EUC-JP
 EOF
+${tst_langinfo_before_env} \
 LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}iconvdata \
-LC_ALL=tt_TT ${tst_langinfo}
+LC_ALL=tt_TT ${tst_langinfo_after_env}
 
 exit $?
diff --git a/localedata/tst-locale.sh b/localedata/tst-locale.sh
index b89dc09..f6f124d 100755
--- a/localedata/tst-locale.sh
+++ b/localedata/tst-locale.sh
@@ -21,7 +21,8 @@ 
 set -e
 
 common_objpfx=$1; shift
-localedef=$1; shift
+localedef_before_env=$1; shift
+localedef_after_env=$1; shift
 
 test_locale ()
 {
@@ -32,9 +33,10 @@  test_locale ()
     if test $rep; then
       rep="--repertoire-map $rep"
     fi
+    ${localedef_before_env} \
     I18NPATH=. GCONV_PATH=${common_objpfx}iconvdata \
     LOCPATH=${common_objpfx}localedata LC_ALL=C LANGUAGE=C \
-    ${localedef} --quiet -c -f $charmap -i $input \
+    ${localedef_after_env} --quiet -c -f $charmap -i $input \
       ${rep} ${common_objpfx}localedata/$out
 
     if [ $? -ne 0 ]; then
diff --git a/localedata/tst-mbswcs.sh b/localedata/tst-mbswcs.sh
index 6a70fd7..b41d8ea 100755
--- a/localedata/tst-mbswcs.sh
+++ b/localedata/tst-mbswcs.sh
@@ -20,29 +20,35 @@ 
 set -e
 
 common_objpfx=$1; shift
-test_program_prefix=$1; shift
+test_program_prefix_before_env=$1; shift
+test_program_prefix_after_env=$1; shift
 
 status=0
 
 # Run the test programs.
+${test_program_prefix_before_env} \
 LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}iconvdata \
-${test_program_prefix} ${common_objpfx}localedata/tst-mbswcs1 \
+${test_program_prefix_after_env} ${common_objpfx}localedata/tst-mbswcs1 \
   > ${common_objpfx}localedata/tst-mbswcs.out || status=1
 
+${test_program_prefix_before_env} \
 LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}iconvdata \
-${test_program_prefix} ${common_objpfx}localedata/tst-mbswcs2 \
+${test_program_prefix_after_env} ${common_objpfx}localedata/tst-mbswcs2 \
   >> ${common_objpfx}localedata/tst-mbswcs.out || status=1
 
+${test_program_prefix_before_env} \
 LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}iconvdata \
-${test_program_prefix} ${common_objpfx}localedata/tst-mbswcs3 \
+${test_program_prefix_after_env} ${common_objpfx}localedata/tst-mbswcs3 \
   >> ${common_objpfx}localedata/tst-mbswcs.out || status=1
 
+${test_program_prefix_before_env} \
 LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}iconvdata \
-${test_program_prefix} ${common_objpfx}localedata/tst-mbswcs4 \
+${test_program_prefix_after_env} ${common_objpfx}localedata/tst-mbswcs4 \
   >> ${common_objpfx}localedata/tst-mbswcs.out || status=1
 
+${test_program_prefix_before_env} \
 LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}iconvdata \
-${test_program_prefix} ${common_objpfx}localedata/tst-mbswcs5 \
+${test_program_prefix_after_env} ${common_objpfx}localedata/tst-mbswcs5 \
   >> ${common_objpfx}localedata/tst-mbswcs.out || status=1
 
 exit $status
diff --git a/localedata/tst-numeric.sh b/localedata/tst-numeric.sh
index ff797cd..994aae7 100644
--- a/localedata/tst-numeric.sh
+++ b/localedata/tst-numeric.sh
@@ -21,8 +21,9 @@ 
 set -e
 
 common_objpfx=$1
-test_program_prefix=$2
-datafile=$3
+test_program_prefix_before_env=$2
+test_program_prefix_after_env=$3
+datafile=$4
 
 # Run the tests.
 errcode=0
@@ -30,9 +31,11 @@  errcode=0
 while IFS="	" read locale format value expect; do
     case "$locale" in '#'*) continue ;; esac
     if [ -n "$format" ]; then
-	if LOCPATH=${common_objpfx}localedata \
+	if ${test_program_prefix_before_env} \
+	    LOCPATH=${common_objpfx}localedata \
 	    GCONV_PATH=${common_objpfx}/iconvdata \
-	    ${test_program_prefix} ${common_objpfx}localedata/tst-numeric \
+	    ${test_program_prefix_after_env} \
+	    ${common_objpfx}localedata/tst-numeric \
 	    "$locale" "$format" "$value" "$expect" < /dev/null
 	then
 	    echo "Locale: \"${locale}\" Format: \"${format}\"" \
diff --git a/localedata/tst-rpmatch.sh b/localedata/tst-rpmatch.sh
index bdb3b7c..171393e 100755
--- a/localedata/tst-rpmatch.sh
+++ b/localedata/tst-rpmatch.sh
@@ -21,14 +21,16 @@ 
 set -e
 
 common_objpfx=$1
-tst_rpmatch=$2
+tst_rpmatch_before_env=$2
+tst_rpmatch_after_env=$3
 
 rc=0
 while IFS=\& read locale string result dummy; do
     if [ "$locale" != "#" ]; then
+	${tst_rpmatch_before_env} \
 	LOCPATH=${common_objpfx}localedata \
 	GCONV_PATH=${common_objpfx}/iconvdata \
-	${tst_rpmatch} $locale $string $result < /dev/null \
+	${tst_rpmatch_after_env} $locale $string $result < /dev/null \
 	|| { echo "$locale $string $result  FAILED"; exit 1; }
     fi
 done <<EOF
diff --git a/localedata/tst-trans.sh b/localedata/tst-trans.sh
index e82e4f8..ed7a65e 100755
--- a/localedata/tst-trans.sh
+++ b/localedata/tst-trans.sh
@@ -20,20 +20,24 @@ 
 set -e
 
 common_objpfx=$1
-run_program_prefix=$2
-test_program_prefix=$3
+run_program_prefix_before_env=$2
+run_program_prefix_after_env=$3
+test_program_prefix_before_env=$4
+test_program_prefix_after_env=$5
 
 # Generate the necessary locale data.
+${run_program_prefix_before_env} \
 I18NPATH=. GCONV_PATH=${common_objpfx}/iconvdata \
-${run_program_prefix} \
+${run_program_prefix_after_env} \
 ${common_objpfx}locale/localedef --quiet \
 -i tests/trans.def -f charmaps/ISO-8859-1 \
 ${common_objpfx}localedata/tt_TT ||
 exit 1
 
 # Run the test program.
+${test_program_prefix_before_env} \
 LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}iconvdata \
-LC_ALL=tt_TT ${test_program_prefix} \
+LC_ALL=tt_TT ${test_program_prefix_after_env} \
 ${common_objpfx}localedata/tst-trans > ${common_objpfx}localedata/tst-trans.out
 
 exit $?
diff --git a/localedata/tst-wctype.sh b/localedata/tst-wctype.sh
index 31d57bc..0245a22 100755
--- a/localedata/tst-wctype.sh
+++ b/localedata/tst-wctype.sh
@@ -20,11 +20,13 @@ 
 set -e
 
 common_objpfx=$1
-tst_wctype=$2
+tst_wctype_before_env=$2
+tst_wctype_after_env=$3
 
 # Run the test program.
+${tst_wctype_before_env} \
 LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}iconvdata \
-LC_ALL=ja_JP.EUC-JP ${tst_wctype} < tst-wctype.input \
+LC_ALL=ja_JP.EUC-JP ${tst_wctype_after_env} < tst-wctype.input \
     > ${common_objpfx}localedata/tst-wctype.out
 
 exit $?
diff --git a/malloc/Makefile b/malloc/Makefile
index 7a716f9..3be5b7f 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -116,7 +116,8 @@  ifeq ($(run-built-tests),yes)
 ifeq (yes,$(build-shared))
 ifneq ($(PERL),no)
 $(objpfx)tst-mtrace.out: tst-mtrace.sh $(objpfx)tst-mtrace
-	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
+	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+		 '$(test-program-prefix-after-env)' ; \
 	$(evaluate-test)
 endif
 endif
diff --git a/malloc/tst-mtrace.sh b/malloc/tst-mtrace.sh
index abd425d..0430c6b 100755
--- a/malloc/tst-mtrace.sh
+++ b/malloc/tst-mtrace.sh
@@ -20,14 +20,16 @@ 
 set -e
 
 common_objpfx=$1; shift
-test_program_prefix=$1; shift
+test_program_prefix_before_env=$1; shift
+test_program_prefix_after_env=$1; shift
 
 status=0
 trap "rm -f ${common_objpfx}malloc/tst-mtrace.leak; exit 1" 1 2 15
 
+${test_program_prefix_before_env} \
 MALLOC_TRACE=${common_objpfx}malloc/tst-mtrace.leak \
 LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}iconvdata \
-${test_program_prefix} \
+${test_program_prefix_after_env} \
   ${common_objpfx}malloc/tst-mtrace || status=1
 
 if test $status -eq 0 && test -f ${common_objpfx}malloc/mtrace; then
diff --git a/manual/install.texi b/manual/install.texi
index d7da02b..e0902ef 100644
--- a/manual/install.texi
+++ b/manual/install.texi
@@ -275,8 +275,8 @@  system and @var{hostname}.
 In general, when testing @theglibc{}, @samp{test-wrapper} may be set
 to the name and arguments of any program to run newly built binaries.
 This program must preserve the arguments to the binary being run, its
-working directory, all environment variables set as part of testing
-and the standard input, output and error file descriptors.  If
+working directory and the standard input, output and error file
+descriptors.  If
 @samp{@var{test-wrapper} env} will not work to run a program with
 environment variables set, then @samp{test-wrapper-env} must be set to
 a program that runs a newly built program with environment variable
diff --git a/nptl/tst-tls6.sh b/nptl/tst-tls6.sh
index 5a897fe..846ddea 100755
--- a/nptl/tst-tls6.sh
+++ b/nptl/tst-tls6.sh
@@ -40,6 +40,7 @@  for aligned in a e f; do
   echo "preload tst-tls5mod{$aligned,b,c,d}.so" >> $logfile
   echo "===============" >> $logfile
   ${test_wrapper_env} \
+  LC_ALL=C LANG=C \
   LD_PRELOAD="`echo ${common_objpfx}nptl/tst-tls5mod{$aligned,b,c,d}.so \
 	      | sed 's/:$//;s/: /:/g'`" ${tst_tls5} >> $logfile || fail=1
   echo >> $logfile
@@ -47,6 +48,7 @@  for aligned in a e f; do
   echo "preload tst-tls5mod{b,$aligned,c,d}.so" >> $logfile
   echo "===============" >> $logfile
   ${test_wrapper_env} \
+  LC_ALL=C LANG=C \
   LD_PRELOAD="`echo ${common_objpfx}nptl/tst-tls5mod{b,$aligned,c,d}.so \
 	      | sed 's/:$//;s/: /:/g'`" ${tst_tls5} >> $logfile || fail=1
   echo >> $logfile
@@ -54,6 +56,7 @@  for aligned in a e f; do
   echo "preload tst-tls5mod{b,c,d,$aligned}.so" >> $logfile
   echo "===============" >> $logfile
   ${test_wrapper_env} \
+  LC_ALL=C LANG=C \
   LD_PRELOAD="`echo ${common_objpfx}nptl/tst-tls5mod{b,c,d,$aligned}.so \
 	      | sed 's/:$//;s/: /:/g'`" ${tst_tls5} >> $logfile || fail=1
   echo >> $logfile
@@ -62,6 +65,7 @@  done
 echo "preload tst-tls5mod{d,a,b,c,e}" >> $logfile
 echo "===============" >> $logfile
 ${test_wrapper_env} \
+LC_ALL=C LANG=C \
 LD_PRELOAD="`echo ${common_objpfx}nptl/tst-tls5mod{d,a,b,c,e}.so \
 	    | sed 's/:$//;s/: /:/g'`" ${tst_tls5} >> $logfile || fail=1
 echo >> $logfile
@@ -69,6 +73,7 @@  echo >> $logfile
 echo "preload tst-tls5mod{d,a,b,e,f}" >> $logfile
 echo "===============" >> $logfile
 ${test_wrapper_env} \
+LC_ALL=C LANG=C \
 LD_PRELOAD="`echo ${common_objpfx}nptl/tst-tls5mod{d,a,b,e,f}.so \
 	    | sed 's/:$//;s/: /:/g'`" ${tst_tls5} >> $logfile || fail=1
 echo >> $logfile
diff --git a/posix/Makefile b/posix/Makefile
index 328c2c5..70b83f3 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -143,7 +143,8 @@  $(objpfx)globtest.out: globtest.sh $(objpfx)globtest
 		'$(test-program-prefix)' '$(test-wrapper-env)'; \
 	$(evaluate-test)
 $(objpfx)wordexp-tst.out: wordexp-tst.sh $(objpfx)wordexp-test
-	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
+	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+		 '$(test-program-prefix-after-env)'; \
 	$(evaluate-test)
 endif
 endif
diff --git a/posix/wordexp-tst.sh b/posix/wordexp-tst.sh
index 392feb0..034a11c 100755
--- a/posix/wordexp-tst.sh
+++ b/posix/wordexp-tst.sh
@@ -24,7 +24,8 @@  set -e
 # The others are just there to be parameters.
 
 common_objpfx=$1; shift
-test_program_prefix=$1; shift
+test_program_prefix_before_env=$1; shift
+test_program_prefix_after_env=$1; shift
 logfile=${common_objpfx}posix/wordexp-tst.out
 testout=${common_objpfx}posix/wordexp-test-result
 
@@ -38,7 +39,7 @@  IFS=" 	\
 export IFS
 
 failed=0
-${test_program_prefix} \
+${test_program_prefix_before_env} IFS="$IFS" ${test_program_prefix_after_env} \
 ${common_objpfx}posix/wordexp-test '$*' > ${testout}1
 cat <<"EOF" | cmp - ${testout}1 >> $logfile || failed=1
 wordexp returned 0
@@ -50,7 +51,7 @@  if test $failed -ne 0; then
 fi
 
 failed=0
-${test_program_prefix} \
+${test_program_prefix_before_env} IFS="$IFS" ${test_program_prefix_after_env} \
 ${common_objpfx}posix/wordexp-test '${*}' unquoted > ${testout}2
 cat <<"EOF" | cmp - ${testout}2 >> $logfile || failed=1
 wordexp returned 0
@@ -63,7 +64,7 @@  if test $failed -ne 0; then
 fi
 
 failed=0
-${test_program_prefix} \
+${test_program_prefix_before_env} IFS="$IFS" ${test_program_prefix_after_env} \
 ${common_objpfx}posix/wordexp-test '$@' unquoted > ${testout}3
 cat <<"EOF" | cmp - ${testout}3 >> $logfile || failed=1
 wordexp returned 0
@@ -76,7 +77,7 @@  if test $failed -ne 0; then
 fi
 
 failed=0
-${test_program_prefix} \
+${test_program_prefix_before_env} IFS="$IFS" ${test_program_prefix_after_env} \
 ${common_objpfx}posix/wordexp-test '"$* quoted"' param > ${testout}4
 cat <<"EOF" | cmp - ${testout}4 >> $logfile || failed=1
 wordexp returned 0
@@ -88,7 +89,7 @@  if test $failed -ne 0; then
 fi
 
 failed=0
-${test_program_prefix} \
+${test_program_prefix_before_env} IFS="$IFS" ${test_program_prefix_after_env} \
 ${common_objpfx}posix/wordexp-test '"$@ quoted"' param > ${testout}5
 cat <<"EOF" | cmp - ${testout}5 >> $logfile || failed=1
 wordexp returned 0
@@ -102,7 +103,7 @@  fi
 # Why?  Because bash does it that way..
 
 failed=0
-${test_program_prefix} \
+${test_program_prefix_before_env} IFS="$IFS" ${test_program_prefix_after_env} \
 ${common_objpfx}posix/wordexp-test '$#' 2 3 4 5 > ${testout}6
 cat <<"EOF" | cmp - ${testout}6 >> $logfile || failed=1
 wordexp returned 0
@@ -114,7 +115,7 @@  if test $failed -ne 0; then
 fi
 
 failed=0
-${test_program_prefix} \
+${test_program_prefix_before_env} IFS="$IFS" ${test_program_prefix_after_env} \
 ${common_objpfx}posix/wordexp-test '$2 ${3} $4' 2nd 3rd "4 th" > ${testout}7
 cat <<"EOF" | cmp - ${testout}7 >> $logfile || failed=1
 wordexp returned 0
@@ -129,7 +130,7 @@  if test $failed -ne 0; then
 fi
 
 failed=0
-${test_program_prefix} \
+${test_program_prefix_before_env} IFS="$IFS" ${test_program_prefix_after_env} \
 ${common_objpfx}posix/wordexp-test '${11}' 2 3 4 5 6 7 8 9 10 11 > ${testout}8
 cat <<"EOF" | cmp - ${testout}8 >> $logfile || failed=1
 wordexp returned 0
@@ -141,7 +142,7 @@  if test $failed -ne 0; then
 fi
 
 failed=0
-${test_program_prefix} \
+${test_program_prefix_before_env} IFS="$IFS" ${test_program_prefix_after_env} \
 ${common_objpfx}posix/wordexp-test '"a $@ b"' c d > ${testout}9
 cat <<"EOF" | cmp - ${testout}9 >> $logfile || failed=1
 wordexp returned 0
@@ -154,7 +155,7 @@  if test $failed -ne 0; then
   status=1
 fi
 
-${test_program_prefix} \
+${test_program_prefix_before_env} IFS="$IFS" ${test_program_prefix_after_env} \
 ${common_objpfx}posix/wordexp-test '${#@} ${#2} *$**' two 3 4 > ${testout}10
 cat <<"EOF" | cmp - ${testout}10 || failed=1
 wordexp returned 0
diff --git a/scripts/cross-test-ssh.sh b/scripts/cross-test-ssh.sh
index 405ae99..0d6093f 100755
--- a/scripts/cross-test-ssh.sh
+++ b/scripts/cross-test-ssh.sh
@@ -21,13 +21,10 @@ 
 # Run with --help flag to get more detailed help.
 
 progname="$(basename $0)"
-env_blacklist='HOME LOGNAME MAIL PATH SHELL SHLVL SSH_CLIENT SSH_CONNECTION
-USER TERM TERMCAP PWD'
 
 usage="usage: ${progname} [--ssh SSH] HOST COMMAND ..."
 help="Run a glibc test COMMAND on the remote machine HOST, via ssh,
-passing environment variables, preserving the current working directory,
-and respecting quoting.
+preserving the current working directory, and respecting quoting.
 
 If the '--ssh SSH' flag is present, use SSH as the SSH command,
 instead of ordinary 'ssh'.
@@ -58,11 +55,7 @@  ${progname} itself is run in on the build machine.
 The command and arguments are passed to the remote host in a way that
 avoids any further shell substitution or expansion, on the assumption
 that the shell on the build machine has already done them
-appropriately.
-
-${progname} propagates the values all environment variables through to
-the remote target, except the following:
-${env_blacklist}"
+appropriately."
 
 ssh='ssh'
 while [ $# -gt 0 ]; do
@@ -108,24 +101,12 @@  bourne_quote ()
   done
 }
 
-# Unset all variables from the blacklist.  Then echo all exported
-# variables.
-blacklist_exports ()
-{
-  (unset ${env_blacklist}; export -p) | sed 's/^declare -x/export/'
-}
-
-# Produce commands to carry over the current environment, less blacklisted
-# variables.
-exports="$(blacklist_exports)"
-
 # Transform the current argument list into a properly quoted Bourne shell
 # command string.
 command="$(bourne_quote "$@")"
 
-# Add commands to set environment variables and the current directory.
-command="${exports}
-cd $(bourne_quote "$PWD")
+# Add command to set the current directory.
+command="cd $(bourne_quote "$PWD")
 ${command}"
 
 # HOST's sshd simply concatenates its arguments with spaces and
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index f179eab..2e1d8db 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -74,7 +74,8 @@  $(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
 	$(evaluate-test)
 
 $(objpfx)tst-printf.out: tst-printf.sh $(objpfx)tst-printf
-	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
+	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+		 '$(test-program-prefix-after-env)'; \
 	$(evaluate-test)
 endif
 
diff --git a/stdio-common/tst-printf.sh b/stdio-common/tst-printf.sh
index 521e660..c47594f 100644
--- a/stdio-common/tst-printf.sh
+++ b/stdio-common/tst-printf.sh
@@ -20,12 +20,14 @@ 
 set -e
 
 common_objpfx=$1; shift
-test_program_prefix=$1; shift
+test_program_prefix_before_env=$1; shift
+test_program_prefix_after_env=$1; shift
 
 status=0
 
+${test_program_prefix_before_env} \
 LOCPATH=${common_objpfx}localedata GCONV_PATH=${common_objpfx}iconvdata \
-${test_program_prefix} \
+${test_program_prefix_after_env} \
   ${common_objpfx}stdio-common/tst-printf \
   > ${common_objpfx}stdio-common/tst-printf.out || status=1
 
diff --git a/stdlib/Makefile b/stdlib/Makefile
index d7a562f..1dbdf29 100644
--- a/stdlib/Makefile
+++ b/stdlib/Makefile
@@ -140,7 +140,8 @@  $(objpfx)isomac: isomac.c
 	$(native-compile)
 
 $(objpfx)tst-fmtmsg.out: tst-fmtmsg.sh $(objpfx)tst-fmtmsg
-	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' $(common-objpfx)stdlib/; \
+	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+		 '$(test-program-prefix-after-env)' $(common-objpfx)stdlib/; \
 	$(evaluate-test)
 
 $(objpfx)tst-putenv: $(objpfx)tst-putenvmod.so
diff --git a/stdlib/tst-fmtmsg.sh b/stdlib/tst-fmtmsg.sh
index 4f075dc..e0abfd7 100755
--- a/stdlib/tst-fmtmsg.sh
+++ b/stdlib/tst-fmtmsg.sh
@@ -20,47 +20,49 @@ 
 set -e
 
 common_objpfx=$1
-test_program_prefix=$2
-objpfx=$3
+test_program_prefix_before_env=$2
+test_program_prefix_after_env=$3
+objpfx=$4
 
-test="${test_program_prefix} ${objpfx}tst-fmtmsg"
+test_pre="${test_program_prefix_before_env} LC_ALL=C"
+test="${test_program_prefix_after_env} ${objpfx}tst-fmtmsg"
 out=${objpfx}tst-fmtmsg.out
 
 LC_ALL=C
 export LC_ALL
 
-(MSGVERB= $test || exit 1;
- MSGVERB=label $test || exit 1;
- MSGVERB=severity $test || exit 1;
- MSGVERB=severity:label $test || exit 1;
- MSGVERB=text $test || exit 1;
- MSGVERB=text:label $test || exit 1;
- MSGVERB=text:severity $test || exit 1;
- MSGVERB=text:severity:label $test || exit 1;
- MSGVERB=action $test || exit 1;
- MSGVERB=action:label $test || exit 1;
- MSGVERB=action:severity $test || exit 1;
- MSGVERB=action:severity:label $test || exit 1;
- MSGVERB=action:text $test || exit 1;
- MSGVERB=action:text:label $test || exit 1;
- MSGVERB=action:text:severity $test || exit 1;
- MSGVERB=action:text:severity:label $test || exit 1;
- MSGVERB=tag $test || exit 1;
- MSGVERB=tag:label $test || exit 1;
- MSGVERB=tag:severity $test || exit 1;
- MSGVERB=tag:severity:label $test || exit 1;
- MSGVERB=tag:text $test || exit 1;
- MSGVERB=tag:text:label $test || exit 1;
- MSGVERB=tag:text:severity $test || exit 1;
- MSGVERB=tag:text:severity:label $test || exit 1;
- MSGVERB=tag:action $test || exit 1;
- MSGVERB=tag:action:label $test || exit 1;
- MSGVERB=tag:action:severity $test || exit 1;
- MSGVERB=tag:action:severity:label $test || exit 1;
- MSGVERB=tag:action:text $test || exit 1;
- MSGVERB=tag:action:text:label $test || exit 1;
- MSGVERB=tag:action:text:severity $test || exit 1;
- MSGVERB=tag:action:text:severity:label $test || exit 1;) 2> $out
+($test_pre MSGVERB= $test || exit 1;
+ $test_pre MSGVERB=label $test || exit 1;
+ $test_pre MSGVERB=severity $test || exit 1;
+ $test_pre MSGVERB=severity:label $test || exit 1;
+ $test_pre MSGVERB=text $test || exit 1;
+ $test_pre MSGVERB=text:label $test || exit 1;
+ $test_pre MSGVERB=text:severity $test || exit 1;
+ $test_pre MSGVERB=text:severity:label $test || exit 1;
+ $test_pre MSGVERB=action $test || exit 1;
+ $test_pre MSGVERB=action:label $test || exit 1;
+ $test_pre MSGVERB=action:severity $test || exit 1;
+ $test_pre MSGVERB=action:severity:label $test || exit 1;
+ $test_pre MSGVERB=action:text $test || exit 1;
+ $test_pre MSGVERB=action:text:label $test || exit 1;
+ $test_pre MSGVERB=action:text:severity $test || exit 1;
+ $test_pre MSGVERB=action:text:severity:label $test || exit 1;
+ $test_pre MSGVERB=tag $test || exit 1;
+ $test_pre MSGVERB=tag:label $test || exit 1;
+ $test_pre MSGVERB=tag:severity $test || exit 1;
+ $test_pre MSGVERB=tag:severity:label $test || exit 1;
+ $test_pre MSGVERB=tag:text $test || exit 1;
+ $test_pre MSGVERB=tag:text:label $test || exit 1;
+ $test_pre MSGVERB=tag:text:severity $test || exit 1;
+ $test_pre MSGVERB=tag:text:severity:label $test || exit 1;
+ $test_pre MSGVERB=tag:action $test || exit 1;
+ $test_pre MSGVERB=tag:action:label $test || exit 1;
+ $test_pre MSGVERB=tag:action:severity $test || exit 1;
+ $test_pre MSGVERB=tag:action:severity:label $test || exit 1;
+ $test_pre MSGVERB=tag:action:text $test || exit 1;
+ $test_pre MSGVERB=tag:action:text:label $test || exit 1;
+ $test_pre MSGVERB=tag:action:text:severity $test || exit 1;
+ $test_pre MSGVERB=tag:action:text:severity:label $test || exit 1;) 2> $out
 
 cmp $out <<EOF
 GLIBC:tst-fmtmsg: HALT: halt