diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 16:58:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 16:58:41 +0000 |
commit | e1908ae95dd4c9d19ee4dfabfc8bf8a7f85943fe (patch) | |
tree | f5cc731bedcac0fb7fe14d952e4581e749f8bb87 /tests/env | |
parent | Initial commit. (diff) | |
download | coreutils-e1908ae95dd4c9d19ee4dfabfc8bf8a7f85943fe.tar.xz coreutils-e1908ae95dd4c9d19ee4dfabfc8bf8a7f85943fe.zip |
Adding upstream version 9.4.upstream/9.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/env')
-rwxr-xr-x | tests/env/env-S-script.sh | 147 | ||||
-rwxr-xr-x | tests/env/env-S.pl | 289 | ||||
-rwxr-xr-x | tests/env/env-null.sh | 58 | ||||
-rwxr-xr-x | tests/env/env-signal-handler.sh | 126 | ||||
-rwxr-xr-x | tests/env/env.sh | 166 |
5 files changed, 786 insertions, 0 deletions
diff --git a/tests/env/env-S-script.sh b/tests/env/env-S-script.sh new file mode 100755 index 0000000..1d9b3e2 --- /dev/null +++ b/tests/env/env-S-script.sh @@ -0,0 +1,147 @@ +#!/bin/sh +# Test env -S in a #! line of a script. + +# Copyright (C) 2018-2023 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 <https://www.gnu.org/licenses/>. + + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ env +print_ver_ printf + +require_perl_ + +# a shortcut to avoid long lines +dir="$abs_top_builddir/src" + +cat <<EOF > shebang || framework_failure_ +#!$SHELL +EOF +cat <<\EOF >> shebang || framework_failure_ +# Execute a script as per 3 argument shebang +# but without length limits (127 on Linux for example). +script="$1"; shift +shebang=$(sed -n 's/^#!//p;q' < "$script") +interp=$(printf '%s' "$shebang" | cut -d' ' -f1) +rest=$(printf '%s' "$shebang" | cut -s -d' ' -f2-) +test "$rest" && exec "$interp" "$rest" "$script" "$@" +exec "$interp" "$script" "$@" +EOF +chmod a+x shebang || framework_failure_ + +# A simple shebang program to call our new "env" +printf "#!$dir/env sh\necho hello\n" > env_test || framework_failure_ +chmod a+x env_test || framework_failure_ + +# Verify we can run the shebang which is not the case if +# there are spaces in $abs_top_builddir. +./shebang ./env_test || skip_ "Error running env_test script" + +# env should execute 'printf' with 7 parameters: +# 'x%sx\n', 'A', 'B' from the "-S" argument, +# the name of the executed script, and its 3 parameters (C,D,'E F'). +# Ignoring the absolute paths, the script is: +# #!env -S printf x%sx\n A B +printf "#!$dir/env -S $dir/printf "'x%%sx\\n A B\n' > env1 || framework_failure_ +chmod a+x env1 || framework_failure_ +cat<<\EOF>exp1 || framework_failure_ +xAx +xBx +x./env1x +xCx +xDx +xE Fx +EOF +./shebang ./env1 C D "E F" > out1 || fail=1 +compare exp1 out1 || fail=1 + + +# similar to the above test but with quotes, the first parameter should be +# 'A B' and not two parameters 'A','B'. +# Ignoring the absolute paths, the script is: +# #!env -S printf x%sx\n "A B" +printf "#!$dir/env -S $dir/printf "'x%%sx\\n "A B"\n' > env2 || + framework_failure_ +chmod a+x env2 || framework_failure_ +cat<<\EOF>exp2 || framework_failure_ +xA Bx +x./env2x +EOF +./shebang ./env2 > out2 || fail=1 +compare exp2 out2 || fail=1 + + +# backslash-underscore instead of spaces. +# Ignoring the absolute paths, the script is: +# #!env -Sprintf\_x%sx\n\_Y +printf "#!$dir/env -S$dir/printf"'\\_x%%sx\\n\\_Y\n' > env3 || + framework_failure_ +chmod a+x env3 || framework_failure_ +cat<<\EOF>exp3 || framework_failure_ +xYx +x./env3x +xWx +EOF +./shebang ./env3 W > out3 || fail=1 +compare exp3 out3 || fail=1 + + + +# Test comments - The "#C D" should be ignored. +# Ignoring the absolute paths, the script is: +# #!env -Sprintf x%sx\n A#B #C D +printf "#!$dir/env -S$dir/printf"' x%%sx\\n A#B #C D\n' > env4 \ + || framework_failure_ +chmod a+x env4 || framework_failure_ +cat<<\EOF>exp4 || framework_failure_ +xA#Bx +x./env4x +xZx +EOF +./shebang ./env4 Z > out4 || fail=1 +compare exp4 out4 || fail=1 + + +# Test with a simple Perl usage. +# (assume Perl is in $PATH, as it is required for the test suite). +# Ignoring the absolute paths, the script is: +# #!env -S perl -w -T +# print "hello\n"; +{ printf "#!$dir/env -S $PERL -w -T\n" ; + printf 'print "hello\\n";\n' ; } > env5 || framework_failure_ +chmod a+x env5 || framework_failure_ +cat<<\EOF>exp5 || framework_failure_ +hello +EOF +./shebang ./env5 > out5 || fail=1 +compare exp5 out5 || fail=1 + + +# Test with a more complex Perl usage. +# Ignoring the absolute paths, the script is: +# #!env -S perl -mFile::Basename=basename -e "print basename(\$ARGV[0]);" +# The backslash before the '$' is required to prevent env(1) from treating +# $ARGV as an (invalid syntax) envvar, and pass it as-is to Perl. +{ printf "#!$dir/env -S " ; + printf "$PERL -mFile::Basename=basename -e " ; + printf '"print basename(\\$ARGV[0]);"\n' ; } > env6 || framework_failure_ +chmod a+x env6 || framework_failure_ +# Note: the perl script does not output a newline. +printf "env6" > exp6 || framework_failure_ +./shebang ./env6 > out6 || fail=1 +compare exp6 out6 || fail=1 + + +Exit $fail diff --git a/tests/env/env-S.pl b/tests/env/env-S.pl new file mode 100755 index 0000000..710ca82 --- /dev/null +++ b/tests/env/env-S.pl @@ -0,0 +1,289 @@ +#!/usr/bin/perl +# Test 'env -S' feature + +# Copyright (C) 2018-2023 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 <https://www.gnu.org/licenses/>. + +use strict; + +(my $program_name = $0) =~ s|.*/||; +my $prog = 'env'; + +my $env = "$ENV{abs_top_builddir}/src/env"; +# Ensure no whitespace or other problematic chars in path +$env =~ m!^([-+\@\w./]+)$! + or CuSkip::skip "unusual absolute builddir name; skipping this test\n"; +$env = $1; + +# Turn off localization of executable's output. +@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; + +# This envvar is somehow set at least on macOS 11.6, and would +# otherwise cause failure of q*, t* and more tests below. Ignore it. +my $cf = '__CF_USER_TEXT_ENCODING'; +exists $ENV{$cf} and $env .= " -u$cf"; +# Likewise for these Cygwin env vars +my $cf = 'SYSTEMROOT'; +exists $ENV{$cf} and $env .= " -u$cf"; +my $cf = 'WINDIR'; +exists $ENV{$cf} and $env .= " -u$cf"; + +my @Tests = + ( + # Test combination of -S and regular arguments + ['1', q[-ufoo A=B FOO=AR sh -c 'echo $A$FOO'], {OUT=>"BAR"}], + ['2', q[-ufoo -S'A=B FOO=AR sh -c "echo \\$A\\$FOO"'], {OUT=>"BAR"}], + ['3', q[-ufoo -S'A=B FOO=AR' sh -c 'echo $A$FOO'], {OUT=>"BAR"}], + ['4', q[-ufoo -S'A=B' FOO=AR sh -c 'echo $A$FOO'], {OUT=>"BAR"}], + ['5', q[-S'-ufoo A=B FOO=AR sh -c "echo \\$A\\$FOO"'], {OUT=>"BAR"}], + + # Test quoting inside -S + ['q1', q[-S'-i A="B C" ]."$env'", {OUT=>"A=B C"}], + ['q2', q[-S"-i A='B C' ]."$env\"", {OUT=>"A=B C"}], + ['q3', q[-S"-i A=\"B C\" ]."$env\"", {OUT=>"A=B C"}], + # Test backslash-quoting inside quoting inside -S + ['q4', q[-S'-i A="B \" C" ]."$env'", {OUT=>'A=B " C'}], + ['q5', q[-S"-i A='B \\' C' ]."$env\"", {OUT=>"A=B ' C"}], + # Single-quotes in double-quotes and vice-versa + ['q6', q[-S'-i A="B'"'"'C" ]."$env'", {OUT=>"A=B'C"}], + ['q7', q[-S"-i A='B\\"C' ]."$env\"", {OUT=>'A=B"C'}], + + # Test tab and space (note: tab here is expanded by perl + # and sent to the shell as ASCII 0x9 inside single-quotes). + ['t1', qq[-S'-i\tA="B \tC" $env'], {OUT=>"A=B \tC"}], + # Here '\\t' is not interpolated by perl/shell, passed as two characters + # (backslash, 't') to env, resulting in one argument ("A<tab>B"). + ['t2', qq[-S'printf x%sx\\n A\\tB'], {OUT=>"xA\tBx"}], + # Here '\t' is interpolated by perl, passed as literal tab (ASCII 0x9) + # to env, resulting in two arguments ("A" <whitespace> "B"). + ['t3', qq[-S'printf x%sx\\n A\tB'], {OUT=>"xAx\nxBx"}], + ['t4', qq[-S'printf x%sx\\n A \t B'], {OUT=>"xAx\nxBx"}], + # Ensure \v\f\r\n treated like other whitespace. + # From 8.30 - 8.32 these would introduce arguments to printf, + # and also crash ASAN builds with out of bounds access. + ['t5', qq[-S'printf x%sx\\n A \t B \013\f\r\n'], {OUT=>"xAx\nxBx"}], + + + # Test empty strings + ['m1', qq[-i -S"" A=B $env], {OUT=>"A=B"}], + ['m2', qq[-i -S" \t" A=B $env], {OUT=>"A=B"}], + + # Test escape sequences. + # note: in the following, there is no interpolation by perl due + # to q[], and no interpolation by the shell due to single-quotes. + # env will receive the backslash character followed by t/f/r/n/v. + # Also: Perl does not recognize "\v", so use "\013" for vertical tab. + ['e1', q[-i -S'A="B\tC" ]."$env'", {OUT=>"A=B\tC"}], + ['e2', q[-i -S'A="B\fC" ]."$env'", {OUT=>"A=B\fC"}], + ['e3', q[-i -S'A="B\rC" ]."$env'", {OUT=>"A=B\rC"}], + ['e4', q[-i -S'A="B\nC" ]."$env'", {OUT=>"A=B\nC"}], + ['e5', q[-i -S'A="B\vC" ]."$env'", {OUT=>"A=B\013C"}], + ['e6', q[-i -S'A="B\$C" ]."$env'", {OUT=>'A=B$C'}], + ['e7', q[-i -S'A=B\$C ]."$env'", {OUT=>'A=B$C'}], + ['e8', q[-i -S'A="B\#C" ]."$env'", {OUT=>'A=B#C'}], + ['e9', q[-i -S'A="B\\\\C" ]."$env'", {OUT=>'A=B\\C'}], + ['e10',q[-i -S"A='B\\\\\\\\C' ]."$env\"", {OUT=>'A=B\\C'}], + + # Escape in single-quoted string - passed as-is + # (the multiple pairs of backslashes are to survive two interpolations: + # by perl and then by the shell due to double-quotes). + ['e11',q[-i -S"A='B\\\\tC' ]."$env\"", {OUT=>'A=B\tC'}], + ['e12',q[-i -S"A='B\\\\#C' ]."$env\"", {OUT=>'A=B\#C'}], + ['e13',q[-i -S"A='B\\\\\\$C' ]."$env\"", {OUT=>'A=B\$C'}], + ['e14',q[-i -S"A='B\\\\\\"C' ]."$env\"", {OUT=>'A=B\"C'}], + + # Special escape sequences: + # \_ in double-quotes is a space - result is just one envvar 'A' + ['e20', q[-i -S'A="B\_C=D" ]."$env'", {OUT=>'A=B C=D'}], + # \_ outside double-quotes is arg separator, the command to + # execute should be 'env env' + ['e21', q[-i -S'A=B]."\\_$env\\_$env'", {OUT=>"A=B"}], + + # Test -C inside -S + ['c1', q["-S-C/ pwd"], {OUT=>"/"}], + ['c2', q["-S -C / pwd"], {OUT=>"/"}], + ['c3', q["-S --ch'dir='/ pwd"], {OUT=>"/"}], + + # Test -u inside and outside -S + # u1,u2 - establish a baseline, without -S + ['u1', q[ sh -c 'echo =$FOO='], {ENV=>"FOO=BAR"}, {OUT=>"=BAR="}], + ['u2', q[-uFOO sh -c 'echo =$FOO='], {ENV=>"FOO=BAR"}, {OUT=>"=="}], + # u3,u4: ${FOO} expanded by env itself before executing sh. + # \\$FOO expanded by sh. + # ${FOO} should have value of the original environment + # and \\$FOO should be unset, regardless where -uFOO is used. + # 'u3' behavior differs from FreeBSD's but deemed preferable, in + # https://lists.gnu.org/r/coreutils/2018-04/msg00014.html + ['u3', q[-uFOO -S'sh -c "echo x${FOO}x =\\$FOO="'], + {ENV=>"FOO=BAR"}, {OUT=>"xBARx =="}], + ['u4', q[-S'-uFOO sh -c "echo x${FOO}x =\\$FOO="'], + {ENV=>"FOO=BAR"}, {OUT=>"xBARx =="}], + + # Test ENVVAR expansion + ['v1', q[-i -S'A=${FOO} ]."$env'", {ENV=>"FOO=BAR"}, {OUT=>"A=BAR"}], + ['v2', q[-i -S'A=x${FOO}x ]."$env'", {ENV=>"FOO=BAR"}, {OUT=>"A=xBARx"}], + ['v3', q[-i -S'A=x${FOO}x ]."$env'", {ENV=>"FOO="}, {OUT=>"A=xx"}], + ['v4', q[-i -S'A=x${FOO}x ]."$env'", {OUT=>"A=xx"}], + ['v5', q[-i -S'A="x${FOO}x" ]."$env'", {ENV=>"FOO=BAR"}, {OUT=>"A=xBARx"}], + ['v6', q[-i -S'${FOO}=A ]."$env'", {ENV=>"FOO=BAR"}, {OUT=>"BAR=A"}], + # No expansion inside single-quotes + ['v7', q[-i -S"A='x\${FOO}x' ]."$env\"", {OUT=>'A=x${FOO}x'}], + ['v8', q[-i -S'A="${_FOO}" ]."$env'", {ENV=>"_FOO=BAR"}, {OUT=>"A=BAR"}], + ['v9', q[-i -S'A="${F_OO}" ]."$env'", {ENV=>"F_OO=BAR"}, {OUT=>"A=BAR"}], + ['v10', q[-i -S'A="${FOO1}" ]."$env'", {ENV=>"FOO1=BAR"}, {OUT=>"A=BAR"}], + + # Test end-of-string '#" and '\c' + ['d1', q[-i -S'A=B #C=D' ]."$env", {OUT=>"A=B"}], + ['d2', q[-i -S'#A=B C=D' ]."$env", {OUT=>""}], + ['d3', q[-i -S'A=B#' ]."$env", {OUT=>"A=B#"}], + ['d4', q[-i -S'A=B #' ]."$env", {OUT=>"A=B"}], + + ['d5', q[-i -S'A=B\cC=D' ]."$env", {OUT=>"A=B"}], + ['d6', q[-i -S'\cA=B C=D' ]."$env", {OUT=>""}], + ['d7', q[-i -S'A=B\c' ]."$env", {OUT=>"A=B"}], + ['d8', q[-i -S'A=B \c' ]."$env", {OUT=>"A=B"}], + + ['d10', q[-S'echo FOO #BAR'], {OUT=>"FOO"}], + ['d11', q[-S'echo FOO \\#BAR'], {OUT=>"FOO #BAR"}], + ['d12', q[-S'echo FOO#BAR'], {OUT=>"FOO#BAR"}], + + # Test underscore as space/separator in double/single/no quotes + ['s1', q[-S'printf x%sx\\n "A\\_B"'], {OUT=>"xA Bx"}], + ['s2', q[-S"printf x%sx\\n 'A\\_B'"], {OUT=>"xA\\_Bx"}], + ['s3', q[-S"printf x%sx\\n A\\_B"], {OUT=>"xAx\nxBx"}], + ['s4', q[-S"printf x%sx\\n A B"], {OUT=>"xAx\nxBx"}], + ['s5', q[-S"printf x%sx\\n A B"], {OUT=>"xAx\nxBx"}], + # test underscore/spaces variations - + # ensure they don't generate empty arguments. + ['s6', q[-S"\\_printf x%sx\\n FOO"], {OUT=>"xFOOx"}], + ['s7', q[-S"printf x%sx\\n FOO\\_"], {OUT=>"xFOOx"}], + ['s8', q[-S"\\_printf x%sx\\n FOO\\_"], {OUT=>"xFOOx"}], + ['s9', q[-S"\\_\\_printf x%sx\\n FOO\\_\\_"], {OUT=>"xFOOx"}], + ['s10', q[-S" printf x%sx\\n FOO"], {OUT=>"xFOOx"}], + ['s11', q[-S"printf x%sx\\n FOO "], {OUT=>"xFOOx"}], + ['s12', q[-S" printf x%sx\\n FOO "], {OUT=>"xFOOx"}], + ['s13', q[-S" printf x%sx\\n FOO "], {OUT=>"xFOOx"}], + ['s14', q[-S'printf\\_x%sx\\n\\_FOO'], {OUT=>"xFOOx"}], + ['s15', q[-S"printf x%sx\\n \\_ FOO"], {OUT=>"xFOOx"}], + ['s16', q[-S"printf x%sx\\n\\_ \\_FOO"], {OUT=>"xFOOx"}], + ['s17', q[-S"\\_ \\_ printf x%sx\\n FOO \\_ \\_"], {OUT=>"xFOOx"}], + + # Check for empty quotes + ['eq1', q[-S'printf x%sx\\n A "" B'], {OUT=>"xAx\nxx\nxBx"}], + ['eq2', q[-S'printf x%sx\\n A"" B'], {OUT=>"xAx\nxBx"}], + ['eq3', q[-S'printf x%sx\\n A""B'], {OUT=>"xABx"}], + ['eq4', q[-S'printf x%sx\\n A ""B'], {OUT=>"xAx\nxBx"}], + ['eq5', q[-S'printf x%sx\\n ""'], {OUT=>"xx"}], + ['eq6', q[-S'printf x%sx\\n "" '], {OUT=>"xx"}], + ['eq10', q[-S"printf x%sx\\n A '' B"], {OUT=>"xAx\nxx\nxBx"}], + ['eq11', q[-S"printf x%sx\\n A'' B"], {OUT=>"xAx\nxBx"}], + ['eq12', q[-S"printf x%sx\\n A''B"], {OUT=>"xABx"}], + ['eq13', q[-S"printf x%sx\\n A ''B"], {OUT=>"xAx\nxBx"}], + ['eq14', q[-S'printf x%sx\\n ""'], {OUT=>"xx"}], + ['eq15', q[-S'printf x%sx\\n "" '], {OUT=>"xx"}], + + # extreme example - such as could be found on a #! line. + ['p10', q[-S"\\_ \\_perl\_-w\_-T\_-e\_'print \"hello\n\";'\\_ \\_"], + {OUT=>"hello"}], + + # Test Error Conditions + ['err1', q[-S'"\\c"'], {EXIT=>125}, + {ERR=>"$prog: '\\c' must not appear in double-quoted -S string\n"}], + ['err2', q[-S'A=B\\'], {EXIT=>125}, + {ERR=>"$prog: invalid backslash at end of string in -S\n"}], + ['err3', q[-S'"A=B\\"'], {EXIT=>125}, + {ERR=>"$prog: no terminating quote in -S string\n"}], + ['err4', q[-S"'A=B\\\\'"], {EXIT=>125}, + {ERR=>"$prog: no terminating quote in -S string\n"}], + ['err5', q[-S'A=B\\q'], {EXIT=>125}, + {ERR=>"$prog: invalid sequence '\\q' in -S\n"}], + ['err6', q[-S'A=$B'], {EXIT=>125}, + {ERR=>"$prog: only \${VARNAME} expansion is supported, error at: \$B\n"}], + ['err7', q[-S'A=${B'], {EXIT=>125}, + {ERR=>"$prog: only \${VARNAME} expansion is supported, " . + "error at: \${B\n"}], + ['err8', q[-S'A=${B%B}'], {EXIT=>125}, + {ERR=>"$prog: only \${VARNAME} expansion is supported, " . + "error at: \${B%B}\n"}], + ['err9', q[-S'A=${9B}'], {EXIT=>125}, + {ERR=>"$prog: only \${VARNAME} expansion is supported, " . + "error at: \${9B}\n"}], + + # Test incorrect shebang usage (extraneous whitespace). + ['err_sp2', q['-v -S cat -n'], {EXIT=>125}, + {ERR=>"env: invalid option -- ' '\n" . + "env: use -[v]S to pass options in shebang lines\n" . + "Try 'env --help' for more information.\n"}], + ['err_sp3', q['-v -S cat -n'], {EXIT=>125}, # embedded tab after -v + {ERR=>"env: invalid option -- '\t'\n" . + "env: use -[v]S to pass options in shebang lines\n" . + "Try 'env --help' for more information.\n"}], + + # Also diagnose incorrect shebang usage when failing to exec. + # This typically happens with: + # + # $ cat xxx + # #!env -v -S cat -n + # + # $ ./xxx + # + # in which case: + # argv[0] = env + # argv[1] = '-v -S cat -n' + # argv[2] = './xxx' + ['err_sp5', q['cat -n' ./xxx], {EXIT=>127}, + {ERR=>"env: 'cat -n': No such file or directory\n" . + "env: use -[v]S to pass options in shebang lines\n"}], + + ['err_sp6', q['cat -n' ./xxx arg], {EXIT=>127}, + {ERR=>"env: 'cat -n': No such file or directory\n" . + "env: use -[v]S to pass options in shebang lines\n"}], + ); + +# Append a newline to end of each expected 'OUT' string. +my $t; +foreach $t (@Tests) + { + my $arg1 = $t->[1]; + my $e; + foreach $e (@$t) + { + $e->{OUT} .= "\n" + if ref $e eq 'HASH' and exists $e->{OUT} and length($e->{OUT})>0; + } + } + +# Repeat above tests with "--debug" option (but discard STDERR). +my @new; +foreach my $t (@Tests) +{ + #skip tests that are expected to fail + next if $t->[0] =~ /^err/; + + my @new_t = @$t; + my $test_name = shift @new_t; + my $args = shift @new_t; + push @new, ["$test_name-debug", + "--debug " . $args, + @new_t, + {ERR_SUBST => 's/.*//ms'}]; +} +push @Tests, @new; + +my $save_temps = $ENV{SAVE_TEMPS}; +my $verbose = $ENV{VERBOSE}; + +my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose); +exit $fail; diff --git a/tests/env/env-null.sh b/tests/env/env-null.sh new file mode 100755 index 0000000..fac6675 --- /dev/null +++ b/tests/env/env-null.sh @@ -0,0 +1,58 @@ +#!/bin/sh +# Verify behavior of env -0 and printenv -0. + +# Copyright (C) 2009-2023 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 <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ env printenv + +# POSIX is clear that environ may, but need not be, sorted. +# Environment variable values may contain newlines, which cannot be +# observed by merely inspecting output from env. +# Cygwin requires a minimal environment to launch new processes: execve +# adds missing variables SYSTEMROOT and WINDIR, which show up in a +# subsequent env. Cygwin also requires /bin to always be part of PATH, +# and attempts to unset or reduce PATH may cause execve to fail. +# +# For these reasons, it is better to compare two outputs from distinct +# programs that should be the same, rather than building an exp file. +env -i PATH="$PATH" env -0 > out1 || fail=1 +env -i PATH="$PATH" printenv -0 > out2 || fail=1 +compare out1 out2 || fail=1 +env -i PATH="$PATH" env --null > out2 || fail=1 +compare out1 out2 || fail=1 +env -i PATH="$PATH" printenv --null > out2 || fail=1 +compare out1 out2 || fail=1 + +# env -0 does not work if a command is specified. +returns_ 125 env -0 echo hi > out || fail=1 +compare /dev/null out || fail=1 + +# Test env -0 on a one-variable environment. +printf 'a=b\nc=\0' > exp || framework_failure_ +env -i -0 "$(printf 'a=b\nc=')" > out || fail=1 +compare exp out || fail=1 + +# Test printenv -0 on particular values. +printf 'b\nc=\0' > exp || framework_failure_ +env "$(printf 'a=b\nc=')" printenv -0 a > out || fail=1 +compare exp out || fail=1 +returns_ 1 env -u a printenv -0 a > out || fail=1 +compare /dev/null out || fail=1 +returns_ 1 env -u b "$(printf 'a=b\nc=')" printenv -0 b a > out || fail=1 +compare exp out || fail=1 + +Exit $fail diff --git a/tests/env/env-signal-handler.sh b/tests/env/env-signal-handler.sh new file mode 100755 index 0000000..7fc7fd6 --- /dev/null +++ b/tests/env/env-signal-handler.sh @@ -0,0 +1,126 @@ +#!/bin/sh +# Test env --default-signal=PIPE feature. + +# Copyright (C) 2019-2023 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 <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ env seq test timeout printf +trap_sigpipe_or_skip_ + +# /bin/sh has an intermittent failure in ignoring SIGPIPE on OpenIndiana 11 +# so we require bash as discussed at: +# https://lists.gnu.org/archive/html/coreutils/2020-03/msg00004.html +require_bash_as_SHELL_ + +# Paraphrasing https://bugs.gnu.org/34488#8: +# POSIX requires that sh started with an inherited ignored SIGPIPE must +# silently ignore all attempts from within the shell to restore SIGPIPE +# handling to child processes of the shell: +# +# $ (trap '' PIPE; bash -c 'trap - PIPE; seq inf | head -n1') +# 1 +# seq: write error: Broken pipe +# +# With 'env --default-signal=PIPE', the signal handler can be reset to its +# default. + +# Baseline Test - default signal handler +# -------------------------------------- +# Ensure this results in a "broken pipe" error (the first 'trap' +# sets SIGPIPE to ignore, and the second 'trap' becomes a no-op instead +# of resetting SIGPIPE to its default). Upon a SIGPIPE 'seq' will not be +# terminated, instead its write(2) call will return an error. +(trap '' PIPE; $SHELL -c 'trap - PIPE; seq 999999 2>err1t | head -n1 > out1') + +# The exact broken pipe message depends on the operating system, just ensure +# there was a 'write error' message in stderr: +sed 's/^\(seq: write error:\) .*/\1/' err1t > err1 || framework_failure_ + +printf "1\n" > exp-out || framework_failure_ +printf "seq: write error:\n" > exp-err1 || framework_failure_ + +compare exp-out out1 || framework_failure_ +compare exp-err1 err1 || framework_failure_ + + +# env test - default signal handler +# --------------------------------- +# With env resetting the signal handler to its defaults, there should be no +# error message (because the default SIGPIPE action is to terminate the +# 'seq' program): +(trap '' PIPE; + env --default-signal=PIPE \ + $SHELL -c 'trap - PIPE; seq 999999 2>err2 | head -n1 > out2') + +compare exp-out out2 || fail=1 +compare /dev/null err2 || fail=1 + +# env test - default signal handler (3) +# ------------------------------------- +# Repeat the previous test, using --default-signal with no signal names, +# i.e., all signals. +(trap '' PIPE; + env --default-signal \ + $SHELL -c 'trap - PIPE; seq 999999 2>err4 | head -n1 > out4') + +compare exp-out out4 || fail=1 +compare /dev/null err4 || fail=1 + +# env test - block signal handler +env --block-signal true || fail=1 + +env_ignore_delay_() +{ + local delay="$1" + + # The first 'env' is just to ensure timeout is not a shell built-in. + env timeout --verbose --kill-after=.1 --signal=INT $delay \ + env $env_opt sleep 10 > /dev/null 2>outt + # check only the first two lines from stderr, which are printed by timeout. + # (operating systems might add more messages, like "killed"). + sed -n '1,2p' outt > out || framework_failure_ + compare exp out +} + +# Baseline test - ignore signal handler +# ------------------------------------- +# Terminate 'sleep' with SIGINT +# (SIGINT's default action is to terminate a program). +cat <<\EOF >exp || framework_failure_ +timeout: sending signal INT to command 'env' +EOF +env_opt='' retry_delay_ env_ignore_delay_ .1 6 || fail=1 + +# env test - ignore signal handler +# -------------------------------- +# Use env to ignore SIGINT - "sleep" should continue running +# after timeout sends SIGINT, and be killed using SIGKILL. +cat <<\EOF >exp || framework_failure_ +timeout: sending signal INT to command 'env' +timeout: sending signal KILL to command 'env' +EOF +env_opt='--ignore-signal=INT' retry_delay_ env_ignore_delay_ .1 6 || fail=1 +env_opt='--ignore-signal' retry_delay_ env_ignore_delay_ .1 6 || fail=1 + +# env test --list-signal-handling +env --default-signal --ignore-signal=INT --list-signal-handling true \ + 2> err8t || fail=1 +sed 's/(.*)/()/' err8t > err8 || framework_failure_ +env printf 'INT (): IGNORE\n' > exp-err8 || framework_failure_ +compare exp-err8 err8 || fail=1 + + +Exit $fail diff --git a/tests/env/env.sh b/tests/env/env.sh new file mode 100755 index 0000000..25241af --- /dev/null +++ b/tests/env/env.sh @@ -0,0 +1,166 @@ +#!/bin/sh +# Verify behavior of env. + +# Copyright (C) 2009-2023 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 <https://www.gnu.org/licenses/>. + + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ env pwd nice + +# 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 we can run the shebang which is not the case if +# there are spaces in $abs_top_builddir. +./simple_echo || skip_ "Error running simple_echo script" + +# Verify clearing the environment +a=1 +export a +env - > out || fail=1 +compare /dev/null out || fail=1 +env -i > out || fail=1 +compare /dev/null out || fail=1 +env -u a -i -u a -- > out || fail=1 +compare /dev/null out || fail=1 +env -i -- a=b > out || fail=1 +echo a=b > exp || framework_failure_ +compare exp out || fail=1 + +# These tests verify exact status of internal failure. +returns_ 125 env --- || fail=1 # unknown option +returns_ 125 env -u || fail=1 # missing option argument +returns_ 2 env sh -c 'exit 2' || fail=1 # exit status propagation +returns_ 126 nice . && { returns_ 126 env . || fail=1; } # invalid command +returns_ 127 env no_such || fail=1 # no such command + +# POSIX is clear that environ may, but need not be, sorted. +# Environment variable values may contain newlines, which cannot be +# observed by merely inspecting output from env. +# Cygwin requires a minimal environment to launch new processes: execve +# adds missing variables SYSTEMROOT and WINDIR, which show up in a +# subsequent env. Cygwin also requires /bin to always be part of PATH, +# and attempts to unset or reduce PATH may cause execve to fail. +# +# For these reasons, it is more portable to grep that our desired changes +# took place, rather than comparing output of env over an entire environment. +if env | grep '^ENV_TEST' >/dev/null ; then + skip_ "environment has potential interference from ENV_TEST*" +fi + +ENV_TEST1=a +export ENV_TEST1 +>out || framework_failure_ +env ENV_TEST2= > all || fail=1 +grep '^ENV_TEST' all | LC_ALL=C sort >> out || framework_failure_ +env -u ENV_TEST1 ENV_TEST3=c > all || fail=1 +grep '^ENV_TEST' all | LC_ALL=C sort >> out || framework_failure_ +env ENV_TEST1=b > all || fail=1 +grep '^ENV_TEST' all | LC_ALL=C sort >> out || framework_failure_ +env ENV_TEST2= env > all || fail=1 +grep '^ENV_TEST' all | LC_ALL=C sort >> out || framework_failure_ +env -u ENV_TEST1 ENV_TEST3=c env > all || fail=1 +grep '^ENV_TEST' all | LC_ALL=C sort >> out || framework_failure_ +env ENV_TEST1=b env > all || fail=1 +grep '^ENV_TEST' all | LC_ALL=C sort >> out || framework_failure_ +cat <<EOF >exp || framework_failure_ +ENV_TEST1=a +ENV_TEST2= +ENV_TEST3=c +ENV_TEST1=b +ENV_TEST1=a +ENV_TEST2= +ENV_TEST3=c +ENV_TEST1=b +EOF +compare exp out || fail=1 + +# PATH modifications affect exec. +mkdir unlikely_name || framework_failure_ +cat <<EOF > unlikely_name/also_unlikely || framework_failure_ +#!/bin/sh +echo pass +EOF +chmod +x unlikely_name/also_unlikely || framework_failure_ +returns_ 127 env also_unlikely || fail=1 +test x$(PATH=$PATH:unlikely_name env also_unlikely) = xpass || fail=1 +test x$(env PATH="$PATH":unlikely_name also_unlikely) = xpass || fail=1 + +# Explicitly put . on the PATH for the rest of this test. +PATH=$PATH: +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 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 "simple_echo" ./-u || framework_failure_ +case $(env -u echo echo good) in + good) ;; + *) fail=1 ;; +esac +case $(env -u echo -- echo good) in + good) ;; + *) fail=1 ;; +esac +case $(env -- -u pass) in + *pass) ;; + *) fail=1 ;; +esac + +# After options have ended, the first argument not containing = is a program. +returns_ 127 env a=b -- true || fail=1 +ln -s "simple_echo" ./-- || framework_failure_ +case $(env a=b -- true || echo fail) in + *true) ;; + *) fail=1 ;; +esac + +# No way to directly invoke program name containing =. +cat <<EOF >./c=d || framework_failure_ +#!/bin/sh +echo pass +EOF +chmod +x c=d || framework_failure_ +test "x$(env c=d echo fail)" = xfail || fail=1 +test "x$(env -- c=d echo fail)" = xfail || fail=1 +test "x$(env ./c=d echo fail)" = xfail || fail=1 +test "x$(env sh -c 'exec "$@"' sh c=d echo fail)" = xpass || fail=1 +test "x$(sh -c '\c=d echo fail')" = xpass && #dash 0.5.4 fails so check first + { test "x$(env sh -c '\c=d echo fail')" = xpass || fail=1; } + +# catch unsetenv failure, broken through coreutils 8.0 +returns_ 125 env -u a=b true || fail=1 +returns_ 125 env -u '' true || fail=1 + +# Verify changing directory. +mkdir empty || framework_failure_ +returns_ 125 env --chdir=empty/nonexistent true || fail=1 +returns_ 125 env -C empty 2>out || fail=1 +printf '%s\n' \ + 'env: must specify command with --chdir (-C)' \ + "Try 'env --help' for more information." > exp || + framework_failure_ +compare exp out || fail=1 +exp=$(cd empty && env pwd) || framework_failure_ +got=$(env --chdir=empty pwd) || fail=1 +test "$exp" = "$got" || fail=1 + +Exit $fail |