xref: /titanic_44/usr/src/lib/libshell/common/tests/builtins.sh (revision 67e3a03ed4a2813074d36330f062ed6e593a4937)
1########################################################################
2#                                                                      #
3#               This software is part of the ast package               #
4#           Copyright (c) 1982-2007 AT&T Knowledge Ventures            #
5#                      and is licensed under the                       #
6#                  Common Public License, Version 1.0                  #
7#                      by AT&T Knowledge Ventures                      #
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 shell builtin commands
29Command=${0##*/}
30integer Errors=0
31builtin getconf
32: ${foo=bar} || err_exit ": failed"
33[[ $foo = bar ]] || err_exit ": side effects failed"
34set -- - foobar
35[[ $# = 2 && $1 = - && $2 = foobar ]] || err_exit "set -- - foobar failed"
36set -- -x foobar
37[[ $# = 2 && $1 = -x && $2 = foobar ]] || err_exit "set -- -x foobar failed"
38getopts :x: foo || err_exit "getopts :x: returns false"
39[[ $foo = x && $OPTARG = foobar ]] || err_exit "getopts :x: failed"
40OPTIND=1
41getopts :r:s var -r
42if	[[ $var != : || $OPTARG != r ]]
43then	err_exit "'getopts :r:s var -r' not working"
44fi
45OPTIND=1
46getopts :d#u var -d 100
47if	[[ $var != d || $OPTARG != 100 ]]
48then	err_exit "'getopts :d#u var -d 100' not working var=$var"
49fi
50OPTIND=1
51while getopts 'ab' option -a -b
52do	[[ $OPTIND == $((OPTIND)) ]] || err_exit "OPTIND optimization bug"
53done
54
55USAGE=$'[-][S:server?Operate on the specified \asubservice\a:]:[subservice:=pmserver]
56    {
57        [p:pmserver]
58        [r:repserver]
59        [11:notifyd]
60    }'
61set pmser p rep r notifyd -11
62while	(( $# > 1 ))
63do	OPTIND=1
64	getopts "$USAGE" OPT -S $1
65	[[ $OPT == S && $OPTARG == $2 ]] || err_exit "OPT=$OPT OPTARG=$OPTARG -- expected OPT=S OPTARG=$2"
66	shift 2
67done
68
69false ${foo=bar} &&  err_exit "false failed"
70read <<!
71hello world
72!
73[[ $REPLY = 'hello world' ]] || err_exit "read builtin failed"
74print x:y | IFS=: read a b
75if	[[ $a != x ]]
76then	err_exit "IFS=: read ... not working"
77fi
78read <<!
79hello \
80world
81!
82[[ $REPLY = 'hello world' ]] || err_exit "read continuation failed"
83read -d x <<!
84hello worldxfoobar
85!
86[[ $REPLY = 'hello world' ]] || err_exit "read builtin failed"
87read <<\!
88hello \
89	world \
90
91!
92[[ $REPLY == 'hello 	world' ]] || err_exit "read continuation2 failed"
93print "one\ntwo" | { read line
94	print $line | /bin/cat > /dev/null
95	read line
96}
97read <<\!
98\
99a\
100\
101\
102b
103!
104if	[[ $REPLY != ab ]]
105then	err_exit "read multiple continuation failed"
106fi
107if	[[ $line != two ]]
108then	err_exit "read from pipeline failed"
109fi
110line=two
111read line < /dev/null
112if	[[ $line != "" ]]
113then	err_exit "read from /dev/null failed"
114fi
115if	[[ $(print -R -) != - ]]
116then	err_exit "print -R not working correctly"
117fi
118if	[[ $(print -- -) != - ]]
119then	err_exit "print -- not working correctly"
120fi
121print -f "hello%nbar\n" size > /dev/null
122if	((	size != 5 ))
123then	err_exit "%n format of printf not working"
124fi
125print -n -u2 2>&1-
126[[ -w /dev/fd/1 ]] || err_exit "2<&1- with built-ins has side effects"
127x=$0
128if	[[ $(eval 'print $0') != $x ]]
129then	err_exit '$0 not correct for eval'
130fi
131unset x
132readonly x
133set -- $(readonly)
134if      [[ " $@ " != *" x "* ]]
135then    err_exit 'unset readonly variables are not displayed'
136fi
137if	[[ $(	for i in foo bar
138		do	print $i
139			continue 10
140		done
141	    ) != $'foo\nbar' ]]
142then	err_exit 'continue breaks out of loop'
143fi
144(continue bad 2>/dev/null && err_exit 'continue bad should return an error')
145(break bad 2>/dev/null && err_exit 'break bad should return an error')
146(continue 0 2>/dev/null && err_exit 'continue 0 should return an error')
147(break 0 2>/dev/null && err_exit 'break 0 should return an error')
148breakfun() { break;}
149continuefun() { continue;}
150for fun in break continue
151do	if	[[ $(	for i in foo
152			do	${fun}fun
153				print $i
154			done
155		) != foo ]]
156	then	err_exit "$fun call in ${fun}fun breaks out of for loop"
157	fi
158done
159if	[[ $(print -f "%b" "\a\n\v\b\r\f\E\03\\oo") != $'\a\n\v\b\r\f\E\03\\oo' ]]
160then	err_exit 'print -f "%b" not working'
161fi
162if	[[ $(print -f "%P" "[^x].*b$") != '*[!x]*b' ]]
163then	err_exit 'print -f "%P" not working'
164fi
165if	[[ $(abc: for i in foo bar;do print $i;break abc;done) != foo ]]
166then	err_exit 'break labels not working'
167fi
168if	[[ $(command -v if)	!= if ]]
169then	err_exit	'command -v not working'
170fi
171read -r var <<\!
172
173!
174if	[[ $var != "" ]]
175then	err_exit "read -r of blank line not working"
176fi
177mkdir -p /tmp/ksh$$/a/b/c 2>/dev/null || err_exit  "mkdir -p failed"
178$SHELL -c "cd /tmp/ksh$$/a/b; cd c" 2>/dev/null || err_exit "initial script relative cd fails"
179rm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed"
180trap 'print HUP' HUP
181if	[[ $(trap) != "trap -- 'print HUP' HUP" ]]
182then	err_exit '$(trap) not working'
183fi
184if	[[ $(trap -p HUP) != 'print HUP' ]]
185then	err_exit '$(trap -p HUP) not working'
186fi
187[[ $($SHELL -c 'trap "print ok" SIGTERM; kill -s SIGTERM $$' 2> /dev/null) == ok
188 ]] || err_exit 'SIGTERM not recognized'
189[[ $($SHELL -c 'trap "print ok" sigterm; kill -s sigterm $$' 2> /dev/null) == ok
190 ]] || err_exit 'SIGTERM not recognized'
191${SHELL} -c 'kill -1 -$$' 2> /dev/null
192[[ $(kill -l $?) == HUP ]] || err_exit 'kill -1 -pid not working'
193${SHELL} -c 'kill -1 -$$' 2> /dev/null
194[[ $(kill -l $?) == HUP ]] || err_exit 'kill -n1 -pid not working'
195${SHELL} -c 'kill -s HUP -$$' 2> /dev/null
196[[ $(kill -l $?) == HUP ]] || err_exit 'kill -HUP -pid not working'
197n=123
198typeset -A base
199base[o]=8#
200base[x]=16#
201base[X]=16#
202for i in d i o u x X
203do	if	(( $(( ${base[$i]}$(printf "%$i" $n) )) != n  ))
204	then	err_exit "printf %$i not working"
205	fi
206done
207if	[[ $( trap 'print done' EXIT) != done ]]
208then	err_exit 'trap on EXIT not working'
209fi
210if	[[ $( trap 'print done' EXIT; trap - EXIT) == done ]]
211then	err_exit 'trap on EXIT not being cleared'
212fi
213if	[[ $(type test) != 'test is a shell builtin' ]]
214then	err_exit 'whence -v test not a builtin'
215fi
216builtin -d test
217if	[[ $(type test) == *builtin* ]]
218then	err_exit 'whence -v test after builtin -d incorrect'
219fi
220typeset -Z3 percent=$(printf '%o\n' "'%'")
221forrmat=\\${percent}s
222if      [[ $(printf "$forrmat") != %s ]]
223then    err_exit "printf $forrmat not working"
224fi
225if	(( $(printf 'x\0y' | wc -c) != 3 ))
226then	err_exit 'printf \0 not working'
227fi
228if	[[ $(printf "%bx%s\n" 'f\to\cbar') != $'f\to' ]]
229then	err_exit 'printf %bx%s\n  not working'
230fi
231alpha=abcdefghijklmnop
232if	[[ $(printf "%10.*s\n" 5 $alpha) != '     abcde' ]]
233then	err_exit 'printf %10.%s\n  not working'
234fi
235float x2=.0000625
236if	[[ $(printf "%10.5E\n" x2) != 6.25000E-05 ]]
237then	err_exit 'printf "%10.5E" not normalizing correctly'
238fi
239x2=.000000001
240if	[[ $(printf "%g\n" x2 2>/dev/null) != 1e-09 ]]
241then	err_exit 'printf "%g" not working correctly'
242fi
243#FIXME#($SHELL read -s foobar <<\!
244#FIXME#testing
245#FIXME#!
246#FIXME#) 2> /dev/null || err_exit ksh read -s var fails
247if	[[ $(printf +3 2>/dev/null) !=   +3 ]]
248then	err_exit 'printf is not processing formats beginning with + correctly'
249fi
250if	printf "%d %d\n" 123bad 78 >/dev/null 2>/dev/null
251then	err_exit "printf not exiting non-zero with conversion errors"
252fi
253if	[[ $(trap --version 2> /dev/null;print done) != done ]]
254then	err_exit 'trap builtin terminating after --version'
255fi
256if	[[ $(set --version 2> /dev/null;print done) != done ]]
257then	err_exit 'set builtin terminating after --veresion'
258fi
259unset -f foobar
260function foobar
261{
262	print 'hello world'
263}
264OPTIND=1
265if	[[ $(getopts  $'[+?X\ffoobar\fX]' v --man 2>&1) != *'Xhello world'X* ]]
266then	err_exit '\f...\f not working in getopts usage strings'
267fi
268if	[[	$(printf '%H\n' $'<>"& \'\tabc') != '&lt;&gt;&quot;&amp;&nbsp;&apos;&#9;abc' ]]
269then	err_exit 'printf %H not working'
270fi
271if	[[	$(printf '%R %R %R %R\n' 'a.b' '*.c' '^'  '!(*.*)') != '^a\.b$ \.c$ ^\^$ ^(.*\..*)!$' ]]
272then	err_exit 'printf %R not working'
273fi
274if	[[ $(printf '%..:c\n' abc) != a:b:c ]]
275then	err_exit	"printf '%..:c' not working"
276fi
277if	[[ $(printf '%..*c\n' : abc) != a:b:c ]]
278then	err_exit	"printf '%..*c' not working"
279fi
280if	[[ $(printf '%..:s\n' abc def ) != abc:def ]]
281then	err_exit	"printf '%..:s' not working"
282fi
283if	[[ $(printf '%..*s\n' : abc def) != abc:def ]]
284then	err_exit	"printf '%..*s' not working"
285fi
286[[ $(printf '%q\n') == '' ]] || err_exit 'printf "%q" with missing arguments'
287# we won't get hit by the one second boundary twice, right?
288[[ $(printf '%T\n' now) == "$(date)" ]] ||
289[[ $(printf '%T\n' now) == "$(date)" ]] ||
290err_exit 'printf "%T" now'
291behead()
292{
293	read line
294	left=$(cat)
295}
296print $'line1\nline2' | behead
297if	[[ $left != line2 ]]
298then	err_exit  "read reading ahead on a pipe"
299fi
300read -n1 y <<!
301abc
302!
303if      [[ $y != a ]]
304then    err_exit  'read -n1 not working'
305fi
306print -n $'{ read -r line;print $line;}\nhello' > /tmp/ksh$$
307chmod 755 /tmp/ksh$$
308trap 'rm -rf /tmp/ksh$$' EXIT
309if	[[ $($SHELL < /tmp/ksh$$) != hello ]]
310then	err_exit 'read of incomplete line not working correctly'
311fi
312set -f
313set -- *
314if      [[ $1 != '*' ]]
315then    err_exit 'set -f not working'
316fi
317unset pid1 pid2
318false &
319pid1=$!
320pid2=$(
321	wait $pid1
322	(( $? == 127 )) || err_exit "job known to subshell"
323	print $!
324)
325wait $pid1
326(( $? == 1 )) || err_exit "wait not saving exit value"
327wait $pid2
328(( $? == 127 )) || err_exit "subshell job known to parent"
329set --noglob
330ifs=$IFS
331IFS=,
332set -- $(getconf LIBPATH)
333IFS=$ifs
334env=
335for v
336do	IFS=:
337	set -- $v
338	IFS=$ifs
339	eval [[ \$$2 ]] && env="$env $2=\"\$$2\""
340done
341set --glob
342if	[[ $(foo=bar; eval foo=\$foo $env exec -c \$SHELL -c \'print \$foo\') != bar ]]
343then	err_exit '"name=value exec -c ..." not working'
344fi
345$SHELL -c 'OPTIND=-1000000; getopts a opt -a' 2> /dev/null
346[[ $? == 1 ]] || err_exit 'getopts with negative OPTIND not working'
347getopts 'n#num' opt  -n 3
348[[ $OPTARG == 3 ]] || err_exit 'getopts with numerical arguments failed'
349if	[[ $($SHELL -c $'printf \'%2$s %1$s\n\' world hello') != 'hello world' ]]
350then	err_exit 'printf %2$s %1$s not working'
351fi
352((n=0))
353((n++)); ARGC[$n]=1 ARGV[$n]=""
354((n++)); ARGC[$n]=2 ARGV[$n]="-a"
355((n++)); ARGC[$n]=4 ARGV[$n]="-a -v 2"
356((n++)); ARGC[$n]=4 ARGV[$n]="-a -v 2 x"
357((n++)); ARGC[$n]=4 ARGV[$n]="-a -v 2 x y"
358for ((i=1; i<=n; i++))
359do	set -- ${ARGV[$i]}
360	OPTIND=0
361	while	getopts -a tst "av:" OPT
362	do	:
363	done
364	if	[[ $OPTIND != ${ARGC[$i]} ]]
365	then	err_exit "\$OPTIND after getopts loop incorrect -- got $OPTIND, expected ${ARGC[$i]}"
366	fi
367done
368unset a
369{ read -N3 a; read -N1 b;}  <<!
370abcdefg
371!
372[[ $a == abc ]] || err_exit 'read -N3 here-document not working'
373[[ $b == d ]] || err_exit 'read -N1 here-document not working'
374read -n3 a <<!
375abcdefg
376!
377[[ $a == abc ]] || err_exit 'read -n3 here-document not working'
378(print -n a;sleep 1; print -n bcde) | { read -N3 a; read -N1 b;}
379[[ $a == abc ]] || err_exit 'read -N3 from pipe not working'
380[[ $b == d ]] || err_exit 'read -N1 from pipe not working'
381(print -n a;sleep 1; print -n bcde) |read -n3 a
382[[ $a == a ]] || err_exit 'read -n3 from pipe not working'
383rm -f /tmp/fifo$$
384if	mkfifo /tmp/fifo$$ 2> /dev/null
385then	(print -n a; sleep 1;print -n bcde)  > /tmp/fifo$$ &
386	{
387	read -u5 -n3  -t2 a  || err_exit 'read -n3 from fifo timedout'
388	read -u5 -n1 -t2 b || err_exit 'read -n1 from fifo timedout'
389	} 5< /tmp/fifo$$
390	[[ $a == a ]] || err_exit 'read -n3 from fifo not working'
391	rm -f /tmp/fifo$$
392	mkfifo /tmp/fifo$$ 2> /dev/null
393	(print -n a; sleep 1;print -n bcde)  > /tmp/fifo$$ &
394	{
395	read -u5 -N3 -t2 a || err_exit 'read -N3 from fifo timed out'
396	read -u5 -N1 -t2 b || err_exit 'read -N1 from fifo timedout'
397	} 5< /tmp/fifo$$
398	[[ $a == abc ]] || err_exit 'read -N3 from fifo not working'
399	[[ $b == d ]] || err_exit 'read -N1 from fifo not working'
400fi
401rm -f /tmp/fifo$$
402function longline
403{
404	integer i
405	for((i=0; i < $1; i++))
406	do	print argument$i
407	done
408}
409# test command -x option
410integer sum=0 n=10000
411if	! ${SHELL:-ksh} -c 'print $#' count $(longline $n) > /dev/null  2>&1
412then	for i in $(command command -x ${SHELL:-ksh} -c 'print $#;[[ $1 != argument0 ]]' count $(longline $n) 2> /dev/null)
413	do	((sum += $i))
414	done
415	(( sum == n )) || err_exit "command -x processed only $sum arguments"
416	command -p command -x ${SHELL:-ksh} -c 'print $#;[[ $1 == argument0 ]]' count $(longline $n) > /dev/null  2>&1
417	[[ $? != 1 ]] && err_exit 'incorrect exit status for command -x'
418fi
419# test command -x option with extra arguments
420integer sum=0 n=10000
421if      ! ${SHELL:-ksh} -c 'print $#' count $(longline $n) > /dev/null  2>&1
422then    for i in $(command command -x ${SHELL:-ksh} -c 'print $#;[[ $1 != argument0 ]]' count $(longline $n) one two three) #2> /dev/null)
423	do      ((sum += $i))
424	done
425	(( sum  > n )) || err_exit "command -x processed only $sum arguments"
426	(( (sum-n)%3==0 )) || err_exit "command -x processed only $sum arguments"
427	(( sum == n+3)) && err_exit "command -x processed only $sum arguments"
428	command -p command -x ${SHELL:-ksh} -c 'print $#;[[ $1 == argument0 ]]' count $(longline $n) > /dev/null  2>&1
429	[[ $? != 1 ]] && err_exit 'incorrect exit status for command -x'
430fi
431# test for debug trap
432[[ $(typeset -i i=0
433	trap 'print $i' DEBUG
434	while (( i <2))
435	do	(( i++))
436	done) == $'0\n0\n1\n1\n2' ]]  || err_exit  "DEBUG trap not working"
437getconf UNIVERSE - ucb
438[[ $($SHELL -c 'echo -3') == -3 ]] || err_exit "echo -3 not working in ucb universe"
439typeset -F3 start_x=SECONDS total_t delay=0.02
440typeset reps=50 leeway=5
441sleep $(( 2 * leeway * reps * delay )) |
442for (( i=0 ; i < reps ; i++ ))
443do	read -N1 -t $delay
444done
445(( total_t = SECONDS - start_x ))
446if	(( total_t > leeway * reps * delay ))
447then	err_exit "read -t in pipe taking $total_t secs - $(( reps * delay )) minimum - too long"
448elif	(( total_t < reps * delay ))
449then	err_exit "read -t in pipe taking $total_t secs - $(( reps * delay )) minimum - too fast"
450fi
451exit $((Errors))
452