1# $NetBSD: t_redir.sh,v 1.9 2016/05/14 00:33:02 kre Exp $ 2# 3# Copyright (c) 2016 The NetBSD Foundation, Inc. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 1. Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# 2. Redistributions in binary form must reproduce the above copyright 12# notice, this list of conditions and the following disclaimer in the 13# documentation and/or other materials provided with the distribution. 14# 15# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25# POSSIBILITY OF SUCH DAMAGE. 26# 27# the implementation of "sh" to test 28: ${TEST_SH:="/bin/sh"} 29 30# Any failures in this first test means it is not worth bothering looking 31# for causes of failures in any other tests, make this one work first. 32 33# Problems with this test usually mean inadequate ATF_SHELL used for testing. 34# (though if all pass but the last, it might be a TEST_SH problem.) 35 36atf_test_case basic_test_method_test 37basic_test_method_test_head() 38{ 39 atf_set "descr" "Tests that test method works as expected" 40} 41basic_test_method_test_body() 42{ 43 cat <<- 'DONE' | 44 DONE 45 atf_check -s exit:0 -o empty -e empty ${TEST_SH} 46 cat <<- 'DONE' | 47 DONE 48 atf_check -s exit:0 -o match:0 -e empty ${TEST_SH} -c 'wc -l' 49 50 cat <<- 'DONE' | 51 echo hello 52 DONE 53 atf_check -s exit:0 -o match:hello -e empty ${TEST_SH} 54 cat <<- 'DONE' | 55 echo hello 56 DONE 57 atf_check -s exit:0 -o match:1 -e empty ${TEST_SH} -c 'wc -l' 58 59 cat <<- 'DONE' | 60 echo hello\ 61 world 62 DONE 63 atf_check -s exit:0 -o match:helloworld -e empty ${TEST_SH} 64 cat <<- 'DONE' | 65 echo hello\ 66 world 67 DONE 68 atf_check -s exit:0 -o match:2 -e empty ${TEST_SH} -c 'wc -l' 69 70 printf '%s\n%s\n%s\n' Line1 Line2 Line3 > File 71 atf_check -s exit:0 -o inline:'Line1\nLine2\nLine3\n' -e empty \ 72 ${TEST_SH} -c 'cat File' 73 74 cat <<- 'DONE' | 75 set -- X "" '' Y 76 echo ARGS="${#}" 77 echo '' -$1- -$2- -$3- -$4- 78 cat <<EOF 79 X=$1 80 EOF 81 cat <<\EOF 82 Y=$4 83 EOF 84 DONE 85 atf_check -s exit:0 -o match:ARGS=4 -o match:'-X- -- -- -Y-' \ 86 -o match:X=X -o match:'Y=\$4' -e empty ${TEST_SH} 87} 88 89atf_test_case do_input_redirections 90do_input_redirections_head() 91{ 92 atf_set "descr" "Tests that simple input redirection works" 93} 94do_input_redirections_body() 95{ 96 printf '%s\n%s\n%s\nEND\n' 'First Line' 'Second Line' 'Line 3' >File 97 98 atf_check -s exit:0 -e empty \ 99 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 100 ${TEST_SH} -c 'cat < File' 101 atf_check -s exit:0 -e empty \ 102 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 103 ${TEST_SH} -c 'cat <File' 104 atf_check -s exit:0 -e empty \ 105 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 106 ${TEST_SH} -c 'cat< File' 107 atf_check -s exit:0 -e empty \ 108 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 109 ${TEST_SH} -c 'cat < "File"' 110 atf_check -s exit:0 -e empty \ 111 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 112 ${TEST_SH} -c '< File cat' 113 114 ln File wc 115 atf_check -s exit:0 -e empty \ 116 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 117 ${TEST_SH} -c '< wc cat' 118 119 mv wc cat 120 atf_check -s exit:0 -e empty -o match:4 \ 121 ${TEST_SH} -c '< cat wc' 122 123 124 cat <<- 'EOF' | 125 for l in 1 2 3; do 126 read line < File 127 echo "$line" 128 done 129 EOF 130 atf_check -s exit:0 -e empty \ 131 -o inline:'First Line\nFirst Line\nFirst Line\n' \ 132 ${TEST_SH} 133 134 cat <<- 'EOF' | 135 for l in 1 2 3; do 136 read line 137 echo "$line" 138 done <File 139 EOF 140 atf_check -s exit:0 -e empty \ 141 -o inline:'First Line\nSecond Line\nLine 3\n' \ 142 ${TEST_SH} 143 144 cat <<- 'EOF' | 145 for l in 1 2 3; do 146 read line < File 147 echo "$line" 148 done <File 149 EOF 150 atf_check -s exit:0 -e empty \ 151 -o inline:'First Line\nFirst Line\nFirst Line\n' \ 152 ${TEST_SH} 153 154 cat <<- 'EOF' | 155 line= 156 while [ "$line" != END ]; do 157 read line || exit 1 158 echo "$line" 159 done <File 160 EOF 161 atf_check -s exit:0 -e empty \ 162 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 163 ${TEST_SH} 164 165 cat <<- 'EOF' | 166 while :; do 167 read line || exit 0 168 echo "$line" 169 done <File 170 EOF 171 atf_check -s exit:0 -e empty \ 172 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 173 ${TEST_SH} 174 175 cat <<- 'EOF' | 176 l='' 177 while read line < File 178 do 179 echo "$line" 180 l="${l}x" 181 [ ${#l} -ge 3 ] && break 182 done 183 echo DONE 184 EOF 185 atf_check -s exit:0 -e empty \ 186 -o inline:'First Line\nFirst Line\nFirst Line\nDONE\n' \ 187 ${TEST_SH} 188 189 cat <<- 'EOF' | 190 while read line 191 do 192 echo "$line" 193 done <File 194 echo DONE 195 EOF 196 atf_check -s exit:0 -e empty \ 197 -o inline:'First Line\nSecond Line\nLine 3\nEND\nDONE\n' \ 198 ${TEST_SH} 199 200 cat <<- 'EOF' | 201 l='' 202 while read line 203 do 204 echo "$line" 205 l="${l}x" 206 [ ${#l} -ge 3 ] && break 207 done <File 208 echo DONE 209 EOF 210 atf_check -s exit:0 -e empty \ 211 -o inline:'First Line\nSecond Line\nLine 3\nDONE\n' ${TEST_SH} 212 213 cat <<- 'EOF' | 214 l='' 215 while read line1 <File 216 do 217 read line2 218 echo "$line1":"$line2" 219 l="${l}x" 220 [ ${#l} -ge 2 ] && break 221 done <File 222 echo DONE 223 EOF 224 atf_check -s exit:0 -e empty \ 225 -o inline:'First Line:First Line\nFirst Line:Second Line\nDONE\n' \ 226 ${TEST_SH} 227} 228 229atf_test_case do_output_redirections 230do_output_redirections_head() 231{ 232 atf_set "descr" "Test Output redirections" 233} 234do_output_redirections_body() 235{ 236nl=' 237' 238 T=0 239 i() { T=$(expr "$T" + 1); } 240 241 rm -f Output 2>/dev/null || : 242 test -f Output && atf_fail "Unable to remove Output file" 243#1 244 i; atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '> Output' 245 test -f Output || atf_fail "#$T: Did not make Output file" 246#2 247 rm -f Output 2>/dev/null || : 248 i; atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '>> Output' 249 test -f Output || atf_fail "#$T: Did not make Output file" 250#3 251 rm -f Output 2>/dev/null || : 252 i; atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '>| Output' 253 test -f Output || atf_fail "#$T: Did not make Output file" 254 255#4 256 rm -f Output 2>/dev/null || : 257 i 258 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c 'echo Hello >Output' 259 test -s Output || atf_fail "#$T: Did not make non-empty Output file" 260 test "$(cat Output)" = "Hello" || 261 atf_fail "#$T: Incorrect Output: Should be 'Hello' is '$(cat Output)'" 262#5 263 i 264 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c 'echo Hello>!Output' 265 test -s Output || atf_fail "#$T: Did not make non-empty Output file" 266 test "$(cat Output)" = "Hello" || 267 atf_fail "#$T: Incorrect Output: Should be 'Hello' is '$(cat Output)'" 268#6 269 i 270 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c 'echo Bye >>Output' 271 test -s Output || atf_fail "#$T: Removed Output file" 272 test "$(cat Output)" = "Hello${nl}Bye" || atf_fail \ 273 "#$T: Incorrect Output: Should be 'Hello\\nBye' is '$(cat Output)'" 274#7 275 i; atf_check -s exit:0 -o inline:'line 1\nline 2\n' -e empty \ 276 ${TEST_SH} -c \ 277 'echo line 1 > Output; echo line 2 >> Output; cat Output' 278 test "$(cat Output)" = "line 1${nl}line 2" || atf_fail \ 279 "#$T: Incorrect Output: Should be 'line 1\\nline 2' is '$(cat Output)'" 280#8 281 i; atf_check -s exit:0 -o inline:'line 2\n' -e empty \ 282 ${TEST_SH} -c 'echo line 1 > Output; echo line 2' 283 test "$(cat Output)" = "line 1" || atf_fail \ 284 "#$T: Incorrect Output: Should be 'line 1' is '$(cat Output)'" 285#9 286 i; atf_check -s exit:0 -o empty -e empty \ 287 ${TEST_SH} -c '(echo line 1; echo line 2 > Out2) > Out1' 288 test "$(cat Out1)" = "line 1" || atf_fail \ 289 "#$T: Incorrect Out1: Should be 'line 1' is '$(cat Out1)'" 290 test "$(cat Out2)" = "line 2" || atf_fail \ 291 "#$T: Incorrect Out2: Should be 'line 2' is '$(cat Out2)'" 292#10 293 i; atf_check -s exit:0 -o empty -e empty \ 294 ${TEST_SH} -c '{ echo line 1; echo line 2 > Out2;} > Out1' 295 test "$(cat Out1)" = "line 1" || atf_fail \ 296 "#$T: Incorrect Out1: Should be 'line 1' is '$(cat Out1)'" 297 test "$(cat Out2)" = "line 2" || atf_fail \ 298 "#$T: Incorrect Out2: Should be 'line 2' is '$(cat Out2)'" 299#11 300 i; rm -f Out1 Out2 2>/dev/null || : 301 cat <<- 'EOF' | 302 for arg in 'line 1' 'line 2' 'line 3' 303 do 304 echo "$arg" 305 echo "$arg" > Out1 306 done > Out2 307 EOF 308 atf_check -s exit:0 -o empty -e empty ${TEST_SH} 309 test "$(cat Out1)" = "line 3" || atf_fail \ 310 "#$T: Incorrect Out1: Should be 'line 3' is '$(cat Out1)'" 311 test "$(cat Out2)" = "line 1${nl}line 2${nl}line 3" || atf_fail \ 312 "#$T: Incorrect Out2: Should be 'line 1\\nline 2\\nline 3' is '$(cat Out2)'" 313#12 314 i; rm -f Out1 Out2 2>/dev/null || : 315 cat <<- 'EOF' | 316 for arg in 'line 1' 'line 2' 'line 3' 317 do 318 echo "$arg" 319 echo "$arg" >> Out1 320 done > Out2 321 EOF 322 atf_check -s exit:0 -o empty -e empty ${TEST_SH} 323 test "$(cat Out1)" = "line 1${nl}line 2${nl}line 3" || atf_fail \ 324 "#$T: Incorrect Out1: Should be 'line 1\\nline 2\\nline 3' is '$(cat Out1)'" 325 test "$(cat Out2)" = "line 1${nl}line 2${nl}line 3" || atf_fail \ 326 "#$T: Incorrect Out2: Should be 'line 1\\nline 2\\nline 3' is '$(cat Out2)'" 327} 328 329atf_test_case fd_redirections 330fd_redirections_head() 331{ 332 atf_set "descr" "Tests redirections to/from specific descriptors" 333} 334fd_redirections_body() 335{ 336 atf_require_prog /bin/echo 337 338 cat <<- 'DONE' > helper.sh 339 f() { 340 /bin/echo nothing "$1" >& "$1" 341 } 342 for n 343 do 344 eval "f $n $n"'> file-$n' 345 done 346 DONE 347 cat <<- 'DONE' > reread.sh 348 f() { 349 (read -r var; echo "${var}") <&"$1" 350 } 351 for n 352 do 353 x=$( eval "f $n $n"'< file-$n' ) 354 test "${x}" = "nothing $n" || echo "$n" 355 done 356 DONE 357 358 validate() 359 { 360 for n 361 do 362 test -e "file-$n" || atf_fail "file-$n not created" 363 C=$(cat file-"$n") 364 test "$C" = "nothing $n" || 365 atf_fail "file-$n contains '$C' not 'nothing $n'" 366 done 367 } 368 369 atf_check -s exit:0 -e empty -o empty \ 370 ${TEST_SH} helper.sh 1 2 3 4 5 6 7 8 9 371 validate 1 2 3 4 5 6 7 8 9 372 atf_check -s exit:0 -e empty -o empty \ 373 ${TEST_SH} reread.sh 3 4 5 6 7 8 9 374 375 L=$(ulimit -n) 376 if [ "$L" -ge 30 ] 377 then 378 atf_check -s exit:0 -e empty -o empty \ 379 ${TEST_SH} helper.sh 10 15 19 20 25 29 380 validate 10 15 19 20 25 29 381 atf_check -s exit:0 -e empty -o empty \ 382 ${TEST_SH} reread.sh 10 15 19 20 25 29 383 fi 384 if [ "$L" -ge 100 ] 385 then 386 atf_check -s exit:0 -e empty -o empty \ 387 ${TEST_SH} helper.sh 32 33 49 50 51 63 64 65 77 88 99 388 validate 32 33 49 50 51 63 64 65 77 88 99 389 atf_check -s exit:0 -e empty -o empty \ 390 ${TEST_SH} reread.sh 32 33 49 50 51 63 64 65 77 88 99 391 fi 392 if [ "$L" -ge 500 ] 393 then 394 atf_check -s exit:0 -e empty -o empty \ 395 ${TEST_SH} helper.sh 100 101 199 200 222 333 444 499 396 validate 100 101 199 200 222 333 444 499 397 atf_check -s exit:0 -e empty -o empty \ 398 ${TEST_SH} reread.sh 100 101 199 200 222 333 444 499 399 fi 400 if [ "$L" -gt 1005 ] 401 then 402 atf_check -s exit:0 -e empty -o empty \ 403 ${TEST_SH} helper.sh 1000 1001 1002 1003 1004 1005 404 validate 1000 1001 1002 1003 1004 1005 405 atf_check -s exit:0 -e empty -o empty \ 406 ${TEST_SH} reread.sh 1000 1001 1002 1003 1004 1005 407 fi 408} 409 410atf_test_case local_redirections 411local_redirections_head() 412{ 413 atf_set "descr" \ 414 "Tests that exec can reassign file descriptors in the shell itself" 415} 416local_redirections_body() 417{ 418 cat <<- 'DONE' > helper.sh 419 for f 420 do 421 eval "exec $f"'> file-$f' 422 done 423 424 for f 425 do 426 printf '%s\n' "Hello $f" >&"$f" 427 done 428 429 for f 430 do 431 eval "exec $f"'>&-' 432 done 433 434 for f 435 do 436 eval "exec $f"'< file-$f' 437 done 438 439 for f 440 do 441 exec <& "$f" 442 read -r var || echo >&2 "No data in file-$f" 443 read -r x && echo >&2 "Too much data in file-${f}: $x" 444 test "${var}" = "Hello $f" || 445 echo >&2 "file-$f contains '${var}' not 'Hello $f'" 446 done 447 DONE 448 449 atf_check -s exit:0 -o empty -e empty \ 450 ${TEST_SH} helper.sh 3 4 5 6 7 8 9 451 452 L=$(ulimit -n) 453 if [ "$L" -ge 30 ] 454 then 455 atf_check -s exit:0 -o empty -e empty \ 456 ${TEST_SH} helper.sh 10 11 13 15 16 19 20 28 29 457 fi 458 if [ "$L" -ge 100 ] 459 then 460 atf_check -s exit:0 -o empty -e empty \ 461 ${TEST_SH} helper.sh 30 31 32 63 64 65 77 88 99 462 fi 463 if [ "$L" -ge 500 ] 464 then 465 atf_check -s exit:0 -o empty -e empty \ 466 ${TEST_SH} helper.sh 100 101 111 199 200 201 222 333 499 467 fi 468 if [ "$L" -ge 1005 ] 469 then 470 atf_check -s exit:0 -o empty -e empty \ 471 ${TEST_SH} helper.sh 1000 1001 1002 1003 1004 1005 472 fi 473} 474 475atf_test_case named_fd_redirections 476named_fd_redirections_head() 477{ 478 atf_set "descr" "Tests redirections to /dev/stdout (etc)" 479 480} 481named_fd_redirections_body() 482{ 483 if test -c /dev/stdout 484 then 485 atf_check -s exit:0 -o inline:'OK\n' -e empty \ 486 ${TEST_SH} -c 'echo OK >/dev/stdout' 487 atf_check -s exit:0 -o inline:'OK\n' -e empty \ 488 ${TEST_SH} -c '/bin/echo OK >/dev/stdout' 489 fi 490 491 if test -c /dev/stdin 492 then 493 atf_require_prog cat 494 495 echo GOOD | atf_check -s exit:0 -o inline:'GOOD\n' -e empty \ 496 ${TEST_SH} -c 'read var </dev/stdin; echo $var' 497 echo GOOD | atf_check -s exit:0 -o inline:'GOOD\n' -e empty \ 498 ${TEST_SH} -c 'cat </dev/stdin' 499 fi 500 501 if test -c /dev/stderr 502 then 503 atf_check -s exit:0 -e inline:'OK\n' -o empty \ 504 ${TEST_SH} -c 'echo OK 2>/dev/stderr >&2' 505 atf_check -s exit:0 -e inline:'OK\n' -o empty \ 506 ${TEST_SH} -c '/bin/echo OK 2>/dev/stderr >&2' 507 fi 508 509 if test -c /dev/fd/8 && test -c /dev/fd/9 510 then 511 atf_check -s exit:0 -o inline:'EIGHT\n' -e empty \ 512 ${TEST_SH} -c 'printf "%s\n" EIGHT 8>&1 >/dev/fd/8 | 513 cat 9<&0 </dev/fd/9' 514 fi 515 516 return 0 517} 518 519atf_test_case redir_in_case 520redir_in_case_head() 521{ 522 atf_set "descr" "Tests that sh(1) allows just redirections " \ 523 "in case statements. (PR bin/48631)" 524} 525redir_in_case_body() 526{ 527 atf_check -s exit:0 -o empty -e empty \ 528 ${TEST_SH} -c 'case x in (whatever) >foo;; esac' 529 530 atf_check -s exit:0 -o empty -e empty \ 531 ${TEST_SH} -c 'case x in (whatever) >foo 2>&1;; esac' 532 533 atf_check -s exit:0 -o empty -e empty \ 534 ${TEST_SH} -c 'case x in (whatever) >foo 2>&1 </dev/null;; esac' 535 536 atf_check -s exit:0 -o empty -e empty \ 537 ${TEST_SH} -c 'case x in (whatever) >${somewhere};; esac' 538} 539 540atf_test_case incorrect_redirections 541incorrect_redirections_head() 542{ 543 atf_set "descr" "Tests that sh(1) correctly ignores non-redirections" 544} 545incorrect_redirections_body() { 546 547 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c 'echo foo>' 548 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c 'read foo<' 549 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c 'echo foo<>' 550 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 551 'echo x > '"$nl" 552 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 553 'read x < '"$nl" 554 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 555 'echo x <> '"$nl" 556 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 557 'echo x >< anything' 558 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 559 'echo x >>< anything' 560 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 561 'echo x >|< anything' 562 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 563 'echo x > ; read x < /dev/null || echo bad' 564 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 565 'read x < & echo y > /dev/null; wait && echo bad' 566 567 rm -f Output 2>/dev/null || : 568 atf_check -s exit:0 -e empty -o inline:'A Line > Output\n' \ 569 ${TEST_SH} -c 'echo A Line \> Output' 570 test -f Output && atf_file "File 'Output' appeared and should not have" 571 572 rm -f Output 2>/dev/null || : 573 atf_check -s exit:0 -e empty -o empty \ 574 ${TEST_SH} -c 'echo A Line \>> Output' 575 test -f Output || atf_file "File 'Output' not created when it should" 576 test "$(cat Output)" = 'A Line >' || atf_fail \ 577 "Output file contains '$(cat Output)' instead of '"'A Line >'\' 578 579 rm -f Output \> 2>/dev/null || : 580 atf_check -s exit:0 -e empty -o empty \ 581 ${TEST_SH} -c 'echo A Line >\> Output' 582 test -f Output && atf_file "File 'Output' appeared and should not have" 583 test -f '>' || atf_file "File '>' not created when it should" 584 test "$(cat '>')" = 'A Line Output' || atf_fail \ 585 "Output file ('>') contains '$(cat '>')' instead of 'A Line Output'" 586} 587 588# Many more tests in t_here, so here we have just rudimentary checks 589atf_test_case redir_here_doc 590redir_here_doc_head() 591{ 592 atf_set "descr" "Tests that sh(1) correctly processes 'here' doc " \ 593 "input redirections" 594} 595redir_here_doc_body() 596{ 597 # nb: the printf is not executed, it is data 598 cat <<- 'DONE' | 599 cat <<EOF 600 printf '%s\n' 'hello\n' 601 EOF 602 DONE 603 atf_check -s exit:0 -o match:printf -o match:'hello\\n' \ 604 -e empty ${TEST_SH} 605} 606 607atf_test_case subshell_redirections 608subshell_redirections_head() 609{ 610 atf_set "descr" "Tests redirection interactions between shell and " \ 611 "its sub-shell(s)" 612} 613subshell_redirections_body() 614{ 615 atf_require_prog cat 616 617 LIM=$(ulimit -n) 618 619 cat <<- 'DONE' | 620 exec 6>output-file 621 622 ( printf "hello\n" >&6 ) 623 624 exec 8<output-file 625 626 ( read hello <&8 ; test hello = "$hello" || echo >&2 Hello ) 627 628 ( printf "bye-bye\n" >&6 ) 629 630 ( exec 8<&- ) 631 read bye <&8 || echo >&2 "Closed?" 632 echo Bye="$bye" 633 DONE 634 atf_check -s exit:0 -o match:Bye=bye-bye -e empty \ 635 ${TEST_SH} 636 637 cat <<- 'DONE' | 638 for arg in one-4 two-24 three-14 639 do 640 fd=${arg#*-} 641 file=${arg%-*} 642 eval "exec ${fd}>${file}" 643 done 644 645 for arg in one-5 two-7 three-19 646 do 647 fd=${arg#*-} 648 file=${arg%-*} 649 eval "exec ${fd}<${file}" 650 done 651 652 ( 653 echo line-1 >&4 654 echo line-2 >&24 655 echo line-3 >&14 656 echo go 657 ) | ( 658 read go 659 read x <&5 660 read y <&7 661 read z <&19 662 663 printf "%s\n" "${x}" "${y}" "${z}" 664 ) 665 DONE 666 atf_check -s exit:0 -o inline:'line-1\nline-2\nline-3\n' \ 667 -e empty ${TEST_SH} 668 669 cat <<- 'DONE' | 670 for arg in one-4-5 two-6-7 three-8-9 four-11-10 five-3-12 671 do 672 ofd=${arg##*-} 673 file=${arg%-*} 674 ifd=${file#*-} 675 file=${file%-*} 676 eval "exec ${ofd}>${file}" 677 eval "exec ${ifd}<${file}" 678 done 679 680 ( ( ( echo line-1 >& 13 ) 13>&12 ) 12>&5 ) >stdout 2>errout 681 ( ( ( echo line-2 >& 4) 13>&12 ) 4>&7 ) >>stdout 2>>errout 682 ( ( ( echo line-3 >& 6) 8>&1 6>&11 >&12) 11>&9 >&7 ) >>stdout 683 684 ( ( ( cat <&13 >&12 ) 13<&8 12>&10 ) 10>&1 8<&6 ) 6<&4 685 ( ( ( cat <&4 ) <&4 6<&8 8<&11 ) 686 <&4 4<&6 6<&8 8<&11 ) <&4 4<&6 6<&8 8<&11 11<&3 687 ( ( ( cat <&7 >&1 ) 7<&6 >&10 ) 10>&2 6<&8 ) 2>&1 688 DONE 689 atf_check -s exit:0 -o inline:'line-1\nline-2\nline-3\n' \ 690 -e empty ${TEST_SH} 691} 692 693atf_test_case ulimit_redirection_interaction 694ulimit_redirection_interaction_head() 695{ 696 atf_set "descr" "Tests interactions between redirect and ulimit -n " 697} 698ulimit_redirection_interaction_body() 699{ 700 atf_require_prog ls 701 702 cat <<- 'DONE' > helper.sh 703 oLIM=$(ulimit -n) 704 HRD=$(ulimit -H -n) 705 test "${oLIM}" -lt "${HRD}" && ulimit -n "${HRD}" 706 LIM=$(ulimit -n) 707 708 FDs= 709 LFD=-1 710 while [ ${LIM} -gt 16 ] 711 do 712 FD=$(( ${LIM} - 1 )) 713 if [ "${FD}" -eq "${LFD}" ]; then 714 echo >&2 "Infinite loop... (busted $(( )) ??)" 715 exit 1 716 fi 717 LFD="${FD}" 718 719 eval "exec ${FD}"'> /dev/null' 720 FDs="${FD}${FDs:+ }${FDs}" 721 722 ( 723 FD=$(( ${LIM} + 1 )) 724 eval "exec ${FD}"'> /dev/null' 725 echo "Reached unreachable command" 726 ) 2>/dev/null && echo >&2 "Opened beyond limit!" 727 728 (eval 'ls 2>&1 3>&1 4>&1 5>&1 '"${FD}"'>&1') >&"${FD}" 729 730 LIM=$(( ${LIM} / 2 )) 731 ulimit -S -n "${LIM}" 732 done 733 734 # Even though ulimit has been reduced, open fds should work 735 for FD in ${FDs} 736 do 737 echo ${FD} in ${FDs} >&"${FD}" || exit 1 738 done 739 740 ulimit -S -n "${oLIM}" 741 742 # maybe more later... 743 744 DONE 745 746 atf_check -s exit:0 -o empty -e empty ${TEST_SH} helper.sh 747} 748 749atf_test_case validate_fn_redirects 750validate_fn_redirects_head() 751{ 752 # These test cases inspired by PR bin/48875 and the sh 753 # changes that were required to fix it. 754 755 atf_set "descr" "Tests various redirections applied to functions " \ 756 "See PR bin/48875" 757} 758validate_fn_redirects_body() 759{ 760 cat <<- 'DONE' > f-def 761 f() { 762 printf '%s\n' In-Func 763 } 764 DONE 765 766 atf_check -s exit:0 -o inline:'In-Func\nsuccess1\n' -e empty \ 767 ${TEST_SH} -c ". ./f-def; f ; printf '%s\n' success1" 768 atf_check -s exit:0 -o inline:'success2\n' -e empty \ 769 ${TEST_SH} -c ". ./f-def; f >/dev/null; printf '%s\n' success2" 770 atf_check -s exit:0 -o inline:'success3\n' -e empty \ 771 ${TEST_SH} -c ". ./f-def; f >&- ; printf '%s\n' success3" 772 atf_check -s exit:0 -o inline:'In-Func\nsuccess4\n' -e empty \ 773 ${TEST_SH} -c ". ./f-def; f & wait; printf '%s\n' success4" 774 atf_check -s exit:0 -o inline:'success5\n' -e empty \ 775 ${TEST_SH} -c ". ./f-def; f >&- & wait; printf '%s\n' success5" 776 atf_check -s exit:0 -o inline:'In-Func\nIn-Func\nsuccess6\n' -e empty \ 777 ${TEST_SH} -c ". ./f-def; f;f; printf '%s\n' success6" 778 atf_check -s exit:0 -o inline:'In-Func\nIn-Func\nsuccess7\n' -e empty \ 779 ${TEST_SH} -c ". ./f-def; { f;f;}; printf '%s\n' success7" 780 atf_check -s exit:0 -o inline:'In-Func\nIn-Func\nsuccess8\n' -e empty \ 781 ${TEST_SH} -c ". ./f-def; { f;f;}& wait; printf '%s\n' success8" 782 atf_check -s exit:0 -o inline:'In-Func\nsuccess9\n' -e empty \ 783 ${TEST_SH} -c \ 784 ". ./f-def; { f>/dev/null;f;}& wait; printf '%s\n' success9" 785 atf_check -s exit:0 -o inline:'In-Func\nsuccess10\n' -e empty \ 786 ${TEST_SH} -c \ 787 ". ./f-def; { f;f>/dev/null;}& wait; printf '%s\n' success10" 788 789 # This one tests the issue etcupdate had with the original 48875 fix 790 atf_check -s exit:0 -o inline:'Func a\nFunc b\nFunc c\n' -e empty \ 791 ${TEST_SH} -c ' 792 f() { 793 echo Func "$1" 794 } 795 exec 3<&0 4>&1 796 ( echo x-a; echo y-b; echo z-c ) | 797 while read A 798 do 799 B=${A#?-} 800 f "$B" <&3 >&4 801 done >&2' 802 803 # And this tests a similar condition with that same fix 804 cat <<- 'DONE' >Script 805 f() { 806 printf '%s' " hello $1" 807 } 808 exec 3>&1 809 echo $( for i in a b c 810 do printf '%s' @$i; f $i >&3; done >foo 811 ) 812 printf '%s\n' foo=$(cat foo) 813 DONE 814 atf_check -s exit:0 -e empty \ 815 -o inline:' hello a hello b hello c\nfoo=@a@b@c\n' \ 816 ${TEST_SH} Script 817 818 # Tests with sh reading stdin, which is not quite the same internal 819 # mechanism. 820 echo ". ./f-def || echo >&2 FAIL 821 f 822 printf '%s\n' stdin1 823 "| atf_check -s exit:0 -o inline:'In-Func\nstdin1\n' -e empty ${TEST_SH} 824 825 echo ' 826 . ./f-def || echo >&2 FAIL 827 f >&- 828 printf "%s\n" stdin2 829 ' | atf_check -s exit:0 -o inline:'stdin2\n' -e empty ${TEST_SH} 830 831 cat <<- 'DONE' > fgh.def 832 f() { 833 echo -n f >&3 834 sleep 4 835 echo -n F >&3 836 } 837 g() { 838 echo -n g >&3 839 sleep 2 840 echo -n G >&3 841 } 842 h() { 843 echo -n h >&3 844 } 845 DONE 846 847 atf_check -s exit:0 -o inline:'fFgGh' -e empty \ 848 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL 849 exec 3>&1 850 f; g; h' 851 852 atf_check -s exit:0 -o inline:'fghGF' -e empty \ 853 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL 854 exec 3>&1 855 f & sleep 1; g & sleep 1; h; wait' 856 857 atf_check -s exit:0 -o inline:'fFgGhX Y\n' -e empty \ 858 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL 859 exec 3>&1 860 echo X $( f ; g ; h ) Y' 861 862 # This one is the real test for PR bin/48875. If the 863 # cmdsub does not complete before f g (and h) exit, 864 # then the 'F' & 'G' will precede 'X Y' in the output. 865 # If the cmdsub finishes while f & g are still running, 866 # then the X Y will appear before the F and G. 867 # The trailing "sleep 3" is just so we catch all the 868 # output (otherwise atf_check will be finished while 869 # f & g are still sleeping). 870 871 atf_check -s exit:0 -o inline:'fghX Y\nGF' -e empty \ 872 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL 873 exec 3>&1 874 echo X $( f >&- & sleep 1; g >&- & sleep 1 ; h ) Y 875 sleep 3 876 exec 4>&1 || echo FD_FAIL 877 ' 878 879 # Do the test again to verify it also all works reading stdin 880 # (which is a slightly different path through the shell) 881 echo ' 882 . ./fgh.def || echo >&2 FAIL 883 exec 3>&1 884 echo X $( f >&- & sleep 1; g >&- & sleep 1 ; h ) Y 885 sleep 3 886 exec 4>&1 || echo FD_FAIL 887 ' | atf_check -s exit:0 -o inline:'fghX Y\nGF' -e empty ${TEST_SH} 888} 889 890atf_init_test_cases() { 891 atf_add_test_case basic_test_method_test 892 atf_add_test_case do_input_redirections 893 atf_add_test_case do_output_redirections 894 atf_add_test_case fd_redirections 895 atf_add_test_case local_redirections 896 atf_add_test_case incorrect_redirections 897 atf_add_test_case named_fd_redirections 898 atf_add_test_case redir_here_doc 899 atf_add_test_case redir_in_case 900 atf_add_test_case subshell_redirections 901 atf_add_test_case ulimit_redirection_interaction 902 atf_add_test_case validate_fn_redirects 903} 904