>Submitter-Id: net >Originator: Jim Meyering >Confidential: no >Synopsis: lseek returns N>0 even though underlying _llseek fails and returns 0 >Severity: non-critical >Priority: medium >Category: libc >Class: sw-bug >Release: libc-2.2.4 >Environment: <machine, os, target, libraries (multiple lines)> Host type: i386-pc-linux-gnu System: Linux _ 2.4.16-pre1 #6 SMP Sun Nov 25 11:45:53 CET 2001 i686 unknown Architecture: i686
Addons: linuxthreads Build CC: gcc Compiler version: 2.95.4 20011006 (Debian prerelease) Kernel headers: UTS_RELEASE Symbol versioning: yes Build static: yes Build shared: yes Build pic-default: no Build profile: yes Build omitfp: no Build bounded: no Build static-nss: no Stdio: libio >Description: With 64-bit offsets, lseek has a bug in that it returns N>0 for some character devices, in spite of the fact that the underlying SYS__llseek returns 0. [background] This started with reports that dd's skip=N option didn't work on some tape drives on linux/gnu systems. That was because lseek would act like it had succeeded, but actually do nothing. I kludged dd to use read rather than lseek on *any* character device. >How-To-Repeat: Compile the following program using gcc
#define _FILE_OFFSET_BITS 64 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> int main (int argc, char **argv) { int fd; off_t off; if (argc < 3) { printf ("usage"); exit (1); } fd = open (argv[1], O_RDONLY); if (fd < 0) { perror ("open failed"); exit (1); } off = atoi (argv[2]); if (lseek (fd, off, SEEK_CUR) < off) { perror ("lseek failed"); exit (1); } exit (0); }
Then run it as root like this: # ltrace -S -o log ./a.out /dev/mem 5120 # grep seek log lseek64(3, 5120, 0, 1, 0x08049770 <unfinished ...> SYS__llseek(3, 0, 5120, 0xbffffce0, 1) = 0 <... lseek64 resumed> ) = 5120 Notice that SYS__llseek returned 0, yet its caller, lseek64(aka llseek) returned 5120 indicating success. The same thing happens with some other character devices, like my scsi tape drive (nst0). The net effect with the physical tape is that the seek does nothing, even though llseek returns a positive value.