mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-02-13 11:42:21 +00:00
Fix BUG_PUTIOERR: Check for and report I/O error in output builtins
This allows scripts to check for a nonzero exit status on the 'print', 'printf' and 'echo' builtins and prevent possible infinite loops if SIGPIPE is ignored. sfsync() was already returning a negative value on I/O error, so all we need to do is add a check. The stream buffer will need to be filled before an I/O error can be detected, but this is the same on other shells. See manual page: src/lib/libast/man/sfio.3 Ref.: https://github.com/att/ast/issues/1093 https://github.com/att/ast/pull/1363 src/cmd/ksh93/bltins/print.c: b_print(): - Make sure an error result from sfsync() is reflected in the output builtin's exit status (exitval). - Write an I/O error message (e_io) if the exit status is nonzero. src/cmd/ksh93/data/msg.c, src/cmd/ksh93/include/io.h: - Add the e_io[] error message. src/cmd/ksh93/tests/builtins.sh: - Add I/O error regression test, checking for the correct error message and exit status. All three output builtins use the same b_print() function so we only need to test one. src/cmd/ksh93/tests/basic.sh, src/cmd/ksh93/tests/coprocess.sh: - Redirect stderr on a few 'print' commands to /dev/null; these now issue an expected I/O error. This does not cause failures. NEWS, TODO: - Update. (cherry picked from commit 9011fa933552e483dab460f7dd1593d64e059d94)
This commit is contained in:
parent
846ad93272
commit
93e15a3035
8 changed files with 45 additions and 13 deletions
5
NEWS
5
NEWS
|
@ -12,6 +12,11 @@ Any uppercase BUG_* names are modernish shell bug IDs.
|
||||||
Ref.: https://github.com/att/ast/issues/425
|
Ref.: https://github.com/att/ast/issues/425
|
||||||
https://github.com/att/ast/pull/442
|
https://github.com/att/ast/pull/442
|
||||||
|
|
||||||
|
- Fix BUG_PUTIOERR: Output builtins now correctly detect and report
|
||||||
|
input/output errors. This allows scripts to check for a nonzero exit
|
||||||
|
status on the 'print', 'printf' and 'echo' builtins and prevent possible
|
||||||
|
infinite loops if SIGPIPE is ignored.
|
||||||
|
|
||||||
2020-05-13:
|
2020-05-13:
|
||||||
|
|
||||||
- Fix BUG_CASELIT: an undocumented 'case' pattern matching misbehaviour that
|
- Fix BUG_CASELIT: an undocumented 'case' pattern matching misbehaviour that
|
||||||
|
|
5
TODO
5
TODO
|
@ -92,10 +92,5 @@ https://github.com/modernish/modernish/tree/0.16/lib/modernish/cap/
|
||||||
example, "$*" joins positional parameters on the first byte of IFS instead
|
example, "$*" joins positional parameters on the first byte of IFS instead
|
||||||
of the first character.
|
of the first character.
|
||||||
|
|
||||||
- BUG_PUTIOERR: Shell builtins that output strings (echo, printf, ksh/zsh
|
|
||||||
print), and thus also modernish put and putln, do not check for I/O errors
|
|
||||||
on output. This means a script cannot check for them, and a script process
|
|
||||||
in a pipe can get stuck in an infinite loop if SIGPIPE is ignored.
|
|
||||||
|
|
||||||
- BUG_TESTERR1A: test/[ exits with a non-error false status (1) if an
|
- BUG_TESTERR1A: test/[ exits with a non-error false status (1) if an
|
||||||
invalid argument is given to an operator.
|
invalid argument is given to an operator.
|
||||||
|
|
|
@ -336,9 +336,11 @@ skip2:
|
||||||
* https://github.com/att/ast/issues/425
|
* https://github.com/att/ast/issues/425
|
||||||
*/
|
*/
|
||||||
if(!sflag && sffileno(outfile)!=sffileno(sfstderr))
|
if(!sflag && sffileno(outfile)!=sffileno(sfstderr))
|
||||||
sfsync(outfile);
|
if (sfsync(outfile) < 0)
|
||||||
|
exitval = 1;
|
||||||
sfpool(sfstderr,pool,SF_WRITE);
|
sfpool(sfstderr,pool,SF_WRITE);
|
||||||
exitval = pdata.err;
|
if (pdata.err)
|
||||||
|
exitval = 1;
|
||||||
}
|
}
|
||||||
else if(vflag)
|
else if(vflag)
|
||||||
{
|
{
|
||||||
|
@ -353,7 +355,10 @@ skip2:
|
||||||
{
|
{
|
||||||
/* echo style print */
|
/* echo style print */
|
||||||
if(nflag && !argv[0])
|
if(nflag && !argv[0])
|
||||||
sfsync((Sfio_t*)0);
|
{
|
||||||
|
if (sfsync((Sfio_t*)0) < 0)
|
||||||
|
exitval = 1;
|
||||||
|
}
|
||||||
else if(sh_echolist(shp,outfile,rflag,argv) && !nflag)
|
else if(sh_echolist(shp,outfile,rflag,argv) && !nflag)
|
||||||
sfputc(outfile,'\n');
|
sfputc(outfile,'\n');
|
||||||
}
|
}
|
||||||
|
@ -365,8 +370,11 @@ skip2:
|
||||||
else if(n&SF_SHARE)
|
else if(n&SF_SHARE)
|
||||||
{
|
{
|
||||||
sfset(outfile,SF_SHARE|SF_PUBLIC,1);
|
sfset(outfile,SF_SHARE|SF_PUBLIC,1);
|
||||||
sfsync(outfile);
|
if (sfsync(outfile) < 0)
|
||||||
|
exitval = 1;
|
||||||
}
|
}
|
||||||
|
if (exitval)
|
||||||
|
errormsg(SH_DICT, 2, e_io);
|
||||||
return(exitval);
|
return(exitval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,7 @@ const char e_access[] = "permission denied";
|
||||||
const char e_direct[] = "bad directory";
|
const char e_direct[] = "bad directory";
|
||||||
const char e_file[] = "%s: bad file unit number";
|
const char e_file[] = "%s: bad file unit number";
|
||||||
const char e_redirect[] = "redirection failed";
|
const char e_redirect[] = "redirection failed";
|
||||||
|
const char e_io[] = "I/O error";
|
||||||
const char e_trap[] = "%s: bad trap";
|
const char e_trap[] = "%s: bad trap";
|
||||||
const char e_readonly[] = "%s: is read only";
|
const char e_readonly[] = "%s: is read only";
|
||||||
const char e_badfield[] = "%d: negative field size";
|
const char e_badfield[] = "%d: negative field size";
|
||||||
|
|
|
@ -97,6 +97,7 @@ extern const char e_tmpcreate[];
|
||||||
extern const char e_exists[];
|
extern const char e_exists[];
|
||||||
extern const char e_file[];
|
extern const char e_file[];
|
||||||
extern const char e_redirect[];
|
extern const char e_redirect[];
|
||||||
|
extern const char e_io[];
|
||||||
extern const char e_formspec[];
|
extern const char e_formspec[];
|
||||||
extern const char e_badregexp[];
|
extern const char e_badregexp[];
|
||||||
extern const char e_open[];
|
extern const char e_open[];
|
||||||
|
|
|
@ -431,7 +431,7 @@ done | while read sec; do ( $sleep $sec; $sleep $sec) done
|
||||||
s=SECONDS
|
s=SECONDS
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
for ((i=0; i < 30; i++))
|
for ((i=0; i < 30; i++))
|
||||||
do print hello
|
do print hello 2>/dev/null
|
||||||
sleep .1
|
sleep .1
|
||||||
done | $sleep 1
|
done | $sleep 1
|
||||||
(( (SECONDS-s) < 2 )) || err_exit 'early termination not causing broken pipe'
|
(( (SECONDS-s) < 2 )) || err_exit 'early termination not causing broken pipe'
|
||||||
|
@ -470,7 +470,7 @@ bintrue=$(whence -p true)
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
float start=$SECONDS end
|
float start=$SECONDS end
|
||||||
for ((i=0; i < 2; i++))
|
for ((i=0; i < 2; i++))
|
||||||
do print foo
|
do print foo 2>/dev/null
|
||||||
sleep 1.5
|
sleep 1.5
|
||||||
done | { read; $bintrue; end=$SECONDS ;}
|
done | { read; $bintrue; end=$SECONDS ;}
|
||||||
(( (SECONDS-start) < 1 )) && err_exit "pipefail not waiting for pipe to finish"
|
(( (SECONDS-start) < 1 )) && err_exit "pipefail not waiting for pipe to finish"
|
||||||
|
|
|
@ -639,4 +639,26 @@ read baz <<< 'foo\\\\bar'
|
||||||
: ~root
|
: ~root
|
||||||
[[ $(builtin) == *.sh.tilde* ]] && err_exit 'builtin contains .sh.tilde'
|
[[ $(builtin) == *.sh.tilde* ]] && err_exit 'builtin contains .sh.tilde'
|
||||||
|
|
||||||
|
# ======
|
||||||
|
# Check that I/O errors are detected <https://github.com/att/ast/issues/1093>
|
||||||
|
actual=$(
|
||||||
|
{
|
||||||
|
(
|
||||||
|
trap "" PIPE
|
||||||
|
for ((i = SECONDS + 1; SECONDS < i; )); do
|
||||||
|
print hi || {
|
||||||
|
print $? >&2
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
done
|
||||||
|
) | true
|
||||||
|
} 2>&1
|
||||||
|
)
|
||||||
|
expect=$': print: I/O error\n1'
|
||||||
|
if [[ $actual != *"$expect" ]]
|
||||||
|
then
|
||||||
|
err_exit "I/O error not detected (expected '$expect', got '$actual')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ======
|
||||||
exit $((Errors<125?Errors:125))
|
exit $((Errors<125?Errors:125))
|
||||||
|
|
|
@ -266,7 +266,7 @@ _COSHELL_msgfd=5
|
||||||
function cop
|
function cop
|
||||||
{
|
{
|
||||||
read
|
read
|
||||||
print ok
|
print ok 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
exp=ok
|
exp=ok
|
||||||
|
@ -342,7 +342,7 @@ wait
|
||||||
function cop
|
function cop
|
||||||
{
|
{
|
||||||
read
|
read
|
||||||
print ok
|
print ok 2>/dev/null
|
||||||
}
|
}
|
||||||
exp=ok
|
exp=ok
|
||||||
cop |&
|
cop |&
|
||||||
|
|
Loading…
Reference in a new issue