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: