2 # Test 'env -S' feature
4 # Copyright (C) 2018-2019 Free Software Foundation, Inc.
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <https://www.gnu.org/licenses/>.
21 (my $program_name = $0) =~ s
|.*/||;
24 # Turn off localization of executable's output.
25 @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x
3;
29 # Test combination of -S and regular arguments
30 ['1', q
[-i A
=B FOO
=AR sh
-c
'echo $A$FOO'], {OUT
=>"BAR"}],
31 ['2', q
[-i
-S
'A=B FOO=AR sh -c "echo \\$A\\$FOO"'], {OUT
=>"BAR"}],
32 ['3', q
[-i
-S
'A=B FOO=AR' sh
-c
'echo $A$FOO'], {OUT
=>"BAR"}],
33 ['4', q
[-i
-S
'A=B' FOO
=AR sh
-c
'echo $A$FOO'], {OUT
=>"BAR"}],
34 ['5', q
[-S
'-i A=B FOO=AR sh -c "echo \\$A\\$FOO"'], {OUT
=>"BAR"}],
36 # Test quoting inside -S
37 ['q1', q
[-S
'-i A="B C" env'], {OUT
=>"A=B C"}],
38 ['q2', q
[-S
"-i A='B C' env"], {OUT
=>"A=B C"}],
39 ['q3', q
[-S
"-i A=\"B C\" env"], {OUT
=>"A=B C"}],
40 # Test backslash-quoting inside quoting inside -S
41 ['q4', q
[-S
'-i A="B \" C" env'], {OUT
=>'A=B " C'}],
42 ['q5', q
[-S
"-i A='B \\' C' env"], {OUT
=>"A=B ' C"}],
43 # Single-quotes in double-quotes and vice-versa
44 ['q6', q
[-S
'-i A="B'"'"'C" env'], {OUT
=>"A=B'C"}],
45 ['q7', q
[-S
"-i A='B\\"C
' env"], {OUT=>'A
=B
"C'}],
47 # Test tab and space (note: tab here is expanded by perl
48 # and sent to the shell as ASCII 0x9 inside single-quotes).
49 ['t1', qq[-S'-i\tA="B
\tC
" env'], {OUT=>"A
=B
\tC
"}],
50 # Here '\\t' is not interpolated by perl/shell, passed as two characters
51 # (backslash, 't') to env, resulting in one argument ("A
<tab
>B
").
52 ['t2', qq[-S'printf x%sx\\n A\\tB'], {OUT=>"xA
\tBx
"}],
53 # Here '\t' is interpolated by perl, passed as literal tab (ASCII 0x9)
54 # to env, resulting in two arguments ("A
" <whitespace> "B
").
55 ['t3', qq[-S'printf x%sx\\n A\tB'], {OUT=>"xAx
\nxBx
"}],
56 ['t4', qq[-S'printf x%sx\\n A \t B'], {OUT=>"xAx
\nxBx
"}],
60 ['m1', qq[-i -S"" A=B env], {OUT=>"A
=B
"}],
61 ['m2', qq[-i -S" \t" A=B env], {OUT=>"A
=B
"}],
63 # Test escape sequences.
64 # note: in the following, there is no interpolation by perl due
65 # to q[], and no interpolation by the shell due to single-quotes.
66 # env will receive the backslash character followed by t/f/r/n/v.
67 # Also: Perl does not recognize "\v", so use "\013" for vertical tab.
68 ['e1', q[-i -S'A="B
\tC
" env'], {OUT=>"A
=B
\tC
"}],
69 ['e2', q[-i -S'A="B
\fC
" env'], {OUT=>"A
=B
\fC
"}],
70 ['e3', q[-i -S'A="B
\rC
" env'], {OUT=>"A
=B
\rC
"}],
71 ['e4', q[-i -S'A="B
\nC
" env'], {OUT=>"A
=B
\nC
"}],
72 ['e5', q[-i -S'A="B
\vC
" env'], {OUT=>"A
=B
\013C
"}],
73 ['e6', q[-i -S'A="B\
$C" env'], {OUT=>'A=B$C'}],
74 ['e7', q[-i -S'A=B\$C env'], {OUT=>'A=B$C'}],
75 ['e8', q[-i -S'A="B\#C
" env'], {OUT=>'A=B#C'}],
76 ['e9', q[-i -S'A="B
\\\\C
" env'], {OUT=>'A=B\\C'}],
77 ['e10',q[-i -S"A
='B\\\\\\\\C' env
"], {OUT=>'A=B\\C'}],
79 # Escape in single-quoted string - passed as-is
80 # (the multiple pairs of backslashes are to survive two interpolations:
81 # by perl and then by the shell due to double-quotes).
82 ['e11',q[-i -S"A
='B\\\\tC' env
"], {OUT=>'A=B\tC'}],
83 ['e12',q[-i -S"A
='B\\\\#C' env
"], {OUT=>'A=B\#C'}],
84 ['e13',q[-i -S"A
='B\\\\\\$C' env
"], {OUT=>'A=B\$C'}],
85 ['e14',q[-i -S"A
='B\\\\\\"C' env
"], {OUT=>'A=B\"C'}],
87 # Special escape sequences:
88 # \_ in duoble-quotes is a space - result is just one envvar 'A'
89 ['e20', q[-i -S'A="B\_C
=D
" env'], {OUT=>'A=B C=D'}],
90 # \_ outside double-quotes is arg separator, the command to
91 # execute should be 'env env'
92 ['e21', q[-i -S'A=B\_env\_env'], {OUT=>"A
=B
"}],
95 ['c1', q["-S
-C
/ pwd"], {OUT=>"/"}],
96 ['c2', q["-S
-C
/ pwd"], {OUT=>"/"}],
97 ['c3', q["-S
--ch
'dir='/ pwd"], {OUT=>"/"}],
99 # Test -u inside and outside -S
100 # u1,u2 - establish a baseline, without -S
101 ['u1', q[ sh -c 'echo =$FOO='], {ENV=>"FOO
=BAR
"}, {OUT=>"=BAR
="}],
102 ['u2', q[-uFOO sh -c 'echo =$FOO='], {ENV=>"FOO
=BAR
"}, {OUT=>"=="}],
103 # u3,u4: ${FOO} expanded by env itself before executing sh.
104 # \\$FOO expanded by sh.
105 # ${FOO} should have value of the original environment
106 # and \\$FOO should be unset, regardlss where -uFOO is used.
107 # 'u3' behavior differs from FreeBSD's but deemed preferable, in
108 # https://lists.gnu.org/r/coreutils/2018-04/msg00014.html
109 ['u3', q[-uFOO -S'sh -c "echo x
${FOO
}x
=\\$FOO="'],
110 {ENV=>"FOO
=BAR
"}, {OUT=>"xBARx
=="}],
111 ['u4', q[-S'-uFOO sh -c "echo x
${FOO
}x
=\\$FOO="'],
112 {ENV=>"FOO
=BAR
"}, {OUT=>"xBARx
=="}],
114 # Test ENVVAR expansion
115 ['v1', q[-i -S'A=${FOO} env'], {ENV=>"FOO
=BAR
"}, {OUT=>"A
=BAR
"}],
116 ['v2', q[-i -S'A=x${FOO}x env'], {ENV=>"FOO
=BAR
"}, {OUT=>"A
=xBARx
"}],
117 ['v3', q[-i -S'A=x${FOO}x env'], {ENV=>"FOO
="}, {OUT=>"A
=xx
"}],
118 ['v4', q[-i -S'A=x${FOO}x env'], {OUT=>"A
=xx
"}],
119 ['v5', q[-i -S'A="x
${FOO
}x
" env'], {ENV=>"FOO
=BAR
"}, {OUT=>"A
=xBARx
"}],
120 ['v6', q[-i -S'${FOO}=A env'], {ENV=>"FOO
=BAR
"}, {OUT=>"BAR
=A
"}],
121 # No expansion inside single-quotes
122 ['v7', q[-i -S"A
='x\${FOO}x' env
"], {OUT=>'A=x${FOO}x'}],
123 ['v8', q[-i -S'A="${_FOO
}" env'], {ENV=>"_FOO
=BAR
"}, {OUT=>"A
=BAR
"}],
124 ['v9', q[-i -S'A="${F_OO
}" env'], {ENV=>"F_OO
=BAR
"}, {OUT=>"A
=BAR
"}],
125 ['v10', q[-i -S'A="${FOO1
}" env'], {ENV=>"FOO1
=BAR
"}, {OUT=>"A
=BAR
"}],
127 # Test end-of-string '#" and '\c'
128 ['d1', q
[-i
-S
'A=B #C=D' env
], {OUT
=>"A=B"}],
129 ['d2', q
[-i
-S
'#A=B C=D' env
], {OUT
=>""}],
130 ['d3', q
[-i
-S
'A=B#' env
], {OUT
=>"A=B#"}],
131 ['d4', q
[-i
-S
'A=B #' env
], {OUT
=>"A=B"}],
133 ['d5', q
[-i
-S
'A=B\cC=D' env
], {OUT
=>"A=B"}],
134 ['d6', q
[-i
-S
'\cA=B C=D' env
], {OUT
=>""}],
135 ['d7', q
[-i
-S
'A=B\c' env
], {OUT
=>"A=B"}],
136 ['d8', q
[-i
-S
'A=B \c' env
], {OUT
=>"A=B"}],
138 ['d10', q
[-S
'echo FOO #BAR'], {OUT
=>"FOO"}],
139 ['d11', q
[-S
'echo FOO \\#BAR'], {OUT
=>"FOO #BAR"}],
140 ['d12', q
[-S
'echo FOO#BAR'], {OUT
=>"FOO#BAR"}],
142 # Test underscore as space/separator in double/single/no quotes
143 ['s1', q
[-S
'printf x%sx\\n "A\\_B"'], {OUT
=>"xA Bx"}],
144 ['s2', q
[-S
"printf x%sx\\n 'A\\_B'"], {OUT
=>"xA\\_Bx"}],
145 ['s3', q
[-S
"printf x%sx\\n A\\_B"], {OUT
=>"xAx\nxBx"}],
146 ['s4', q
[-S
"printf x%sx\\n A B"], {OUT
=>"xAx\nxBx"}],
147 ['s5', q
[-S
"printf x%sx\\n A B"], {OUT
=>"xAx\nxBx"}],
148 # test underscore/spaces variations -
149 # ensure they don't generate empty arguments.
150 ['s6', q
[-S
"\\_printf x%sx\\n FOO"], {OUT
=>"xFOOx"}],
151 ['s7', q
[-S
"printf x%sx\\n FOO\\_"], {OUT
=>"xFOOx"}],
152 ['s8', q
[-S
"\\_printf x%sx\\n FOO\\_"], {OUT
=>"xFOOx"}],
153 ['s9', q
[-S
"\\_\\_printf x%sx\\n FOO\\_\\_"], {OUT
=>"xFOOx"}],
154 ['s10', q
[-S
" printf x%sx\\n FOO"], {OUT
=>"xFOOx"}],
155 ['s11', q
[-S
"printf x%sx\\n FOO "], {OUT
=>"xFOOx"}],
156 ['s12', q
[-S
" printf x%sx\\n FOO "], {OUT
=>"xFOOx"}],
157 ['s13', q
[-S
" printf x%sx\\n FOO "], {OUT
=>"xFOOx"}],
158 ['s14', q
[-S
'printf\\_x%sx\\n\\_FOO'], {OUT
=>"xFOOx"}],
159 ['s15', q
[-S
"printf x%sx\\n \\_ FOO"], {OUT
=>"xFOOx"}],
160 ['s16', q
[-S
"printf x%sx\\n\\_ \\_FOO"], {OUT
=>"xFOOx"}],
161 ['s17', q
[-S
"\\_ \\_ printf x%sx\\n FOO \\_ \\_"], {OUT
=>"xFOOx"}],
163 # Check for empty quotes
164 ['eq1', q
[-S
'printf x%sx\\n A "" B'], {OUT
=>"xAx\nxx\nxBx"}],
165 ['eq2', q
[-S
'printf x%sx\\n A"" B'], {OUT
=>"xAx\nxBx"}],
166 ['eq3', q
[-S
'printf x%sx\\n A""B'], {OUT
=>"xABx"}],
167 ['eq4', q
[-S
'printf x%sx\\n A ""B'], {OUT
=>"xAx\nxBx"}],
168 ['eq5', q
[-S
'printf x%sx\\n ""'], {OUT
=>"xx"}],
169 ['eq6', q
[-S
'printf x%sx\\n "" '], {OUT
=>"xx"}],
170 ['eq10', q
[-S
"printf x%sx\\n A '' B"], {OUT
=>"xAx\nxx\nxBx"}],
171 ['eq11', q
[-S
"printf x%sx\\n A'' B"], {OUT
=>"xAx\nxBx"}],
172 ['eq12', q
[-S
"printf x%sx\\n A''B"], {OUT
=>"xABx"}],
173 ['eq13', q
[-S
"printf x%sx\\n A ''B"], {OUT
=>"xAx\nxBx"}],
174 ['eq14', q
[-S
'printf x%sx\\n ""'], {OUT
=>"xx"}],
175 ['eq15', q
[-S
'printf x%sx\\n "" '], {OUT
=>"xx"}],
177 # extreme example - such as could be found on a #! line.
178 ['p10', q
[-S
"\\_ \\_perl\_-w\_-T\_-e\_'print \"hello\n\";'\\_ \\_"],
181 # Test Error Conditions
182 ['err1', q
[-S
'"\\c"'], {EXIT
=>125},
183 {ERR
=>"$prog: '\\c' must not appear in double-quoted -S string\n"}],
184 ['err2', q
[-S
'A=B\\'], {EXIT
=>125},
185 {ERR
=>"$prog: invalid backslash at end of string in -S\n"}],
186 ['err3', q
[-S
'"A=B\\"'], {EXIT
=>125},
187 {ERR
=>"$prog: no terminating quote in -S string\n"}],
188 ['err4', q
[-S
"'A=B\\\\'"], {EXIT
=>125},
189 {ERR
=>"$prog: no terminating quote in -S string\n"}],
190 ['err5', q
[-S
'A=B\\q'], {EXIT
=>125},
191 {ERR
=>"$prog: invalid sequence '\\q' in -S\n"}],
192 ['err6', q
[-S
'A=$B'], {EXIT
=>125},
193 {ERR
=>"$prog: only \${VARNAME} expansion is supported, error at: \$B\n"}],
194 ['err7', q
[-S
'A=${B'], {EXIT
=>125},
195 {ERR
=>"$prog: only \${VARNAME} expansion is supported, " .
196 "error at: \${B\n"}],
197 ['err8', q
[-S
'A=${B%B}'], {EXIT
=>125},
198 {ERR
=>"$prog: only \${VARNAME} expansion is supported, " .
199 "error at: \${B%B}\n"}],
200 ['err9', q
[-S
'A=${9B}'], {EXIT
=>125},
201 {ERR
=>"$prog: only \${VARNAME} expansion is supported, " .
202 "error at: \${9B}\n"}],
204 # Test incorrect shebang usage (extraneous whitespace).
205 ['err_sp2', q
['-v -S cat -n'], {EXIT
=>125},
206 {ERR
=>"env: invalid option -- ' '\n" .
207 "env: use -[v]S to pass options in shebang lines\n" .
208 "Try 'env --help' for more information.\n"}],
209 ['err_sp3', q
['-v -S cat -n'], {EXIT
=>125}, # embedded tab after -v
210 {ERR
=>"env: invalid option -- '\t'\n" .
211 "env: use -[v]S to pass options in shebang lines\n" .
212 "Try 'env --help' for more information.\n"}],
214 # Also diagnose incorrect shebang usage when failing to exec.
215 # This typically happens with:
224 # argv[1] = '-v -S cat -n'
226 ['err_sp5', q
['cat -n' ./xxx
], {EXIT
=>127},
227 {ERR
=>"env: 'cat -n': No such file or directory\n" .
228 "env: use -[v]S to pass options in shebang lines\n"}],
230 ['err_sp6', q
['cat -n' ./xxx arg
], {EXIT
=>127},
231 {ERR
=>"env: 'cat -n': No such file or directory\n" .
232 "env: use -[v]S to pass options in shebang lines\n"}],
235 # Append a newline to end of each expected 'OUT' string.
244 if ref $e eq 'HASH' and exists $e->{OUT
} and length($e->{OUT
})>0;
248 # Repeat above tests with "--debug" option (but discard STDERR).
250 foreach my $t (@Tests)
252 #skip tests that are expected to fail
253 next if $t->[0] =~ /^err/;
256 my $test_name = shift @new_t;
257 my $args = shift @new_t;
258 push @new, ["$test_name-debug",
261 {ERR_SUBST
=> 's/.*//ms'}];
265 my $save_temps = $ENV{SAVE_TEMPS
};
266 my $verbose = $ENV{VERBOSE
};
268 my $fail = run_tests
($program_name, $prog, \
@Tests, $save_temps, $verbose);