Subject: bin/6774: dd(1) will not seek on raw disk devices
To: None <gnats-bugs@gnats.netbsd.org>
From: None <dave@dtsp.co.nz>
List: netbsd-bugs
Date: 01/09/1999 13:10:00
>Number:         6774
>Category:       bin
>Synopsis:       dd(1) will not seek on raw disk devices
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Jan  9 05:20:00 1999
>Last-Modified:
>Originator:     Dave Sainty
>Organization:
Dynamic Technology Services and Products Ltd (NZ)
>Release:        sup 30/12/98
>Environment:
>Description:
	The man page for dd(1) states that:

     skip=n   Skip n blocks from the beginning of the input before copying.
              On input which supports seeks, a lseek(2) operation is used.

	However this is not the case, "dd bs=512 if=/dev/rwd0a skip=19338496
	count=1" takes a very long time.

In src/bin/dd/position.c:

	/* If not a character, pipe or tape device, try to seek on it. */
	if (!(in.flags & (ISCHR|ISPIPE|ISTAPE))) {
		if (lseek(in.fd, (off_t)in.offset * (off_t)in.dbsz, SEEK_CUR)
		    == -1)
			err(1, "%s", in.name);
		return;
	}

This seems a trifle unfair on raw disk devices, just because they are a
character devices.  Perhaps instead it could actually try an lseek() and if it
fails revert to reading and ignoring the preceeding data.

Note that it already does this to decide whether it is a pipe or not...

static void
getfdtype(io)
	IO *io;
{
	struct mtget mt;
	struct stat sb;

	if (fstat(io->fd, &sb))
		err(1, "%s", io->name);
	if (S_ISCHR(sb.st_mode))
		io->flags |= ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE;
	else if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
		io->flags |= ISPIPE;		/* XXX fixed in 4.4BSD */
}

>How-To-Repeat:
	time dd bs=512 if=/dev/rwd0a skip=19338496 count=1

	Note that elapsed time is very high.

>Fix:
	Actually trying an lseek() seems an appropriate fix.  It needs more
	investigation as to how to implement this (I'm not sure how often the
	function in position.c is called).

	If the concensus is that testing for seek capability by actually
	trying a lseek() is the right thing to do, I'm happy to make up a
	patch.
>Audit-Trail:
>Unformatted:
System: NetBSD tequila.dave.dtsp.co.nz 1.3I NetBSD 1.3I (TEQUILA) #3: Tue Jan 5 01:00:19 NZDT 1999 dave@tequila.dave.dtsp.co.nz:/vol/tequila/userC/NetBSD-current/src/sys/arch/i386/compile/TEQUILA i386