I have attached a patch. It's pretty lame, though: what it does is read the fifo file into a buffer (and execute it). On the other hand, bash already read the sourced file into a buffer, so I guess I'm no worse at working around crufty design than the average bash hacker.
I also added two test cases which check that bash DTRT WRT sourcing fifos. I also added the --norc and --noprofile flags to an invocation in a test case (my output differed, because I eat fortune cookies in my ~/.bashrc), something which is unrelated to fifo sourcing, but needed doing :) -- An OS is like god, but without the beard Jonas Kölker <[EMAIL PROTECTED]> <URL:http://jonaskoelker.homeunix.org/>
diff -ru orig/bash-3.1/bash-3.1/builtins/evalfile.c patched/bash-3.1/bash-3.1/builtins/evalfile.c --- orig/bash-3.1/bash-3.1/builtins/evalfile.c 2004-11-27 20:07:12.000000000 +0100 +++ patched/bash-3.1/bash-3.1/builtins/evalfile.c 2006-11-17 21:34:35.000000000 +0100 @@ -103,7 +103,7 @@ GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a); # endif #endif - + fd = open (filename, O_RDONLY); if (fd < 0 || (fstat (fd, &finfo) == -1)) @@ -139,6 +139,7 @@ /* Check for overflow with large files. */ if (file_size != finfo.st_size || file_size + 1 < file_size) { + file_too_large: (*errfunc) (_("%s: file is too large"), filename); return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1); } @@ -147,13 +148,51 @@ setmode (fd, O_TEXT); #endif - string = (char *)xmalloc (1 + file_size); - result = read (fd, string, file_size); - string[result] = '\0'; - - return_val = errno; - close (fd); - errno = return_val; + if (S_ISFIFO (finfo.st_mode) == 0) + { + string = (char *)xmalloc (1 + file_size); + result = read (fd, string, file_size); + string[result] = '\0'; + + close_with_errno: + return_val = errno; + close (fd); + errno = return_val; + } + /* we can't slurp a fifo (linux sez 5Bfile_size is zero) so we ask + * read instead of stat; this requires a growing buffer. */ + else + { + size_t used = 0; + size_t buffer_size = 3; + string = xmalloc (buffer_size); + string[0] = '\0'; + while (1) + { + errno = 0; + result = read (fd, string + used, buffer_size - used - 1); + if (result < 0) + goto close_with_errno; + else if (result == 0) + { + string[used] = '\0'; + close (fd); + break; + } + used += result; + if (used + 1 == buffer_size) /* buffer full: grow it */ + { + const size_t newsize = 2 * buffer_size + 1; + if (buffer_size >= newsize) + { + free(string); + goto file_too_large; + } + buffer_size = newsize; + string = xrealloc(string, buffer_size); + } + } + } if (result < 0) /* XXX was != file_size, not < 0 */ { @@ -161,7 +200,7 @@ goto file_error_and_exit; } - if (result == 0) + if (result == 0 && S_ISFIFO (finfo.st_mode) == 0) { free (string); return ((flags & FEVAL_BUILTIN) ? EXECUTION_SUCCESS : 1); Only in patched/bash-3.1/bash-3.1/builtins: evalfile.c~ diff -ru orig/bash-3.1/bash-3.1/tests/builtins.right patched/bash-3.1/bash-3.1/tests/builtins.right --- orig/bash-3.1/bash-3.1/tests/builtins.right 2005-02-28 15:12:27.000000000 +0100 +++ patched/bash-3.1/bash-3.1/tests/builtins.right 2006-11-17 21:32:58.000000000 +0100 @@ -108,6 +108,8 @@ ./source5.sub: line 10: /tmp/source-notthere: No such file or directory after bad source 1 ./source5.sub: line 17: /tmp/source-notthere: No such file or directory +sourcing a pipe: success (this is echoed) +sourcing a pipe: success (I got no sigpipe) AVAR foo foo @@ -118,15 +120,15 @@ foo declare -x foo="" declare -x FOO="\$\$" -./builtins.tests: line 207: declare: FOO: not found +./builtins.tests: line 229: declare: FOO: not found declare -x FOO="\$\$" ok ok -./builtins.tests: line 239: kill: 4096: invalid signal specification +./builtins.tests: line 261: kill: 4096: invalid signal specification 1 a\n\n\nb a b -./builtins.tests: line 248: exit: status: numeric argument required +./builtins.tests: line 270: exit: status: numeric argument required diff -ru orig/bash-3.1/bash-3.1/tests/builtins.tests patched/bash-3.1/bash-3.1/tests/builtins.tests --- orig/bash-3.1/bash-3.1/tests/builtins.tests 2003-01-14 17:09:26.000000000 +0100 +++ patched/bash-3.1/bash-3.1/tests/builtins.tests 2006-11-17 21:32:52.000000000 +0100 @@ -108,8 +108,8 @@ esac # test options to exec -(exec -a specialname ${THIS_SH} -c 'echo $0' ) -(exec -l -a specialname ${THIS_SH} -c 'echo $0' ) +(exec -a specialname ${THIS_SH} --norc --noprofile -c 'echo $0' ) +(exec -l -a specialname ${THIS_SH} --norc --noprofile -c 'echo $0' ) # test `clean' environment. if /bin/sh is bash, and the script version of # printenv is run, there will be variables in the environment that bash # sets on startup. Also test code that prefixes argv[0] with a dash. @@ -176,6 +176,28 @@ # test behavior of `.' when given a non-existant file argument ${THIS_SH} ./source5.sub +# test behavior of `.' when trying to source a fifo file +PIPE=/tmp/fifo-for-testing-bash-$$ +if mkfifo $PIPE; then trap "rm $PIPE" exit; else exit; fi + +# this doesn't cause sigpipe in version (n - 1) +echo 'echo sourcing a pipe: success "(this is echoed)"' > $PIPE & +source $PIPE +wait + +# this *does* cause sigpipe in version (n - 1) +write_or_sigpipe() { + trap 'echo sourcing a pipe: failure "(sigpipe recieved)"' SIGPIPE + echo 'echo sourcing a pipe: success "(I got no sigpipe)"' > $PIPE +} + +# n = 1 + "GNU bash, version 3.1.17(1)-release (i486-pc-linux-gnu)" +# (apt-get source bash; `dpkg -l bash' says version is "3.1-5") + +write_or_sigpipe & +source $PIPE +wait + # in posix mode, assignment statements preceding special builtins are # reflected in the shell environment. `.' and `eval' need special-case # code.
signature.asc
Description: Digital signature