[parisc-linux] Re: pipes

Richard Hirst rhirst@linuxcare.com
Mon, 26 Feb 2001 17:57:01 +0000


This is looking like a glibc/kernel issue regardling the width
of the type returned by lseek():


I have a simple way of reproducing the bug now:

merlin:/build# echo 'if ( test  -r /dev/null ); then echo TRUE; fi;
echo Oops' | /bin/sh
TRUE
merlin:/build#


The echo parameter is split over two lines there, and should result
in two lines of output 'TRUE' and then 'Oops'.

/bin/sh picks up input with one read of 57 characters, and then
processes the string, char by char, via input.c:buffered_getchar(),
until it has the complete if..then..fi\n (about 46 characters). Then it
tries to stuff input following the 'fi\n' back on to the input stream by
doing an lseek(fd, -n, SEEK_CUR), before forking a child to do the
'test'.  On return from the child, it expects to pick up the input it
stuffed back on to the input stream.

The problem is that the input stream is a pipe, and lseek doesn't work.
bash should have decided that its input stream was not seekable and
dropped back to multiple reads of one byte.  It uses this test:

#  define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)

and then

  if (fd_is_seekable (fd) == 0)
    size = 1;
  else
    size = (size_t)((sb.st_size > MAX_INPUT_BUFFER_SIZE) ? ...


Now for us lseek is of type __off64_t (from /usr/include/unistd.h),
although our kernel has sys_lseek() returning off_t, which is 32
bits.  Anyway, if I try to print the 64 bit return value from lseek()
I get 0x00000000ffffffe3.  The lower 32 bits is -ESPIPE, which is the
expected errno.  I don't know if glibc, kernel, or both are at fault
here.

Richard