From 416a412d710f40c69fc77706fafad4515ea16e9b Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Tue, 28 Jun 2022 20:16:31 +0300 Subject: [PATCH] Fix seeking on block devices with FD 0, 1 or 2 @stephane-chazelas reports: > A very weird issue: > > To reproduce on GNU/Linux (here as superuser) > > # truncate -s10M file > # export DEV="$(losetup -f --show file)" > # ksh -c 'exec 3<> "$DEV" 3>#((0))' # fine > # ksh -c 'exec 1<> file 1>#((0))' # fine > # ksh -c 'exec 1<> "$DEV" 1>#((0))' > ksh: 0: invalid seek offset > > Any seek offset is considered "invalid" as long as the file is a > block device and the fd is 0, 1 or 2. It's fine for fds above 2 > and it's fine with any fd for regular files. Apparently, block devices are not seekable with sfio. In io.c there is specific code to avoid using sfio's sfseek(3) if there is no sfio stream in sh.sftable[] for the file descriptor in question: 1398: Sfio_t *sp = sh.sftable[fn]; [...] 1420: if(sp) 1421: { 1422: off=sfseek(sp, off, SEEK_SET); 1423: sfsync(sp); 1424: } 1425: else 1426: off=lseek(fn, off, SEEK_SET); For file descriptors 0, 1 or 2 (stdin/stdout/stderr), there is a sh.sftable[] stream by default, and it is marked as not seekable. This makes it return -1 in these lines in sfseek.c, even if the system call called via SFSK() succeeds: 89: if(f->extent < 0) 90: { /* let system call set errno */ 91: (void)SFSK(f,(Sfoff_t)0,SEEK_CUR,f->disc); 92: return (Sfoff_t)(-1); 93: } ...which explains the strange behaviour. src/lib/libast/sfio/sfseek.c: sfseek(): - Allow for the possibility that the fallback system call might succeed: let it handle both errno and the return value. Resolves: https://github.com/ksh93/ksh/issues/318 --- NEWS | 6 ++++++ src/cmd/ksh93/include/version.h | 2 +- src/lib/libast/sfio/sfseek.c | 5 ++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 258481890..e2cbfab54 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,12 @@ For full details, see the git log at: https://github.com/ksh93/ksh/tree/1.0 Any uppercase BUG_* names are modernish shell bug IDs. +2022-06-28: + +- Fixed a bug that caused the <#((num)) or >#((num)) arithmetic seek + redirection operator to fail if used with file descriptor 0, 1 or 2 + connected to a block device. + 2022-06-22: - Fixed: 'echo' failed when used inside a command substitution that diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index 8f918ada4..6c331703f 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -23,7 +23,7 @@ #define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */ #define SH_RELEASE_SVER "1.0.0-beta.2" /* semantic version number: https://semver.org */ -#define SH_RELEASE_DATE "2022-06-22" /* must be in this format for $((.sh.version)) */ +#define SH_RELEASE_DATE "2022-06-28" /* must be in this format for $((.sh.version)) */ #define SH_RELEASE_CPYR "(c) 2020-2022 Contributors to ksh " SH_RELEASE_FORK /* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */ diff --git a/src/lib/libast/sfio/sfseek.c b/src/lib/libast/sfio/sfseek.c index 651cdee3e..271ad977a 100644 --- a/src/lib/libast/sfio/sfseek.c +++ b/src/lib/libast/sfio/sfseek.c @@ -87,9 +87,8 @@ Sfoff_t sfseek(Sfio_t* f, /* seek to a new location in this stream */ } if(f->extent < 0) - { /* let system call set errno */ - (void)SFSK(f,(Sfoff_t)0,SEEK_CUR,f->disc); - return (Sfoff_t)(-1); + { /* not seekable with sfio: let the system call either set errno or succeed */ + return SFSK(f,p,type,f->disc); } /* throw away ungetc data */