Date: Tue, 4 May 2021 09:28:04 -0400 From: Chet Ramey <chet.ra...@case.edu> Message-ID: <c8b1b097-d430-e840-017d-52a1a6a39...@case.edu>
| The issue with the BSDs and terminal devices is that the current code | only checks for -1/ESPIPE, but they return a different value for errno | (EINVAL? I forget.) On traditional unix, since forever, lseek() on a terminal is simply a no-op. (The seek() sys call that preceded it, on 6th edition and earlier was the same.) No error, no effect -- or no useful effect, the "file offset" might get set, so you can't even: pos = lseek(0,somewhere,0); if (lseek(0, pos, 0) != somewhere) /* unseekable */ as that would probably (seem to) succeed, but terminals don't use it. jinx$ cat /tmp/t.c main() { if (lseek(0, 0L, 0) < 0) perror("lseek"); exit(0); } jinx$ # ignore the gcc warnings when compiling this nonsense... jinx$ /tmp/t jinx$ (stdin was the terminal) jinx$ /tmp/t < /etc/motd jinx$ cat /etc/motd | /tmp/t lseek: Illegal seek jinx$ If you want to add this optimisation, just fstat(0, &...) and check for it being a regular file. If it is, then check if lseek will work (pipes tend to masquerade as files in some systems when examined this way). Otherwise fall back to byte at a time reads. (The \n delimiter special case just optimises for terminal input, where one line max is all you get, but that doesn't help if you want to end the read on some other delimiter). You could optimise block devices (and yes, even the block device interface to a tape drive, seek works there - I once ran the root filesystem from a 9 track (reel to reel) tape (read only of course) - slow, but it worked. But why would anyone care? What would be the use case for sh's "read" from a block device? Just leave that slow for anyone weird enough to try it. But block devices are for housing filesystems, which requires the ability to seek, so by definition, any block device must support seek. kre