fdread.c revision 139905
176589Sjoerg/*
276589Sjoerg * Copyright (c) 2001 Joerg Wunsch
376589Sjoerg *
476589Sjoerg * All rights reserved.
576589Sjoerg *
676589Sjoerg * Redistribution and use in source and binary forms, with or without
776589Sjoerg * modification, are permitted provided that the following conditions
876589Sjoerg * are met:
976589Sjoerg * 1. Redistributions of source code must retain the above copyright
1076589Sjoerg *    notice, this list of conditions and the following disclaimer.
1176589Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
1276589Sjoerg *    notice, this list of conditions and the following disclaimer in the
1376589Sjoerg *    documentation and/or other materials provided with the distribution.
1476589Sjoerg *
1576589Sjoerg * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
1676589Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1776589Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1876589Sjoerg * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
1976589Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2076589Sjoerg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2176589Sjoerg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2276589Sjoerg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2376589Sjoerg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2476589Sjoerg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2576589Sjoerg *
2676589Sjoerg * $FreeBSD: head/usr.sbin/fdread/fdread.c 139905 2005-01-08 15:46:06Z delphij $
2776589Sjoerg */
2876589Sjoerg
2976589Sjoerg#include <sys/types.h>
3076589Sjoerg#include <sys/stat.h>
3177801Sjoerg#include <sys/fdcio.h>
3276589Sjoerg
3376589Sjoerg#include <err.h>
3476589Sjoerg#include <errno.h>
3576589Sjoerg#include <fcntl.h>
3676589Sjoerg#include <paths.h>
3776589Sjoerg#include <stdio.h>
3876589Sjoerg#include <stdlib.h>
3976589Sjoerg#include <string.h>
4076589Sjoerg#include <sysexits.h>
4176589Sjoerg#include <unistd.h>
4276589Sjoerg
4377729Sjoerg#include <dev/ic/nec765.h>
4476589Sjoerg
4579110Sjoerg#include "fdutil.h"
4679110Sjoerg
4776589Sjoergint	quiet, recover;
4876589Sjoergunsigned char fillbyte = 0xf0;	/* "foo" */
4976589Sjoerg
50139905Sdelphijint	doread(int fd, FILE *of, const char *_devname);
5178857Sjoergint	doreadid(int fd, unsigned int numids, unsigned int trackno);
5276589Sjoergvoid	usage(void);
5376589Sjoerg
5476589Sjoergvoid
5576589Sjoergusage(void)
5676589Sjoerg{
5776589Sjoerg
5876589Sjoerg	errx(EX_USAGE,
5978857Sjoerg	     "usage: fdread [-qr] [-d device] [-f fillbyte]\n"
6078857Sjoerg	     "       fdread [-d device] -I numids [-t trackno]");
6176589Sjoerg}
6276589Sjoerg
6376589Sjoerg
6476589Sjoergint
6576589Sjoergmain(int argc, char **argv)
6676589Sjoerg{
6776589Sjoerg	int c, errs = 0;
6878857Sjoerg	unsigned int numids = 0, trackno = 0;
69139905Sdelphij	const char *fname = 0, *_devname = "/dev/fd0";
7076589Sjoerg	char *cp;
7176589Sjoerg	FILE *of = stdout;
7276589Sjoerg	int fd;
7376589Sjoerg	unsigned long ul;
7476589Sjoerg
7578857Sjoerg	while ((c = getopt(argc, argv, "d:f:I:o:qrt:")) != -1)
7676589Sjoerg		switch (c) {
7776589Sjoerg		case 'd':
78139905Sdelphij			_devname = optarg;
7976589Sjoerg			break;
8076589Sjoerg
8176589Sjoerg		case 'f':
8276589Sjoerg			ul = strtoul(optarg, &cp, 0);
8376589Sjoerg			if (*cp != '\0') {
8476589Sjoerg				fprintf(stderr,
8576589Sjoerg			"Bad argument %s to -f option; must be numeric\n",
8676589Sjoerg					optarg);
8776589Sjoerg				usage();
8876589Sjoerg			}
8976589Sjoerg			if (ul > 0xff)
9076589Sjoerg				warnx(
9176589Sjoerg			"Warning: fillbyte %#lx too large, truncating\n",
9276589Sjoerg				      ul);
9376589Sjoerg			fillbyte = ul & 0xff;
9476589Sjoerg			break;
9576589Sjoerg
9678857Sjoerg		case 'I':
9778857Sjoerg			ul = strtoul(optarg, &cp, 0);
9878857Sjoerg			if (*cp != '\0') {
9978857Sjoerg				fprintf(stderr,
10078857Sjoerg			"Bad argument %s to -I option; must be numeric\n",
10178857Sjoerg					optarg);
10278857Sjoerg				usage();
10378857Sjoerg			}
10478857Sjoerg			numids = ul;
10578857Sjoerg			break;
10678857Sjoerg
10776589Sjoerg		case 'o':
10876589Sjoerg			fname = optarg;
10976589Sjoerg			break;
11076589Sjoerg
11176589Sjoerg		case 'q':
11276589Sjoerg			quiet++;
11376589Sjoerg			break;
11476589Sjoerg
11576589Sjoerg		case 'r':
11676589Sjoerg			recover++;
11776589Sjoerg			break;
11876589Sjoerg
11978857Sjoerg		case 't':
12078857Sjoerg			ul = strtoul(optarg, &cp, 0);
12178857Sjoerg			if (*cp != '\0') {
12278857Sjoerg				fprintf(stderr,
12378857Sjoerg			"Bad argument %s to -t option; must be numeric\n",
12478857Sjoerg					optarg);
12578857Sjoerg				usage();
12678857Sjoerg			}
12778857Sjoerg			trackno = ul;
12878857Sjoerg			break;
12978857Sjoerg
13076589Sjoerg		default:
13176589Sjoerg			errs++;
13276589Sjoerg		}
13376589Sjoerg	argc -= optind;
13476589Sjoerg	argv += optind;
13576589Sjoerg
13676589Sjoerg	if (argc != 0 || errs)
13776589Sjoerg		usage();
13878857Sjoerg	/* check for mutually exclusive options */
13978857Sjoerg	if (numids) {
14078857Sjoerg		if (fname || quiet || recover)
14178857Sjoerg			usage();
14278857Sjoerg	} else {
14378857Sjoerg		if (trackno)
14478857Sjoerg			usage();
14578857Sjoerg	}
14676589Sjoerg
14776589Sjoerg	if (fname) {
14876589Sjoerg		if ((of = fopen(fname, "w")) == NULL)
14976589Sjoerg			err(EX_OSERR, "cannot create output file %s", fname);
15076589Sjoerg	}
15176589Sjoerg
152139905Sdelphij	if ((fd = open(_devname, O_RDONLY)) == -1)
153139905Sdelphij		err(EX_OSERR, "cannot open device %s", _devname);
15476589Sjoerg
155139905Sdelphij	return (numids? doreadid(fd, numids, trackno): doread(fd, of, _devname));
15676589Sjoerg}
15776589Sjoerg
15876589Sjoergint
159139905Sdelphijdoread(int fd, FILE *of, const char *_devname)
16076589Sjoerg{
16176589Sjoerg	char *trackbuf;
16276589Sjoerg	int rv, fdopts, recoverable, nerrs = 0;
16376589Sjoerg	unsigned int nbytes, tracksize, mediasize, secsize, n;
16476589Sjoerg	struct fdc_status fdcs;
16576589Sjoerg	struct fd_type fdt;
16676589Sjoerg
16776589Sjoerg	if (ioctl(fd, FD_GTYPE, &fdt) == -1)
16876589Sjoerg		err(EX_OSERR, "ioctl(FD_GTYPE) failed -- not a floppy?");
16976589Sjoerg	fdopts = FDOPT_NOERRLOG;
17076589Sjoerg	if (ioctl(fd, FD_SOPTS, &fdopts) == -1)
17176589Sjoerg		err(EX_OSERR, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)");
17276589Sjoerg
17376589Sjoerg	secsize = 128 << fdt.secsize;
17476589Sjoerg	tracksize = fdt.sectrac * secsize;
17576589Sjoerg	mediasize = tracksize * fdt.tracks * fdt.heads;
17676589Sjoerg	if ((trackbuf = malloc(tracksize)) == 0)
17776589Sjoerg		errx(EX_TEMPFAIL, "out of memory");
17876589Sjoerg
17976589Sjoerg	if (!quiet)
18076589Sjoerg		fprintf(stderr, "Reading %d * %d * %d * %d medium at %s\n",
181139905Sdelphij			fdt.tracks, fdt.heads, fdt.sectrac, secsize, _devname);
18276589Sjoerg
18376589Sjoerg	for (nbytes = 0; nbytes < mediasize;) {
18476589Sjoerg		if (lseek(fd, nbytes, SEEK_SET) != nbytes)
18576589Sjoerg			err(EX_OSERR, "cannot lseek()");
18676589Sjoerg		rv = read(fd, trackbuf, tracksize);
18776589Sjoerg		if (rv == 0) {
18876589Sjoerg			/* EOF? */
18976589Sjoerg			warnx("premature EOF after %u bytes", nbytes);
19076589Sjoerg			return (EX_OK);
19176589Sjoerg		}
192139905Sdelphij		if ((unsigned)rv == tracksize) {
19376589Sjoerg			nbytes += rv;
19476589Sjoerg			if (!quiet)
19576589Sjoerg				fprintf(stderr, "%5d KB\r", nbytes / 1024);
19676589Sjoerg			fwrite(trackbuf, sizeof(unsigned char), rv, of);
19776589Sjoerg			fflush(of);
19876589Sjoerg			continue;
19976589Sjoerg		}
20076589Sjoerg		if (rv == -1) {
20176589Sjoerg			/* fall back reading one sector at a time */
20276589Sjoerg			for (n = 0; n < tracksize; n += secsize) {
20376589Sjoerg				if (lseek(fd, nbytes, SEEK_SET) != nbytes)
20476589Sjoerg					err(EX_OSERR, "cannot lseek()");
20576589Sjoerg				rv = read(fd, trackbuf, secsize);
206139905Sdelphij				if ((unsigned) rv == secsize) {
20776589Sjoerg					nbytes += rv;
20876589Sjoerg					if (!quiet)
20976589Sjoerg						fprintf(stderr, "%5d KB\r",
21076589Sjoerg							nbytes / 1024);
21176589Sjoerg					fwrite(trackbuf, sizeof(unsigned char),
21276589Sjoerg					       rv, of);
21376589Sjoerg					fflush(of);
21476589Sjoerg					continue;
21576589Sjoerg				}
21676589Sjoerg				if (rv == -1) {
21776589Sjoerg					if (errno != EIO) {
21876589Sjoerg						if (!quiet)
21976589Sjoerg							putc('\n', stderr);
22076589Sjoerg						perror("non-IO error");
22176589Sjoerg						return (EX_OSERR);
22276589Sjoerg					}
22376589Sjoerg					if (ioctl(fd, FD_GSTAT, &fdcs) == -1)
22476589Sjoerg						errx(EX_IOERR,
22576589Sjoerg				     "floppy IO error, but no FDC status");
22676589Sjoerg					nerrs++;
22776589Sjoerg					recoverable = fdcs.status[2] &
22876589Sjoerg						NE7_ST2_DD;
22976589Sjoerg					if (!quiet) {
23079110Sjoerg						printstatus(&fdcs, 0);
23176589Sjoerg						fputs(" (", stderr);
23276589Sjoerg						if (!recoverable)
23376589Sjoerg							fputs("not ", stderr);
23476589Sjoerg						fputs("recoverable)", stderr);
23576589Sjoerg					}
23676589Sjoerg					if (!recover) {
23776589Sjoerg						if (!quiet)
23876589Sjoerg							putc('\n', stderr);
23976589Sjoerg						return (EX_IOERR);
24076589Sjoerg					}
24176589Sjoerg					memset(trackbuf, fillbyte, secsize);
24276589Sjoerg					if (recoverable) {
24376589Sjoerg						fdopts |= FDOPT_NOERROR;
24476589Sjoerg						if (ioctl(fd, FD_SOPTS,
24576589Sjoerg							  &fdopts) == -1)
24676589Sjoerg							err(EX_OSERR,
24776589Sjoerg				    "ioctl(fd, FD_SOPTS, FDOPT_NOERROR)");
24876589Sjoerg						rv = read(fd, trackbuf,
24976589Sjoerg							  secsize);
250139905Sdelphij						if ((unsigned)rv != secsize)
25176589Sjoerg							err(EX_IOERR,
25276589Sjoerg				    "read() with FDOPT_NOERROR still fails");
25376589Sjoerg						fdopts &= ~FDOPT_NOERROR;
25476589Sjoerg						(void)ioctl(fd, FD_SOPTS,
25576589Sjoerg							    &fdopts);
25676589Sjoerg					}
25776589Sjoerg					if (!quiet) {
25876589Sjoerg						if (recoverable)
25976589Sjoerg							fprintf(stderr,
26076589Sjoerg								": recovered");
26176589Sjoerg						else
26276589Sjoerg							fprintf(stderr,
26376589Sjoerg								": dummy");
26476589Sjoerg						fprintf(stderr,
26576589Sjoerg							" data @ %#x ... %#x\n",
26676589Sjoerg							nbytes,
26776589Sjoerg							nbytes + secsize - 1);
26876589Sjoerg					}
26976589Sjoerg					nbytes += secsize;
27076589Sjoerg					fwrite(trackbuf, sizeof(unsigned char),
27176589Sjoerg					       secsize, of);
27276589Sjoerg					fflush(of);
27376589Sjoerg					continue;
27476589Sjoerg				}
27576589Sjoerg				errx(EX_OSERR, "unexpected read() result: %d",
27676589Sjoerg				     rv);
27776589Sjoerg			}
27876589Sjoerg		}
279139905Sdelphij		if ((unsigned)rv < tracksize) {
280139905Sdelphij			/* should not happen */
281139905Sdelphij			nbytes += rv;
282139905Sdelphij			if (!quiet)
283139905Sdelphij				fprintf(stderr, "\nshort after %5d KB\r",
284139905Sdelphij					nbytes / 1024);
285139905Sdelphij			fwrite(trackbuf, sizeof(unsigned char), rv, of);
286139905Sdelphij			fflush(of);
287139905Sdelphij			continue;
288139905Sdelphij		}
28976589Sjoerg	}
29076589Sjoerg	if (!quiet) {
29176589Sjoerg		putc('\n', stderr);
29276589Sjoerg		if (nerrs)
29376589Sjoerg			fprintf(stderr, "%d error%s\n",
29476589Sjoerg				nerrs, nerrs > 1? "s": "");
29576589Sjoerg	}
29676589Sjoerg
29776589Sjoerg	return (nerrs? EX_IOERR: EX_OK);
29876589Sjoerg}
29976589Sjoerg
30078857Sjoergint
30178857Sjoergdoreadid(int fd, unsigned int numids, unsigned int trackno)
30278857Sjoerg{
30378857Sjoerg	int rv = 0, status, fdopts;
30478857Sjoerg	unsigned int i;
30578857Sjoerg	struct fdc_readid info;
30678857Sjoerg	struct fdc_status fdcs;
30778857Sjoerg	struct fd_type fdt;
30878857Sjoerg
30978857Sjoerg	if (ioctl(fd, FD_GTYPE, &fdt) == -1)
31078857Sjoerg		err(EX_OSERR, "ioctl(FD_GTYPE) failed -- not a floppy?");
31178857Sjoerg
31278857Sjoerg	fdopts = FDOPT_NOERRLOG;
31378857Sjoerg	if (ioctl(fd, FD_SOPTS, &fdopts) == -1)
31478857Sjoerg		err(EX_OSERR, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)");
31578857Sjoerg
31678857Sjoerg	for (i = 0; i < numids; i++) {
31778857Sjoerg		info.cyl = trackno / fdt.heads;
31878857Sjoerg		info.head = fdt.heads > 1? trackno % fdt.heads: 0;
31978857Sjoerg		if ((status = ioctl(fd, FD_READID, &info)) == 0) {
32078857Sjoerg			printf("C = %d, H = %d, R = %d, N = %d\n",
32178857Sjoerg			       info.cyl, info.head, info.sec, info.secshift);
32278857Sjoerg		} else {
32378857Sjoerg			if (errno != EIO) {
32478857Sjoerg				perror("non-IO error");
32578857Sjoerg				return (EX_OSERR);
32678857Sjoerg			}
32778857Sjoerg			if (ioctl(fd, FD_GSTAT, &fdcs) == -1)
32878857Sjoerg				errx(EX_IOERR,
32978857Sjoerg				     "floppy IO error, but no FDC status");
33079110Sjoerg			printstatus(&fdcs, 0);
33178857Sjoerg			putc('\n', stderr);
33278857Sjoerg			rv = EX_IOERR;
33378857Sjoerg		}
33478857Sjoerg	}
33578857Sjoerg
33678857Sjoerg	return (rv);
33778857Sjoerg}
338