xref: /titanic_44/usr/src/lib/libshell/common/tests/basic.sh (revision 63ea9ad24896f2939472f8f96f568086d190eb33)
1########################################################################
2#                                                                      #
3#               This software is part of the ast package               #
4#          Copyright (c) 1982-2008 AT&T Intellectual Property          #
5#                      and is licensed under the                       #
6#                  Common Public License, Version 1.0                  #
7#                    by AT&T Intellectual Property                     #
8#                                                                      #
9#                A copy of the License is available at                 #
10#            http://www.opensource.org/licenses/cpl1.0.txt             #
11#         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         #
12#                                                                      #
13#              Information and Software Systems Research               #
14#                            AT&T Research                             #
15#                           Florham Park NJ                            #
16#                                                                      #
17#                  David Korn <dgk@research.att.com>                   #
18#                                                                      #
19########################################################################
20function err_exit
21{
22	print -u2 -n "\t"
23	print -u2 -r ${Command}[$1]: "${@:2}"
24	let Errors+=1
25}
26alias err_exit='err_exit $LINENO'
27
28# test basic file operations like redirection, pipes, file expansion
29Command=${0##*/}
30integer Errors=0
31set -- \
32	go+r	0000	\
33	go-r	0044	\
34	ug=r	0330	\
35	go+w	0000	\
36	go-w	0022	\
37	ug=w	0550	\
38	go+x	0000	\
39	go-x	0011	\
40	ug=x	0660	\
41	go-rx	0055	\
42	uo-wx	0303	\
43	ug-rw	0660	\
44	o=	0007
45while	(( $# >= 2 ))
46do	umask 0
47	umask $1
48	g=$(umask)
49	[[ $g == $2 ]] || err_exit "umask 0; umask $1 failed -- expected $2, got $g"
50	shift 2
51done
52umask u=rwx,go=rx || err_exit "umask u=rws,go=rx failed"
53if	[[ $(umask -S) != u=rwx,g=rx,o=rx ]]
54then	err_exit 'umask -S incorrect'
55fi
56mkdir  /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed"
57trap "cd /; rm -rf /tmp/ksh$$" EXIT
58pwd=$PWD
59[[ $SHELL != /* ]] && SHELL=$pwd/$SHELL
60cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed"
61um=$(umask -S)
62( umask 0777; > foobar )
63rm -f foobar
64> foobar
65[[ -r foobar ]] || err_exit 'umask not being restored after subshell'
66umask "$um"
67rm -f foobar
68# optimizer bug test
69> foobar
70for i in 1 2
71do      print foobar*
72        rm -f foobar
73done > out$$
74if      [[ "$(<out$$)"  != "foobar"$'\n'"foobar*" ]]
75then    print -u2 "optimizer bug with file expansion"
76fi
77rm -f out$$ foobar
78mkdir dir
79if	[[ $(print */) != dir/ ]]
80then	err_exit 'file expansion with trailing / not working'
81fi
82if	[[ $(print *) != dir ]]
83then	err_exit 'file expansion with single file not working'
84fi
85print hi > .foo
86if	[[ $(print *) != dir ]]
87then	err_exit 'file expansion leading . not working'
88fi
89date > dat1 || err_exit "date > dat1 failed"
90test -r dat1 || err_exit "dat1 is not readable"
91x=dat1
92cat <$x > dat2 || err_exit "cat < $x > dat2 failed"
93cat dat1 dat2 | cat  | cat | cat > dat3 || err_exit "cat pipe failed"
94cat > dat4 <<!
95$(date)
96!
97cat dat1 dat2 | cat  | cat | cat > dat5 &
98wait $!
99set -- dat*
100if	(( $# != 5 ))
101then	err_exit "dat* matches only $# files"
102fi
103if	(command > foo\\abc) 2> /dev/null
104then	set -- foo*
105	if	[[ $1 != 'foo\abc' ]]
106	then	err_exit 'foo* does not match foo\abc'
107	fi
108fi
109if ( : > TT* && : > TTfoo ) 2>/dev/null
110then	set -- TT*
111	if	(( $# < 2 ))
112	then	err_exit 'TT* not expanding when file TT* exists'
113	fi
114fi
115cd ~- || err_exit "cd back failed"
116cat > /tmp/ksh$$/script <<- !
117	#! $SHELL
118	print -r -- \$0
119!
120chmod 755 /tmp/ksh$$/script
121if	[[ $(/tmp/ksh$$/script) != "/tmp/ksh$$/script" ]]
122then	err_exit '$0 not correct for #! script'
123fi
124rm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed"
125bar=foo
126eval foo=\$bar
127if	[[ $foo != foo ]]
128then	err_exit 'eval foo=\$bar not working'
129fi
130bar='foo=foo\ bar'
131eval $bar
132if	[[ $foo != 'foo bar' ]]
133then	err_exit 'eval foo=\$bar, with bar="foo\ bar" not working'
134fi
135cd /tmp
136cd ../../tmp || err_exit "cd ../../tmp failed"
137if	[[ $PWD != /tmp ]]
138then	err_exit 'cd ../../tmp is not /tmp'
139fi
140( sleep 2; cat <<!
141foobar
142!
143) | cat > /tmp/foobar$$ &
144wait $!
145foobar=$( < /tmp/foobar$$)
146if	[[ $foobar != foobar ]]
147then	err_exit "$foobar is not foobar"
148fi
149{
150	print foo
151	/bin/echo bar
152	print bam
153} > /tmp/foobar$$
154if	[[ $( < /tmp/foobar$$) != $'foo\nbar\nbam' ]]
155then	err_exit "Output file pointer not shared correctly."
156fi
157cat > /tmp/foobar$$ <<\!
158	print foo
159	/bin/echo bar
160	print bam
161!
162chmod +x /tmp/foobar$$
163if	[[ $(/tmp/foobar$$) != $'foo\nbar\nbam' ]]
164then	err_exit "Script not working."
165fi
166if	[[ $(/tmp/foobar$$ | /bin/cat) != $'foo\nbar\nbam' ]]
167then	err_exit "Script | cat not working."
168fi
169if	[[ $( /tmp/foobar$$) != $'foo\nbar\nbam' ]]
170then	err_exit "Output file pointer not shared correctly."
171fi
172rm -f /tmp/foobar$$
173x=$( (print foo) ; (print bar) )
174if	[[ $x != $'foo\nbar' ]]
175then	err_exit " ( (print foo);(print bar ) failed"
176fi
177x=$( (/bin/echo foo) ; (print bar) )
178if	[[ $x != $'foo\nbar' ]]
179then	err_exit " ( (/bin/echo);(print bar ) failed"
180fi
181x=$( (/bin/echo foo) ; (/bin/echo bar) )
182if	[[ $x != $'foo\nbar' ]]
183then	err_exit " ( (/bin/echo);(/bin/echo bar ) failed"
184fi
185cat > /tmp/ksh$$ <<\!
186if	[[ -p /dev/fd/0 ]]
187then	builtin cat
188	cat - > /dev/null
189	[[ -p /dev/fd/0 ]] && print ok
190else	print no
191fi
192!
193chmod +x /tmp/ksh$$
194case $( (print) | /tmp/ksh$$;:) in
195ok)	;;
196no)	err_exit "[[ -p /dev/fd/0 ]] fails for standard input pipe" ;;
197*)	err_exit "builtin replaces standard input pipe" ;;
198esac
199print 'print $0' > /tmp/ksh$$
200print ". /tmp/ksh$$" > /tmp/ksh$$x
201chmod +x /tmp/ksh$$x
202if	[[ $(/tmp/ksh$$x) != /tmp/ksh$$x ]]
203then	err_exit '$0 not correct for . script'
204fi
205rm -r /tmp/ksh$$ /tmp/ksh$$x
206mkdir  /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed"
207cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed"
208print ./b > ./a; print ./c > b; print ./d > c; print ./e > d; print "echo \"hello there\"" > e
209chmod 755 a b c d e
210x=$(./a)
211if	[[ $x != "hello there" ]]
212then	err_exit "nested scripts failed"
213fi
214x=$( (./a) | cat)
215if	[[ $x != "hello there" ]]
216then	err_exit "scripts in subshells fail"
217fi
218cd ~- || err_exit "cd back failed"
219rm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed"
220x=$( (/bin/echo foo) 2> /dev/null )
221if	[[ $x != foo ]]
222then	err_exit "subshell in command substitution fails"
223fi
224exec 1>&-
225x=$(print hello)
226if	[[ $x != hello ]]
227then	err_exit "command subsitution with stdout closed failed"
228fi
229cd $pwd
230x=$(cat <<\! | $SHELL
231/bin/echo | /bin/cat
232/bin/echo hello
233!
234)
235if	[[ $x != $'\n'hello ]]
236then	err_exit "$SHELL not working when standard input is a pipe"
237fi
238x=$( (/bin/echo hello) 2> /dev/null )
239if	[[ $x != hello ]]
240then	err_exit "subshell in command substitution with 1 closed fails"
241fi
242cat > /tmp/ksh$$ <<- \!
243read line 2> /dev/null
244print done
245!
246if	[[ $($SHELL /tmp/ksh$$ <&-) != done ]]
247then	err_exit "executing script with 0 closed fails"
248fi
249trap '' INT
250cat > /tmp/ksh$$ <<- \!
251trap 'print bad' INT
252kill -s INT $$
253print good
254!
255chmod +x /tmp/ksh$$
256if	[[ $($SHELL  /tmp/ksh$$) != good ]]
257then	err_exit "traps ignored by parent not ignored"
258fi
259trap - INT
260cat > /tmp/ksh$$ <<- \!
261read line
262/bin/cat
263!
264if	[[ $($SHELL /tmp/ksh$$ <<!
265one
266two
267!
268)	!= two ]]
269then	err_exit "standard input not positioned correctly"
270fi
271word=$(print $'foo\nbar' | { read line; /bin/cat;})
272if	[[ $word != bar ]]
273then	err_exit "pipe to { read line; /bin/cat;} not working"
274fi
275word=$(print $'foo\nbar' | ( read line; /bin/cat) )
276if	[[ $word != bar ]]
277then	err_exit "pipe to ( read line; /bin/cat) not working"
278fi
279if	[[ $(print x{a,b}y) != 'xay xby' ]]
280then	err_exit 'brace expansion not working'
281fi
282if	[[ $(for i in foo bar
283	  do ( tgz=$(print $i)
284	  print $tgz)
285	  done) != $'foo\nbar' ]]
286then	err_exit 'for loop subshell optimizer bug'
287fi
288unset a1
289optbug()
290{
291	set -A a1  foo bar bam
292	integer i
293	for ((i=0; i < 3; i++))
294	do
295		(( ${#a1[@]} < 2 )) && return 0
296		set -- "${a1[@]}"
297		shift
298		set -A a1 -- "$@"
299	done
300	return 1
301}
302optbug ||  err_exit 'array size optimzation bug'
303wait # not running --pipefail which would interfere with subsequent tests
304: $(jobs -p) # required to clear jobs for next jobs -p (interactive side effect)
305sleep 20 &
306pids=$!
307if	[[ $(jobs -p) != $! ]]
308then	err_exit 'jobs -p not reporting a background job'
309fi
310sleep 20 &
311pids="$pids $!"
312foo()
313{
314	set -- $(jobs -p)
315	(( $# == 2 )) || err_exit "$# jobs not reported -- 2 expected"
316}
317foo
318kill $pids
319
320[[ $( (trap 'print alarm' ALRM; sleep 4) & sleep 2; kill -ALRM $!; sleep 2; wait) == alarm ]] || err_exit 'ALRM signal not working'
321[[ $($SHELL -c 'trap "" HUP; $SHELL -c "(sleep 2;kill -HUP $$)& sleep 4;print done"') != done ]] && err_exit 'ignored traps not being ignored'
322[[ $($SHELL -c 'o=foobar; for x in foo bar; do (o=save);print $o;done' 2> /dev/null ) == $'foobar\nfoobar' ]] || err_exit 'for loop optimization subshell bug'
323command exec 3<> /dev/null
324if	cat /dev/fd/3 >/dev/null 2>&1
325then	[[ $($SHELL -c 'cat <(print foo)' 2> /dev/null) == foo ]] || err_exit 'process substitution not working'
326	[[ $($SHELL -c 'print $(cat <(print foo) )' 2> /dev/null) == foo ]] || err_exit 'process substitution in subshell not working'
327	[[ $($SHELL -c  $'tee >(grep \'1$\' > /tmp/ksh'$$'x) > /dev/null <<-  \!!!
328	line0
329	line1
330	line2
331	!!!
332	wait
333	cat /tmp/ksh'$$x 2> /dev/null)  == line1 ]] || err_exit '>() process substitution fails'
334	> /tmp/ksh$$x
335	[[ $($SHELL -c  $'
336	for i in 1
337	do	tee >(grep \'1$\' > /tmp/ksh'$$'x) > /dev/null  <<-  \!!!
338		line0
339		line1
340		line2
341		!!!
342	done
343	wait
344	cat /tmp/ksh'$$x 2>> /dev/null) == line1 ]] || err_exit '>() process substitution fails in for loop'
345	[[ $({ $SHELL -c 'cat <(for i in x y z; do print $i; done)';} 2> /dev/null) == $'x\ny\nz' ]] ||
346		err_exit 'process substitution of compound commands not working'
347fi
348[[ $($SHELL -r 'command -p :' 2>&1) == *restricted* ]]  || err_exit 'command -p not restricted'
349print cat >  /tmp/ksh$$x
350chmod +x /tmp/ksh$$x
351[[ $($SHELL -c "print foo | /tmp/ksh$$x ;:" 2> /dev/null ) == foo ]] || err_exit 'piping into script fails'
352[[ $($SHELL -c 'X=1;print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 1 ]] || err_exit 'x=1;${x:=$(..."...")} failure'
353[[ $($SHELL -c 'print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 0 ]] || err_exit '${x:=$(..."...")} failure'
354exec 3<&-
355if	[[ -d /dev/fd  && -w /dev/fd/3 ]]
356then	[[ $(cat <(print hello) ) == hello ]] || err_exit "process substitution not working outside for or while loop"
357	$SHELL -c '[[ $(for i in 1;do cat <(print hello);done ) == hello ]]' 2> /dev/null|| err_exit "process substitution not working in for or while loop"
358fi
359exec 3> /dev/null
360print 'print foo "$@"' > /tmp/ksh$$x
361[[ $( print "(/tmp/ksh$$x bar)" | $SHELL 2>/dev/null) == 'foo bar' ]] || err_exit 'script pipe to shell fails'
362print "#! $SHELL" > /tmp/ksh$$x
363print 'print  -- $0' >> /tmp/ksh$$x
364chmod +x /tmp/ksh$$x
365[[ $(/tmp/ksh$$x) == /tmp/ksh$$x ]] || err_exit  "\$0 is $0 instead of /tmp/ksh$$x"
366cat > /tmp/ksh$$x <<- \EOF
367	myfilter() { x=$(print ok | cat); print  -r -- $SECONDS;}
368	set -o pipefail
369	sleep 3 | myfilter
370EOF
371(( $($SHELL /tmp/ksh$$x) > 2.0 )) && err_exit 'command substitution causes pipefail option to hang'
372rm -f /tmp/ksh$$x
373exec 3<&-
374( typeset -r foo=bar) 2> /dev/null || err_exit 'readonly variables set in a subshell cannot unset'
375$SHELL -c 'x=${ print hello;}; [[ $x == hello ]]' 2> /dev/null || err_exit '${ command;} not supported'
376$SHELL 2> /dev/null <<- \EOF || err_exit 'multiline ${...} command substitution not supported'
377	x=${
378		print hello
379	}
380	[[ $x == hello ]]
381EOF
382$SHELL 2> /dev/null <<- \EOF || err_exit '${...} command substitution with side effects not supported '
383	y=bye
384	x=${
385		y=hello
386		print hello
387	}
388	[[ $y == $x ]]
389EOF
390$SHELL   2> /dev/null <<- \EOF || err_exit 'nested ${...} command substitution not supported'
391	x=${
392		print ${ print hello;} $(print world)
393	}
394	[[ $x == 'hello world' ]]
395EOF
396$SHELL   2> /dev/null <<- \EOF || err_exit 'terminating } is not a reserved word with ${ command }'
397	x=${	{ print -n } ; print -n hello ; }  ; print ' world' }
398	[[ $x == '}hello world' ]]
399EOF
400$SHELL   2> /dev/null <<- \EOF || err_exit '${ command;}xxx not working'
401	f()
402	{
403		print foo
404	}
405	[[ ${ f;}bar == foobar ]]
406EOF
407
408unset foo
409function foo
410{
411	print bar
412}
413[[ ${foo} == bar ]] || err_exit '${foo} is not command substitution when foo unset'
414[[ ! ${foo[@]} ]] || err_exit '${foo[@]} is not empty when foo is unset'
415[[ ! ${foo[3]} ]] || err_exit '${foo[3]} is not empty when foo is unset'
416[[ $(print  "[${ print foo }]") == '[foo]' ]] || err_exit '${...} not working when } is followed by ]'
417[[ $(print  "${ print "[${ print foo }]" }") == '[foo]' ]] || err_exit 'nested ${...} not working when } is followed by ]'
418unset foo
419foo=$(false) > /dev/null && err_exit 'failed command substitution with redirection not returning false'
420expected=foreback
421got=$(print -n fore;(sleep 2;print back)&)
422[[ $got == $expected ]] || err_exit "command substitution background process output error -- got '$got', expected '$expected'"
423
424for false in false $(whence -p false)
425do	x=$($false) && err_exit "x=\$($false) should fail"
426	$($false) && err_exit "\$($false) should fail"
427	$($false) > /dev/null && err_exit "\$($false) > /dev/null should fail"
428done
429[[ $(env 'x-a=y'  $SHELL -c 'env | grep x-a') == *x-a=y* ]] || err_exit 'invalid environment variables not preserved'
430exit $((Errors))
431