Subject: kern/3997: SYS_lseek on tape drive is broken
To: None <gnats-bugs@gnats.netbsd.org>
From: Matthias Scheler <tron@lyssa.owl.de>
List: netbsd-bugs
Date: 08/16/1997 19:23:15
>Number:         3997
>Category:       kern
>Synopsis:       SYS_lseek on tape drive is broken
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Aug 16 11:20:01 1997
>Last-Modified:
>Originator:     Matthias Scheler
>Organization:
Matthias Scheler                                http://home.owl.de/~tron/
>Release:        970814
>Environment:
System: NetBSD lyssa 1.2G NetBSD 1.2G (LYSSA) #0: Fri Aug 15 20:37:06 MEST 1997 tron@lyssa:/usr/src/sys/arch/i386/compile/LYSSA i386


>Description:
While programming an interface to "/etc/rmt" for an alien operating system
I discovered that the handling of SYS_lseek within NetBSD's SCSI tape handler
is broken. If you try to use lseek() with it you get a result which looks
like everything worked fine but actually nothing happened.

>How-To-Repeat:

Here's a small program "foo.c" which writes 10240 times 0 (as byte) and
10240 times 1 to "/dev/rst1":

#include <sys/file.h>
#include <unistd.h>

#include <stdio.h>
#include <string.h>

char Tape[] = "/dev/rst1";

int main(int argc,char **argv)

{
 int FD,Bytes,Index;
 char Buffer[10240];

 if ((FD=open(Tape,O_WRONLY|O_CREAT))==-1)
  {
   (void)fprintf(stderr,"%s: can't open \"%s\" for write.\n",argv[0],Tape);
   return 1;
  }

 Bytes=sizeof(Buffer);
 for (Index=0; Index<2; Index++)
  {
   (void)memset(Buffer,(char)Index,Bytes);
   if (write(FD,Buffer,Bytes)!=Bytes)
    {
     (void)fprintf(stderr,"%s: error writing %d. block to \"%s\".\n",
                   argv[0],Index,Tape);
     return 1;
    }
  }

 (void)close(FD);
 return 0;
}

Here's a program "bar.c" which opens "/dev/rst1", seeks 10240 bytes forward,
reads 10240 bytes and prints out the first readen byte:

#include <sys/file.h>
#include <unistd.h>

#include <stdio.h>
#include <string.h>

char Tape[] = "/dev/rst1";

int main(int argc,char **argv)

{
 int FD,Bytes;
 off_t Pos;
 char Buffer[10240];

 if ((FD=open(Tape,O_RDONLY|O_CREAT))==-1)
  {
   (void)fprintf(stderr,"%s: can't open \"%s\" for read.\n",argv[0],Tape);
   return 1;
  }

 Bytes=sizeof(Buffer);
 Pos=lseek(FD,Bytes,SEEK_CUR);
 if (Pos<0)
  {
   (void)fprintf(stderr,"%s: seek error on \"%s\".\n",argv[0],Tape);
   return 1;
  }
 (void)printf("New position: %d\n",Pos);

 if (read(FD,Buffer,Bytes)!=Bytes)
  {
   (void)fprintf(stderr,"%s: error reading from \"%s\".\n",argv[0],Tape);
   return 1;
  }
 (void)printf("First byte: %d\n",Buffer[0]);

 (void)close(FD);
 return 0;
}

If you call "bar" after "foo" you get this:

tron@lyssa:~/c/tape>./foo
tron@lyssa:~/c/tape>./bar
New position: 10240
First byte: 0

Looking at the source code one can see that the first byte should be a 1.

>Fix:
Either implement SYS_lseek in "st.c" or at least let it return an error.

>Audit-Trail:
>Unformatted: