From owner-freebsd-hackers@FreeBSD.ORG Wed Nov 16 10:31:44 2011 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 1233) id 73D1C106566B; Wed, 16 Nov 2011 10:31:44 +0000 (UTC) Date: Wed, 16 Nov 2011 10:31:44 +0000 From: Alexander Best To: Brandon Gooch Message-ID: <20111116103144.GA22928@freebsd.org> References: <20111115202450.GA73512@freebsd.org> <20111116101422.GA20453@freebsd.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="tThc/1wpZn/ma/RB" Content-Disposition: inline In-Reply-To: <20111116101422.GA20453@freebsd.org> Cc: freebsd-hackers@freebsd.org Subject: Re: easy way to determine if a stream or fd is seekable X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 16 Nov 2011 10:31:44 -0000 --tThc/1wpZn/ma/RB Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Wed Nov 16 11, Alexander Best wrote: > On Tue Nov 15 11, Brandon Gooch wrote: > > On Nov 15, 2011 2:25 PM, "Alexander Best" wrote: > > > > > > hi there, > > > > > > one of the things i'm missing is an easy way to determine, whether a > > stream or > > > fd is seekable. i checked the dd(1) and hd(1) sources and those tools are > > > performing so much stuff just to find out if this is the case, and they > > still > > > are doing a very poor job. > > > > > > dd(1) e.g. identifies /dev/zero as non-seekable, even though it is. the > > result: > > > > > > `dd if=/dev/zero bs=1m count=1 skip=100000`: > > > > > > on freebsd: > > > 57,41 real 0,05 user 43,21 sys > > > > > > on openbsd: > > > 0,88 real 0,00 user 0,07 sys > > > > > > on freebsd dd(1) is very easy fixable (1 line diff). the point however is: > > > > > > there doesn't seem to exist a unified way of checking seekable == TRUE. so > > > every userspace application seems to do it differently and most of them > > (dd(1) > > > and hd(1) e.g) aren't doing it right. hd(1) e.g. believes that only > > regular > > > files are seekable. this means that hd(1) fired at /dev/ada* with a high > > skip > > > value takes ages! dd(1) is a bit smarter in this case, but still not > > correct. > > > > > > idealy there would be something like stat.st_mode (see stat(2)) where one > > > could simply do a S_ISSEEK(m). so far the best and easiest solution i've > > seen > > > is: > > > > > > fd = open(argv[1], O_RDONLY); > > > if (fd == -1) > > > exit(1); > > > if (lseek(fd, 0, SEEK_CUR) != -1) > > > printf ("%d is seekable.\n", fd); > > > else > > > printf ("%d is not seekable.\n", fd); > > > > > > seeing an application iterate through a stream or fd via getchar(), > > although > > > a simple seek() would work is very frustrating. i think what would be > > needed > > > is a simple function or macro that userspace applications can make use of. > > > maybe such a thing already exists in linux, openbsd, netbsd, dragonflybsd, > > > solaris or plan9? > > > > > > cheers. > > > alex > > > > > > references: > > > [1] > > http://www.mavetju.org/mail/view_thread.php?list=freebsd-hackers&id=3290708&thread=yes > > > [2] http://www.freebsd.org/cgi/query-pr.cgi?pr=152485 > > > [3] http://www.freebsd.org/cgi/query-pr.cgi?pr=86485 > > > > So, according to APUE 2nd Edition, seek should be supported on anything > > that's not a pipe, FIFO, or socket. In fact, the "test for seekability" > > you've provided above closely resembles the example given in that text. > > if this really is the case, things could even be easier in a freebsd specific > manor than the code above: > > !S_ISFIFO(m) && !S_ISSOCK(m) > > this means it would be trivial to write a new macro S_ISSEEK which would test > stat.st_mode against the according bits. here's a patch, which also fixes a comment. cheers. alex > > cheers. > alex > > > > > Need to think about this more before commenting further... > > > > -Brandon --tThc/1wpZn/ma/RB Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="stat.h.diff" diff --git a/sys/sys/stat.h b/sys/sys/stat.h index 1b03bd2..ab5ae44 100644 --- a/sys/sys/stat.h +++ b/sys/sys/stat.h @@ -238,10 +238,11 @@ struct nstat { #define S_ISCHR(m) (((m) & 0170000) == 0020000) /* char special */ #define S_ISBLK(m) (((m) & 0170000) == 0060000) /* block special */ #define S_ISREG(m) (((m) & 0170000) == 0100000) /* regular file */ -#define S_ISFIFO(m) (((m) & 0170000) == 0010000) /* fifo or socket */ +#define S_ISFIFO(m) (((m) & 0170000) == 0010000) /* pipe or fifo */ #if __POSIX_VISIBLE >= 200112 #define S_ISLNK(m) (((m) & 0170000) == 0120000) /* symbolic link */ #define S_ISSOCK(m) (((m) & 0170000) == 0140000) /* socket */ +#define S_ISSEEK(m) (((m) & 0150000) == 0) /* seekable file */ #endif #if __BSD_VISIBLE #define S_ISWHT(m) (((m) & 0170000) == 0160000) /* whiteout */ --tThc/1wpZn/ma/RB--