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$
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
47227253Sedstatic int	quiet, recover;
48227253Sedstatic unsigned char fillbyte = 0xf0;	/* "foo" */
4976589Sjoerg
50227253Sedstatic int	doread(int fd, FILE *of, const char *_devname);
51227253Sedstatic int	doreadid(int fd, unsigned int numids, unsigned int trackno);
52227253Sedstatic void	usage(void);
5376589Sjoerg
54227253Sedstatic void
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
152223197Sjoerg	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
158227253Sedstatic int
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
17076589Sjoerg	secsize = 128 << fdt.secsize;
17176589Sjoerg	tracksize = fdt.sectrac * secsize;
17276589Sjoerg	mediasize = tracksize * fdt.tracks * fdt.heads;
17376589Sjoerg	if ((trackbuf = malloc(tracksize)) == 0)
17476589Sjoerg		errx(EX_TEMPFAIL, "out of memory");
17576589Sjoerg
17676589Sjoerg	if (!quiet)
17776589Sjoerg		fprintf(stderr, "Reading %d * %d * %d * %d medium at %s\n",
178139905Sdelphij			fdt.tracks, fdt.heads, fdt.sectrac, secsize, _devname);
17976589Sjoerg
18076589Sjoerg	for (nbytes = 0; nbytes < mediasize;) {
18176589Sjoerg		if (lseek(fd, nbytes, SEEK_SET) != nbytes)
18276589Sjoerg			err(EX_OSERR, "cannot lseek()");
18376589Sjoerg		rv = read(fd, trackbuf, tracksize);
18476589Sjoerg		if (rv == 0) {
18576589Sjoerg			/* EOF? */
18676589Sjoerg			warnx("premature EOF after %u bytes", nbytes);
18776589Sjoerg			return (EX_OK);
18876589Sjoerg		}
189139905Sdelphij		if ((unsigned)rv == tracksize) {
19076589Sjoerg			nbytes += rv;
19176589Sjoerg			if (!quiet)
19276589Sjoerg				fprintf(stderr, "%5d KB\r", nbytes / 1024);
19376589Sjoerg			fwrite(trackbuf, sizeof(unsigned char), rv, of);
19476589Sjoerg			fflush(of);
19576589Sjoerg			continue;
19676589Sjoerg		}
19776589Sjoerg		if (rv == -1) {
19876589Sjoerg			/* fall back reading one sector at a time */
19976589Sjoerg			for (n = 0; n < tracksize; n += secsize) {
20076589Sjoerg				if (lseek(fd, nbytes, SEEK_SET) != nbytes)
20176589Sjoerg					err(EX_OSERR, "cannot lseek()");
20276589Sjoerg				rv = read(fd, trackbuf, secsize);
203139905Sdelphij				if ((unsigned) rv == secsize) {
20476589Sjoerg					nbytes += rv;
20576589Sjoerg					if (!quiet)
20676589Sjoerg						fprintf(stderr, "%5d KB\r",
20776589Sjoerg							nbytes / 1024);
20876589Sjoerg					fwrite(trackbuf, sizeof(unsigned char),
20976589Sjoerg					       rv, of);
21076589Sjoerg					fflush(of);
21176589Sjoerg					continue;
21276589Sjoerg				}
21376589Sjoerg				if (rv == -1) {
21476589Sjoerg					if (errno != EIO) {
21576589Sjoerg						if (!quiet)
21676589Sjoerg							putc('\n', stderr);
21776589Sjoerg						perror("non-IO error");
21876589Sjoerg						return (EX_OSERR);
21976589Sjoerg					}
22076589Sjoerg					if (ioctl(fd, FD_GSTAT, &fdcs) == -1)
22176589Sjoerg						errx(EX_IOERR,
22276589Sjoerg				     "floppy IO error, but no FDC status");
22376589Sjoerg					nerrs++;
22476589Sjoerg					recoverable = fdcs.status[2] &
22576589Sjoerg						NE7_ST2_DD;
22676589Sjoerg					if (!quiet) {
22779110Sjoerg						printstatus(&fdcs, 0);
22876589Sjoerg						fputs(" (", stderr);
22976589Sjoerg						if (!recoverable)
23076589Sjoerg							fputs("not ", stderr);
23176589Sjoerg						fputs("recoverable)", stderr);
23276589Sjoerg					}
23376589Sjoerg					if (!recover) {
23476589Sjoerg						if (!quiet)
23576589Sjoerg							putc('\n', stderr);
23676589Sjoerg						return (EX_IOERR);
23776589Sjoerg					}
23876589Sjoerg					memset(trackbuf, fillbyte, secsize);
23976589Sjoerg					if (recoverable) {
24076589Sjoerg						fdopts |= FDOPT_NOERROR;
24176589Sjoerg						if (ioctl(fd, FD_SOPTS,
24276589Sjoerg							  &fdopts) == -1)
24376589Sjoerg							err(EX_OSERR,
24476589Sjoerg				    "ioctl(fd, FD_SOPTS, FDOPT_NOERROR)");
24576589Sjoerg						rv = read(fd, trackbuf,
24676589Sjoerg							  secsize);
247139905Sdelphij						if ((unsigned)rv != secsize)
24876589Sjoerg							err(EX_IOERR,
24976589Sjoerg				    "read() with FDOPT_NOERROR still fails");
25076589Sjoerg						fdopts &= ~FDOPT_NOERROR;
25176589Sjoerg						(void)ioctl(fd, FD_SOPTS,
25276589Sjoerg							    &fdopts);
25376589Sjoerg					}
25476589Sjoerg					if (!quiet) {
25576589Sjoerg						if (recoverable)
25676589Sjoerg							fprintf(stderr,
25776589Sjoerg								": recovered");
25876589Sjoerg						else
25976589Sjoerg							fprintf(stderr,
26076589Sjoerg								": dummy");
26176589Sjoerg						fprintf(stderr,
26276589Sjoerg							" data @ %#x ... %#x\n",
26376589Sjoerg							nbytes,
26476589Sjoerg							nbytes + secsize - 1);
26576589Sjoerg					}
26676589Sjoerg					nbytes += secsize;
26776589Sjoerg					fwrite(trackbuf, sizeof(unsigned char),
26876589Sjoerg					       secsize, of);
26976589Sjoerg					fflush(of);
27076589Sjoerg					continue;
27176589Sjoerg				}
27276589Sjoerg				errx(EX_OSERR, "unexpected read() result: %d",
27376589Sjoerg				     rv);
27476589Sjoerg			}
27576589Sjoerg		}
276139905Sdelphij		if ((unsigned)rv < tracksize) {
277139905Sdelphij			/* should not happen */
278139905Sdelphij			nbytes += rv;
279139905Sdelphij			if (!quiet)
280139905Sdelphij				fprintf(stderr, "\nshort after %5d KB\r",
281139905Sdelphij					nbytes / 1024);
282139905Sdelphij			fwrite(trackbuf, sizeof(unsigned char), rv, of);
283139905Sdelphij			fflush(of);
284139905Sdelphij			continue;
285139905Sdelphij		}
28676589Sjoerg	}
28776589Sjoerg	if (!quiet) {
28876589Sjoerg		putc('\n', stderr);
28976589Sjoerg		if (nerrs)
29076589Sjoerg			fprintf(stderr, "%d error%s\n",
29176589Sjoerg				nerrs, nerrs > 1? "s": "");
29276589Sjoerg	}
29376589Sjoerg
29476589Sjoerg	return (nerrs? EX_IOERR: EX_OK);
29576589Sjoerg}
29676589Sjoerg
297227253Sedstatic int
29878857Sjoergdoreadid(int fd, unsigned int numids, unsigned int trackno)
29978857Sjoerg{
300194892Sjoerg	int rv = 0;
30178857Sjoerg	unsigned int i;
30278857Sjoerg	struct fdc_readid info;
30378857Sjoerg	struct fdc_status fdcs;
30478857Sjoerg	struct fd_type fdt;
30578857Sjoerg
30678857Sjoerg	if (ioctl(fd, FD_GTYPE, &fdt) == -1)
30778857Sjoerg		err(EX_OSERR, "ioctl(FD_GTYPE) failed -- not a floppy?");
30878857Sjoerg
30978857Sjoerg	for (i = 0; i < numids; i++) {
31078857Sjoerg		info.cyl = trackno / fdt.heads;
31178857Sjoerg		info.head = fdt.heads > 1? trackno % fdt.heads: 0;
312160522Sstefanf		if (ioctl(fd, FD_READID, &info) == 0) {
31378857Sjoerg			printf("C = %d, H = %d, R = %d, N = %d\n",
31478857Sjoerg			       info.cyl, info.head, info.sec, info.secshift);
31578857Sjoerg		} else {
31678857Sjoerg			if (errno != EIO) {
31778857Sjoerg				perror("non-IO error");
31878857Sjoerg				return (EX_OSERR);
31978857Sjoerg			}
32078857Sjoerg			if (ioctl(fd, FD_GSTAT, &fdcs) == -1)
32178857Sjoerg				errx(EX_IOERR,
32278857Sjoerg				     "floppy IO error, but no FDC status");
32379110Sjoerg			printstatus(&fdcs, 0);
32478857Sjoerg			putc('\n', stderr);
32578857Sjoerg			rv = EX_IOERR;
32678857Sjoerg		}
32778857Sjoerg	}
32878857Sjoerg
32978857Sjoerg	return (rv);
33078857Sjoerg}
331