fdread.c revision 77729
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 77729 2001-06-04 21:16:28Z joerg $
2776589Sjoerg */
2876589Sjoerg
2976589Sjoerg#include <sys/types.h>
3076589Sjoerg#include <sys/stat.h>
3176589Sjoerg
3276589Sjoerg#include <machine/ioctl_fd.h>
3376589Sjoerg
3476589Sjoerg#include <err.h>
3576589Sjoerg#include <errno.h>
3676589Sjoerg#include <fcntl.h>
3776589Sjoerg#include <paths.h>
3876589Sjoerg#include <stdio.h>
3976589Sjoerg#include <stdlib.h>
4076589Sjoerg#include <string.h>
4176589Sjoerg#include <sysexits.h>
4276589Sjoerg#include <unistd.h>
4376589Sjoerg
4477729Sjoerg#include <dev/ic/nec765.h>
4576589Sjoerg
4676589Sjoergint	quiet, recover;
4776589Sjoergunsigned char fillbyte = 0xf0;	/* "foo" */
4876589Sjoerg
4976589Sjoergint	doread(int fd, FILE *of, const char *devname);
5076589Sjoergvoid	printstatus(struct fdc_status *fdcsp);
5176589Sjoergvoid	usage(void);
5276589Sjoerg
5376589Sjoergvoid
5476589Sjoergusage(void)
5576589Sjoerg{
5676589Sjoerg
5776589Sjoerg	errx(EX_USAGE,
5876589Sjoerg	     "usage: fdread [-qr] [-d device] [-f fillbyte] [-o file]");
5976589Sjoerg}
6076589Sjoerg
6176589Sjoerg
6276589Sjoergint
6376589Sjoergmain(int argc, char **argv)
6476589Sjoerg{
6576589Sjoerg	int c, errs = 0;
6676589Sjoerg	const char *fname = 0, *devname = "/dev/fd0";
6776589Sjoerg	char *cp;
6876589Sjoerg	FILE *of = stdout;
6976589Sjoerg	int fd;
7076589Sjoerg	unsigned long ul;
7176589Sjoerg
7276589Sjoerg	while ((c = getopt(argc, argv, "d:f:o:qr")) != -1)
7376589Sjoerg		switch (c) {
7476589Sjoerg		case 'd':
7576589Sjoerg			devname = optarg;
7676589Sjoerg			break;
7776589Sjoerg
7876589Sjoerg		case 'f':
7976589Sjoerg			ul = strtoul(optarg, &cp, 0);
8076589Sjoerg			if (*cp != '\0') {
8176589Sjoerg				fprintf(stderr,
8276589Sjoerg			"Bad argument %s to -f option; must be numeric\n",
8376589Sjoerg					optarg);
8476589Sjoerg				usage();
8576589Sjoerg			}
8676589Sjoerg			if (ul > 0xff)
8776589Sjoerg				warnx(
8876589Sjoerg			"Warning: fillbyte %#lx too large, truncating\n",
8976589Sjoerg				      ul);
9076589Sjoerg			fillbyte = ul & 0xff;
9176589Sjoerg			break;
9276589Sjoerg
9376589Sjoerg		case 'o':
9476589Sjoerg			fname = optarg;
9576589Sjoerg			break;
9676589Sjoerg
9776589Sjoerg		case 'q':
9876589Sjoerg			quiet++;
9976589Sjoerg			break;
10076589Sjoerg
10176589Sjoerg		case 'r':
10276589Sjoerg			recover++;
10376589Sjoerg			break;
10476589Sjoerg
10576589Sjoerg		default:
10676589Sjoerg			errs++;
10776589Sjoerg		}
10876589Sjoerg	argc -= optind;
10976589Sjoerg	argv += optind;
11076589Sjoerg
11176589Sjoerg	if (argc != 0 || errs)
11276589Sjoerg		usage();
11376589Sjoerg
11476589Sjoerg	if (fname) {
11576589Sjoerg		if ((of = fopen(fname, "w")) == NULL)
11676589Sjoerg			err(EX_OSERR, "cannot create output file %s", fname);
11776589Sjoerg	}
11876589Sjoerg
11976589Sjoerg	if ((fd = open(devname, O_RDONLY)) == -1)
12076589Sjoerg		err(EX_OSERR, "cannot open device %s", devname);
12176589Sjoerg
12276589Sjoerg	return (doread(fd, of, devname));
12376589Sjoerg}
12476589Sjoerg
12576589Sjoergint
12676589Sjoergdoread(int fd, FILE *of, const char *devname)
12776589Sjoerg{
12876589Sjoerg	char *trackbuf;
12976589Sjoerg	int rv, fdopts, recoverable, nerrs = 0;
13076589Sjoerg	unsigned int nbytes, tracksize, mediasize, secsize, n;
13176589Sjoerg	struct fdc_status fdcs;
13276589Sjoerg	struct fd_type fdt;
13376589Sjoerg
13476589Sjoerg	if (ioctl(fd, FD_GTYPE, &fdt) == -1)
13576589Sjoerg		err(EX_OSERR, "ioctl(FD_GTYPE) failed -- not a floppy?");
13676589Sjoerg	fdopts = FDOPT_NOERRLOG;
13776589Sjoerg	if (ioctl(fd, FD_SOPTS, &fdopts) == -1)
13876589Sjoerg		err(EX_OSERR, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)");
13976589Sjoerg
14076589Sjoerg	secsize = 128 << fdt.secsize;
14176589Sjoerg	tracksize = fdt.sectrac * secsize;
14276589Sjoerg	mediasize = tracksize * fdt.tracks * fdt.heads;
14376589Sjoerg	if ((trackbuf = malloc(tracksize)) == 0)
14476589Sjoerg		errx(EX_TEMPFAIL, "out of memory");
14576589Sjoerg
14676589Sjoerg	if (!quiet)
14776589Sjoerg		fprintf(stderr, "Reading %d * %d * %d * %d medium at %s\n",
14876589Sjoerg			fdt.tracks, fdt.heads, fdt.sectrac, secsize, devname);
14976589Sjoerg
15076589Sjoerg	for (nbytes = 0; nbytes < mediasize;) {
15176589Sjoerg		if (lseek(fd, nbytes, SEEK_SET) != nbytes)
15276589Sjoerg			err(EX_OSERR, "cannot lseek()");
15376589Sjoerg		rv = read(fd, trackbuf, tracksize);
15476589Sjoerg		if (rv == 0) {
15576589Sjoerg			/* EOF? */
15676589Sjoerg			warnx("premature EOF after %u bytes", nbytes);
15776589Sjoerg			return (EX_OK);
15876589Sjoerg		}
15976589Sjoerg		if (rv == tracksize) {
16076589Sjoerg			nbytes += rv;
16176589Sjoerg			if (!quiet)
16276589Sjoerg				fprintf(stderr, "%5d KB\r", nbytes / 1024);
16376589Sjoerg			fwrite(trackbuf, sizeof(unsigned char), rv, of);
16476589Sjoerg			fflush(of);
16576589Sjoerg			continue;
16676589Sjoerg		}
16776589Sjoerg		if (rv < tracksize) {
16876589Sjoerg			/* should not happen */
16976589Sjoerg			nbytes += rv;
17076589Sjoerg			if (!quiet)
17176589Sjoerg				fprintf(stderr, "\nshort after %5d KB\r",
17276589Sjoerg					nbytes / 1024);
17376589Sjoerg			fwrite(trackbuf, sizeof(unsigned char), rv, of);
17476589Sjoerg			fflush(of);
17576589Sjoerg			continue;
17676589Sjoerg		}
17776589Sjoerg		if (rv == -1) {
17876589Sjoerg			/* fall back reading one sector at a time */
17976589Sjoerg			for (n = 0; n < tracksize; n += secsize) {
18076589Sjoerg				if (lseek(fd, nbytes, SEEK_SET) != nbytes)
18176589Sjoerg					err(EX_OSERR, "cannot lseek()");
18276589Sjoerg				rv = read(fd, trackbuf, secsize);
18376589Sjoerg				if (rv == secsize) {
18476589Sjoerg					nbytes += rv;
18576589Sjoerg					if (!quiet)
18676589Sjoerg						fprintf(stderr, "%5d KB\r",
18776589Sjoerg							nbytes / 1024);
18876589Sjoerg					fwrite(trackbuf, sizeof(unsigned char),
18976589Sjoerg					       rv, of);
19076589Sjoerg					fflush(of);
19176589Sjoerg					continue;
19276589Sjoerg				}
19376589Sjoerg				if (rv == -1) {
19476589Sjoerg					if (errno != EIO) {
19576589Sjoerg						if (!quiet)
19676589Sjoerg							putc('\n', stderr);
19776589Sjoerg						perror("non-IO error");
19876589Sjoerg						return (EX_OSERR);
19976589Sjoerg					}
20076589Sjoerg					if (ioctl(fd, FD_GSTAT, &fdcs) == -1)
20176589Sjoerg						errx(EX_IOERR,
20276589Sjoerg				     "floppy IO error, but no FDC status");
20376589Sjoerg					nerrs++;
20476589Sjoerg					recoverable = fdcs.status[2] &
20576589Sjoerg						NE7_ST2_DD;
20676589Sjoerg					if (!quiet) {
20776589Sjoerg						printstatus(&fdcs);
20876589Sjoerg						fputs(" (", stderr);
20976589Sjoerg						if (!recoverable)
21076589Sjoerg							fputs("not ", stderr);
21176589Sjoerg						fputs("recoverable)", stderr);
21276589Sjoerg					}
21376589Sjoerg					if (!recover) {
21476589Sjoerg						if (!quiet)
21576589Sjoerg							putc('\n', stderr);
21676589Sjoerg						return (EX_IOERR);
21776589Sjoerg					}
21876589Sjoerg					memset(trackbuf, fillbyte, secsize);
21976589Sjoerg					if (recoverable) {
22076589Sjoerg						fdopts |= FDOPT_NOERROR;
22176589Sjoerg						if (ioctl(fd, FD_SOPTS,
22276589Sjoerg							  &fdopts) == -1)
22376589Sjoerg							err(EX_OSERR,
22476589Sjoerg				    "ioctl(fd, FD_SOPTS, FDOPT_NOERROR)");
22576589Sjoerg						rv = read(fd, trackbuf,
22676589Sjoerg							  secsize);
22776589Sjoerg						if (rv != secsize)
22876589Sjoerg							err(EX_IOERR,
22976589Sjoerg				    "read() with FDOPT_NOERROR still fails");
23076589Sjoerg						fdopts &= ~FDOPT_NOERROR;
23176589Sjoerg						(void)ioctl(fd, FD_SOPTS,
23276589Sjoerg							    &fdopts);
23376589Sjoerg					}
23476589Sjoerg					if (!quiet) {
23576589Sjoerg						if (recoverable)
23676589Sjoerg							fprintf(stderr,
23776589Sjoerg								": recovered");
23876589Sjoerg						else
23976589Sjoerg							fprintf(stderr,
24076589Sjoerg								": dummy");
24176589Sjoerg						fprintf(stderr,
24276589Sjoerg							" data @ %#x ... %#x\n",
24376589Sjoerg							nbytes,
24476589Sjoerg							nbytes + secsize - 1);
24576589Sjoerg					}
24676589Sjoerg					nbytes += secsize;
24776589Sjoerg					fwrite(trackbuf, sizeof(unsigned char),
24876589Sjoerg					       secsize, of);
24976589Sjoerg					fflush(of);
25076589Sjoerg					continue;
25176589Sjoerg				}
25276589Sjoerg				errx(EX_OSERR, "unexpected read() result: %d",
25376589Sjoerg				     rv);
25476589Sjoerg			}
25576589Sjoerg		}
25676589Sjoerg	}
25776589Sjoerg	if (!quiet) {
25876589Sjoerg		putc('\n', stderr);
25976589Sjoerg		if (nerrs)
26076589Sjoerg			fprintf(stderr, "%d error%s\n",
26176589Sjoerg				nerrs, nerrs > 1? "s": "");
26276589Sjoerg	}
26376589Sjoerg
26476589Sjoerg	return (nerrs? EX_IOERR: EX_OK);
26576589Sjoerg}
26676589Sjoerg
26776589Sjoergvoid
26876589Sjoergprintstatus(struct fdc_status *fdcsp)
26976589Sjoerg{
27076589Sjoerg	char msgbuf[100];
27176589Sjoerg
27276589Sjoerg	fprintf(stderr,
27376589Sjoerg		"\nFDC status ST0=%#x ST1=%#x ST2=%#x C=%u H=%u R=%u N=%u:\n",
27476589Sjoerg		fdcsp->status[0] & 0xff,
27576589Sjoerg		fdcsp->status[1] & 0xff,
27676589Sjoerg		fdcsp->status[2] & 0xff,
27776589Sjoerg		fdcsp->status[3] & 0xff,
27876589Sjoerg		fdcsp->status[4] & 0xff,
27976589Sjoerg		fdcsp->status[5] & 0xff,
28076589Sjoerg		fdcsp->status[6] & 0xff);
28176589Sjoerg
28276589Sjoerg	if ((fdcsp->status[0] & NE7_ST0_IC_RC) != NE7_ST0_IC_AT) {
28376589Sjoerg		sprintf(msgbuf, "unexcpted interrupt code %#x",
28476589Sjoerg			fdcsp->status[0] & NE7_ST0_IC_RC);
28576589Sjoerg	} else {
28676589Sjoerg		strcpy(msgbuf, "unexpected error code in ST1/ST2");
28776589Sjoerg
28876589Sjoerg		if (fdcsp->status[1] & NE7_ST1_EN)
28976589Sjoerg			strcpy(msgbuf, "end of cylinder (wrong format)");
29076589Sjoerg		else if (fdcsp->status[1] & NE7_ST1_DE) {
29176589Sjoerg			if (fdcsp->status[2] & NE7_ST2_DD)
29276589Sjoerg				strcpy(msgbuf, "CRC error in data field");
29376589Sjoerg			else
29476589Sjoerg				strcpy(msgbuf, "CRC error in ID field");
29576589Sjoerg		} else if (fdcsp->status[1] & NE7_ST1_MA) {
29676589Sjoerg			if (fdcsp->status[2] & NE7_ST2_MD)
29776589Sjoerg				strcpy(msgbuf, "no address mark in data field");
29876589Sjoerg			else
29976589Sjoerg				strcpy(msgbuf, "no address mark in ID field");
30076589Sjoerg		} else if (fdcsp->status[2] & NE7_ST2_WC)
30176589Sjoerg			strcpy(msgbuf, "wrong cylinder (format mismatch)");
30276589Sjoerg		else if (fdcsp->status[1] & NE7_ST1_ND)
30376589Sjoerg			strcpy(msgbuf, "no data (sector not found)");
30476589Sjoerg	}
30576589Sjoerg	fputs(msgbuf, stderr);
30676589Sjoerg}
307