fdread.c revision 76589
1/*
2 * Copyright (c) 2001 Joerg Wunsch
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * $FreeBSD: cvs2svn/branches/JOERG/usr.sbin/fdread/fdread.c 76589 2001-05-14 20:22:49Z joerg $
27 */
28
29#include <sys/types.h>
30#include <sys/stat.h>
31
32#include <machine/ioctl_fd.h>
33
34#include <err.h>
35#include <errno.h>
36#include <fcntl.h>
37#include <paths.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <sysexits.h>
42#include <unistd.h>
43
44/* XXX -- header file should probably be installed somewhere */
45#include "/sys/isa/ic/nec765.h"
46
47int	quiet, recover;
48unsigned char fillbyte = 0xf0;	/* "foo" */
49
50int	doread(int fd, FILE *of, const char *devname);
51void	printstatus(struct fdc_status *fdcsp);
52void	usage(void);
53
54void
55usage(void)
56{
57
58	errx(EX_USAGE,
59	     "usage: fdread [-qr] [-d device] [-f fillbyte] [-o file]");
60}
61
62
63int
64main(int argc, char **argv)
65{
66	int c, errs = 0;
67	const char *fname = 0, *devname = "/dev/fd0";
68	char *cp;
69	FILE *of = stdout;
70	int fd;
71	unsigned long ul;
72
73	while ((c = getopt(argc, argv, "d:f:o:qr")) != -1)
74		switch (c) {
75		case 'd':
76			devname = optarg;
77			break;
78
79		case 'f':
80			ul = strtoul(optarg, &cp, 0);
81			if (*cp != '\0') {
82				fprintf(stderr,
83			"Bad argument %s to -f option; must be numeric\n",
84					optarg);
85				usage();
86			}
87			if (ul > 0xff)
88				warnx(
89			"Warning: fillbyte %#lx too large, truncating\n",
90				      ul);
91			fillbyte = ul & 0xff;
92			break;
93
94		case 'o':
95			fname = optarg;
96			break;
97
98		case 'q':
99			quiet++;
100			break;
101
102		case 'r':
103			recover++;
104			break;
105
106		default:
107			errs++;
108		}
109	argc -= optind;
110	argv += optind;
111
112	if (argc != 0 || errs)
113		usage();
114
115	if (fname) {
116		if ((of = fopen(fname, "w")) == NULL)
117			err(EX_OSERR, "cannot create output file %s", fname);
118	}
119
120	if ((fd = open(devname, O_RDONLY)) == -1)
121		err(EX_OSERR, "cannot open device %s", devname);
122
123	return (doread(fd, of, devname));
124}
125
126int
127doread(int fd, FILE *of, const char *devname)
128{
129	char *trackbuf;
130	int rv, fdopts, recoverable, nerrs = 0;
131	unsigned int nbytes, tracksize, mediasize, secsize, n;
132	struct fdc_status fdcs;
133	struct fd_type fdt;
134
135	if (ioctl(fd, FD_GTYPE, &fdt) == -1)
136		err(EX_OSERR, "ioctl(FD_GTYPE) failed -- not a floppy?");
137	fdopts = FDOPT_NOERRLOG;
138	if (ioctl(fd, FD_SOPTS, &fdopts) == -1)
139		err(EX_OSERR, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)");
140
141	secsize = 128 << fdt.secsize;
142	tracksize = fdt.sectrac * secsize;
143	mediasize = tracksize * fdt.tracks * fdt.heads;
144	if ((trackbuf = malloc(tracksize)) == 0)
145		errx(EX_TEMPFAIL, "out of memory");
146
147	if (!quiet)
148		fprintf(stderr, "Reading %d * %d * %d * %d medium at %s\n",
149			fdt.tracks, fdt.heads, fdt.sectrac, secsize, devname);
150
151	for (nbytes = 0; nbytes < mediasize;) {
152		if (lseek(fd, nbytes, SEEK_SET) != nbytes)
153			err(EX_OSERR, "cannot lseek()");
154		rv = read(fd, trackbuf, tracksize);
155		if (rv == 0) {
156			/* EOF? */
157			warnx("premature EOF after %u bytes", nbytes);
158			return (EX_OK);
159		}
160		if (rv == tracksize) {
161			nbytes += rv;
162			if (!quiet)
163				fprintf(stderr, "%5d KB\r", nbytes / 1024);
164			fwrite(trackbuf, sizeof(unsigned char), rv, of);
165			fflush(of);
166			continue;
167		}
168		if (rv < tracksize) {
169			/* should not happen */
170			nbytes += rv;
171			if (!quiet)
172				fprintf(stderr, "\nshort after %5d KB\r",
173					nbytes / 1024);
174			fwrite(trackbuf, sizeof(unsigned char), rv, of);
175			fflush(of);
176			continue;
177		}
178		if (rv == -1) {
179			/* fall back reading one sector at a time */
180			for (n = 0; n < tracksize; n += secsize) {
181				if (lseek(fd, nbytes, SEEK_SET) != nbytes)
182					err(EX_OSERR, "cannot lseek()");
183				rv = read(fd, trackbuf, secsize);
184				if (rv == secsize) {
185					nbytes += rv;
186					if (!quiet)
187						fprintf(stderr, "%5d KB\r",
188							nbytes / 1024);
189					fwrite(trackbuf, sizeof(unsigned char),
190					       rv, of);
191					fflush(of);
192					continue;
193				}
194				if (rv == -1) {
195					if (errno != EIO) {
196						if (!quiet)
197							putc('\n', stderr);
198						perror("non-IO error");
199						return (EX_OSERR);
200					}
201					if (ioctl(fd, FD_GSTAT, &fdcs) == -1)
202						errx(EX_IOERR,
203				     "floppy IO error, but no FDC status");
204					nerrs++;
205					recoverable = fdcs.status[2] &
206						NE7_ST2_DD;
207					if (!quiet) {
208						printstatus(&fdcs);
209						fputs(" (", stderr);
210						if (!recoverable)
211							fputs("not ", stderr);
212						fputs("recoverable)", stderr);
213					}
214					if (!recover) {
215						if (!quiet)
216							putc('\n', stderr);
217						return (EX_IOERR);
218					}
219					memset(trackbuf, fillbyte, secsize);
220					if (recoverable) {
221						fdopts |= FDOPT_NOERROR;
222						if (ioctl(fd, FD_SOPTS,
223							  &fdopts) == -1)
224							err(EX_OSERR,
225				    "ioctl(fd, FD_SOPTS, FDOPT_NOERROR)");
226						rv = read(fd, trackbuf,
227							  secsize);
228						if (rv != secsize)
229							err(EX_IOERR,
230				    "read() with FDOPT_NOERROR still fails");
231						fdopts &= ~FDOPT_NOERROR;
232						(void)ioctl(fd, FD_SOPTS,
233							    &fdopts);
234					}
235					if (!quiet) {
236						if (recoverable)
237							fprintf(stderr,
238								": recovered");
239						else
240							fprintf(stderr,
241								": dummy");
242						fprintf(stderr,
243							" data @ %#x ... %#x\n",
244							nbytes,
245							nbytes + secsize - 1);
246					}
247					nbytes += secsize;
248					fwrite(trackbuf, sizeof(unsigned char),
249					       secsize, of);
250					fflush(of);
251					continue;
252				}
253				errx(EX_OSERR, "unexpected read() result: %d",
254				     rv);
255			}
256		}
257	}
258	if (!quiet) {
259		putc('\n', stderr);
260		if (nerrs)
261			fprintf(stderr, "%d error%s\n",
262				nerrs, nerrs > 1? "s": "");
263	}
264
265	return (nerrs? EX_IOERR: EX_OK);
266}
267
268void
269printstatus(struct fdc_status *fdcsp)
270{
271	char msgbuf[100];
272
273	fprintf(stderr,
274		"\nFDC status ST0=%#x ST1=%#x ST2=%#x C=%u H=%u R=%u N=%u:\n",
275		fdcsp->status[0] & 0xff,
276		fdcsp->status[1] & 0xff,
277		fdcsp->status[2] & 0xff,
278		fdcsp->status[3] & 0xff,
279		fdcsp->status[4] & 0xff,
280		fdcsp->status[5] & 0xff,
281		fdcsp->status[6] & 0xff);
282
283	if ((fdcsp->status[0] & NE7_ST0_IC_RC) != NE7_ST0_IC_AT) {
284		sprintf(msgbuf, "unexcpted interrupt code %#x",
285			fdcsp->status[0] & NE7_ST0_IC_RC);
286	} else {
287		strcpy(msgbuf, "unexpected error code in ST1/ST2");
288
289		if (fdcsp->status[1] & NE7_ST1_EN)
290			strcpy(msgbuf, "end of cylinder (wrong format)");
291		else if (fdcsp->status[1] & NE7_ST1_DE) {
292			if (fdcsp->status[2] & NE7_ST2_DD)
293				strcpy(msgbuf, "CRC error in data field");
294			else
295				strcpy(msgbuf, "CRC error in ID field");
296		} else if (fdcsp->status[1] & NE7_ST1_MA) {
297			if (fdcsp->status[2] & NE7_ST2_MD)
298				strcpy(msgbuf, "no address mark in data field");
299			else
300				strcpy(msgbuf, "no address mark in ID field");
301		} else if (fdcsp->status[2] & NE7_ST2_WC)
302			strcpy(msgbuf, "wrong cylinder (format mismatch)");
303		else if (fdcsp->status[1] & NE7_ST1_ND)
304			strcpy(msgbuf, "no data (sector not found)");
305	}
306	fputs(msgbuf, stderr);
307}
308