1330449Seadler/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
476589Sjoerg * Copyright (c) 2001 Joerg Wunsch
576589Sjoerg *
676589Sjoerg * All rights reserved.
776589Sjoerg *
876589Sjoerg * Redistribution and use in source and binary forms, with or without
976589Sjoerg * modification, are permitted provided that the following conditions
1076589Sjoerg * are met:
1176589Sjoerg * 1. Redistributions of source code must retain the above copyright
1276589Sjoerg *    notice, this list of conditions and the following disclaimer.
1376589Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
1476589Sjoerg *    notice, this list of conditions and the following disclaimer in the
1576589Sjoerg *    documentation and/or other materials provided with the distribution.
1676589Sjoerg *
1776589Sjoerg * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
1876589Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1976589Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2076589Sjoerg * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
2176589Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2276589Sjoerg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2376589Sjoerg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2476589Sjoerg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2576589Sjoerg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2676589Sjoerg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2776589Sjoerg *
2876589Sjoerg * $FreeBSD: stable/11/usr.sbin/fdread/fdread.c 330449 2018-03-05 07:26:05Z eadler $
2976589Sjoerg */
3076589Sjoerg
3176589Sjoerg#include <sys/types.h>
3276589Sjoerg#include <sys/stat.h>
3377801Sjoerg#include <sys/fdcio.h>
3476589Sjoerg
3576589Sjoerg#include <err.h>
3676589Sjoerg#include <errno.h>
3776589Sjoerg#include <fcntl.h>
3876589Sjoerg#include <paths.h>
3976589Sjoerg#include <stdio.h>
4076589Sjoerg#include <stdlib.h>
4176589Sjoerg#include <string.h>
4276589Sjoerg#include <sysexits.h>
4376589Sjoerg#include <unistd.h>
4476589Sjoerg
4577729Sjoerg#include <dev/ic/nec765.h>
4676589Sjoerg
4779110Sjoerg#include "fdutil.h"
4879110Sjoerg
49227253Sedstatic int	quiet, recover;
50227253Sedstatic unsigned char fillbyte = 0xf0;	/* "foo" */
5176589Sjoerg
52227253Sedstatic int	doread(int fd, FILE *of, const char *_devname);
53227253Sedstatic int	doreadid(int fd, unsigned int numids, unsigned int trackno);
54227253Sedstatic void	usage(void);
5576589Sjoerg
56227253Sedstatic void
5776589Sjoergusage(void)
5876589Sjoerg{
5976589Sjoerg
6076589Sjoerg	errx(EX_USAGE,
6178857Sjoerg	     "usage: fdread [-qr] [-d device] [-f fillbyte]\n"
6278857Sjoerg	     "       fdread [-d device] -I numids [-t trackno]");
6376589Sjoerg}
6476589Sjoerg
6576589Sjoerg
6676589Sjoergint
6776589Sjoergmain(int argc, char **argv)
6876589Sjoerg{
6976589Sjoerg	int c, errs = 0;
7078857Sjoerg	unsigned int numids = 0, trackno = 0;
71139905Sdelphij	const char *fname = 0, *_devname = "/dev/fd0";
7276589Sjoerg	char *cp;
7376589Sjoerg	FILE *of = stdout;
7476589Sjoerg	int fd;
7576589Sjoerg	unsigned long ul;
7676589Sjoerg
7778857Sjoerg	while ((c = getopt(argc, argv, "d:f:I:o:qrt:")) != -1)
7876589Sjoerg		switch (c) {
7976589Sjoerg		case 'd':
80139905Sdelphij			_devname = optarg;
8176589Sjoerg			break;
8276589Sjoerg
8376589Sjoerg		case 'f':
8476589Sjoerg			ul = strtoul(optarg, &cp, 0);
8576589Sjoerg			if (*cp != '\0') {
8676589Sjoerg				fprintf(stderr,
8776589Sjoerg			"Bad argument %s to -f option; must be numeric\n",
8876589Sjoerg					optarg);
8976589Sjoerg				usage();
9076589Sjoerg			}
9176589Sjoerg			if (ul > 0xff)
9276589Sjoerg				warnx(
9376589Sjoerg			"Warning: fillbyte %#lx too large, truncating\n",
9476589Sjoerg				      ul);
9576589Sjoerg			fillbyte = ul & 0xff;
9676589Sjoerg			break;
9776589Sjoerg
9878857Sjoerg		case 'I':
9978857Sjoerg			ul = strtoul(optarg, &cp, 0);
10078857Sjoerg			if (*cp != '\0') {
10178857Sjoerg				fprintf(stderr,
10278857Sjoerg			"Bad argument %s to -I option; must be numeric\n",
10378857Sjoerg					optarg);
10478857Sjoerg				usage();
10578857Sjoerg			}
10678857Sjoerg			numids = ul;
10778857Sjoerg			break;
10878857Sjoerg
10976589Sjoerg		case 'o':
11076589Sjoerg			fname = optarg;
11176589Sjoerg			break;
11276589Sjoerg
11376589Sjoerg		case 'q':
11476589Sjoerg			quiet++;
11576589Sjoerg			break;
11676589Sjoerg
11776589Sjoerg		case 'r':
11876589Sjoerg			recover++;
11976589Sjoerg			break;
12076589Sjoerg
12178857Sjoerg		case 't':
12278857Sjoerg			ul = strtoul(optarg, &cp, 0);
12378857Sjoerg			if (*cp != '\0') {
12478857Sjoerg				fprintf(stderr,
12578857Sjoerg			"Bad argument %s to -t option; must be numeric\n",
12678857Sjoerg					optarg);
12778857Sjoerg				usage();
12878857Sjoerg			}
12978857Sjoerg			trackno = ul;
13078857Sjoerg			break;
13178857Sjoerg
13276589Sjoerg		default:
13376589Sjoerg			errs++;
13476589Sjoerg		}
13576589Sjoerg	argc -= optind;
13676589Sjoerg	argv += optind;
13776589Sjoerg
13876589Sjoerg	if (argc != 0 || errs)
13976589Sjoerg		usage();
14078857Sjoerg	/* check for mutually exclusive options */
14178857Sjoerg	if (numids) {
14278857Sjoerg		if (fname || quiet || recover)
14378857Sjoerg			usage();
14478857Sjoerg	} else {
14578857Sjoerg		if (trackno)
14678857Sjoerg			usage();
14778857Sjoerg	}
14876589Sjoerg
14976589Sjoerg	if (fname) {
15076589Sjoerg		if ((of = fopen(fname, "w")) == NULL)
15176589Sjoerg			err(EX_OSERR, "cannot create output file %s", fname);
15276589Sjoerg	}
15376589Sjoerg
154223197Sjoerg	if ((fd = open(_devname, O_RDONLY)) == -1)
155139905Sdelphij		err(EX_OSERR, "cannot open device %s", _devname);
15676589Sjoerg
157139905Sdelphij	return (numids? doreadid(fd, numids, trackno): doread(fd, of, _devname));
15876589Sjoerg}
15976589Sjoerg
160227253Sedstatic int
161139905Sdelphijdoread(int fd, FILE *of, const char *_devname)
16276589Sjoerg{
16376589Sjoerg	char *trackbuf;
16476589Sjoerg	int rv, fdopts, recoverable, nerrs = 0;
16576589Sjoerg	unsigned int nbytes, tracksize, mediasize, secsize, n;
16676589Sjoerg	struct fdc_status fdcs;
16776589Sjoerg	struct fd_type fdt;
16876589Sjoerg
16976589Sjoerg	if (ioctl(fd, FD_GTYPE, &fdt) == -1)
17076589Sjoerg		err(EX_OSERR, "ioctl(FD_GTYPE) failed -- not a floppy?");
17176589Sjoerg
17276589Sjoerg	secsize = 128 << fdt.secsize;
17376589Sjoerg	tracksize = fdt.sectrac * secsize;
17476589Sjoerg	mediasize = tracksize * fdt.tracks * fdt.heads;
175297962Saraujo	if ((trackbuf = malloc(tracksize)) == NULL)
17676589Sjoerg		errx(EX_TEMPFAIL, "out of memory");
17776589Sjoerg
17876589Sjoerg	if (!quiet)
17976589Sjoerg		fprintf(stderr, "Reading %d * %d * %d * %d medium at %s\n",
180139905Sdelphij			fdt.tracks, fdt.heads, fdt.sectrac, secsize, _devname);
18176589Sjoerg
18276589Sjoerg	for (nbytes = 0; nbytes < mediasize;) {
18376589Sjoerg		if (lseek(fd, nbytes, SEEK_SET) != nbytes)
18476589Sjoerg			err(EX_OSERR, "cannot lseek()");
18576589Sjoerg		rv = read(fd, trackbuf, tracksize);
18676589Sjoerg		if (rv == 0) {
18776589Sjoerg			/* EOF? */
18876589Sjoerg			warnx("premature EOF after %u bytes", nbytes);
189318395Saraujo			free(trackbuf);
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");
221318395Saraujo						free(trackbuf);
22276589Sjoerg						return (EX_OSERR);
22376589Sjoerg					}
22476589Sjoerg					if (ioctl(fd, FD_GSTAT, &fdcs) == -1)
22576589Sjoerg						errx(EX_IOERR,
22676589Sjoerg				     "floppy IO error, but no FDC status");
22776589Sjoerg					nerrs++;
22876589Sjoerg					recoverable = fdcs.status[2] &
22976589Sjoerg						NE7_ST2_DD;
23076589Sjoerg					if (!quiet) {
23179110Sjoerg						printstatus(&fdcs, 0);
23276589Sjoerg						fputs(" (", stderr);
23376589Sjoerg						if (!recoverable)
23476589Sjoerg							fputs("not ", stderr);
23576589Sjoerg						fputs("recoverable)", stderr);
23676589Sjoerg					}
23776589Sjoerg					if (!recover) {
23876589Sjoerg						if (!quiet)
23976589Sjoerg							putc('\n', stderr);
240318395Saraujo						free(trackbuf);
24176589Sjoerg						return (EX_IOERR);
24276589Sjoerg					}
24376589Sjoerg					memset(trackbuf, fillbyte, secsize);
24476589Sjoerg					if (recoverable) {
24576589Sjoerg						fdopts |= FDOPT_NOERROR;
24676589Sjoerg						if (ioctl(fd, FD_SOPTS,
24776589Sjoerg							  &fdopts) == -1)
24876589Sjoerg							err(EX_OSERR,
24976589Sjoerg				    "ioctl(fd, FD_SOPTS, FDOPT_NOERROR)");
25076589Sjoerg						rv = read(fd, trackbuf,
25176589Sjoerg							  secsize);
252139905Sdelphij						if ((unsigned)rv != secsize)
25376589Sjoerg							err(EX_IOERR,
25476589Sjoerg				    "read() with FDOPT_NOERROR still fails");
25576589Sjoerg						fdopts &= ~FDOPT_NOERROR;
25676589Sjoerg						(void)ioctl(fd, FD_SOPTS,
25776589Sjoerg							    &fdopts);
25876589Sjoerg					}
25976589Sjoerg					if (!quiet) {
26076589Sjoerg						if (recoverable)
26176589Sjoerg							fprintf(stderr,
26276589Sjoerg								": recovered");
26376589Sjoerg						else
26476589Sjoerg							fprintf(stderr,
26576589Sjoerg								": dummy");
26676589Sjoerg						fprintf(stderr,
26776589Sjoerg							" data @ %#x ... %#x\n",
26876589Sjoerg							nbytes,
26976589Sjoerg							nbytes + secsize - 1);
27076589Sjoerg					}
27176589Sjoerg					nbytes += secsize;
27276589Sjoerg					fwrite(trackbuf, sizeof(unsigned char),
27376589Sjoerg					       secsize, of);
27476589Sjoerg					fflush(of);
27576589Sjoerg					continue;
27676589Sjoerg				}
27776589Sjoerg				errx(EX_OSERR, "unexpected read() result: %d",
27876589Sjoerg				     rv);
27976589Sjoerg			}
28076589Sjoerg		}
281139905Sdelphij		if ((unsigned)rv < tracksize) {
282139905Sdelphij			/* should not happen */
283139905Sdelphij			nbytes += rv;
284139905Sdelphij			if (!quiet)
285139905Sdelphij				fprintf(stderr, "\nshort after %5d KB\r",
286139905Sdelphij					nbytes / 1024);
287139905Sdelphij			fwrite(trackbuf, sizeof(unsigned char), rv, of);
288139905Sdelphij			fflush(of);
289139905Sdelphij			continue;
290139905Sdelphij		}
29176589Sjoerg	}
292318395Saraujo	free(trackbuf);
29376589Sjoerg	if (!quiet) {
29476589Sjoerg		putc('\n', stderr);
29576589Sjoerg		if (nerrs)
29676589Sjoerg			fprintf(stderr, "%d error%s\n",
29776589Sjoerg				nerrs, nerrs > 1? "s": "");
29876589Sjoerg	}
29976589Sjoerg
30076589Sjoerg	return (nerrs? EX_IOERR: EX_OK);
30176589Sjoerg}
30276589Sjoerg
303227253Sedstatic int
30478857Sjoergdoreadid(int fd, unsigned int numids, unsigned int trackno)
30578857Sjoerg{
306194892Sjoerg	int rv = 0;
30778857Sjoerg	unsigned int i;
30878857Sjoerg	struct fdc_readid info;
30978857Sjoerg	struct fdc_status fdcs;
31078857Sjoerg	struct fd_type fdt;
31178857Sjoerg
31278857Sjoerg	if (ioctl(fd, FD_GTYPE, &fdt) == -1)
31378857Sjoerg		err(EX_OSERR, "ioctl(FD_GTYPE) failed -- not a floppy?");
31478857Sjoerg
31578857Sjoerg	for (i = 0; i < numids; i++) {
31678857Sjoerg		info.cyl = trackno / fdt.heads;
31778857Sjoerg		info.head = fdt.heads > 1? trackno % fdt.heads: 0;
318160522Sstefanf		if (ioctl(fd, FD_READID, &info) == 0) {
31978857Sjoerg			printf("C = %d, H = %d, R = %d, N = %d\n",
32078857Sjoerg			       info.cyl, info.head, info.sec, info.secshift);
32178857Sjoerg		} else {
32278857Sjoerg			if (errno != EIO) {
32378857Sjoerg				perror("non-IO error");
32478857Sjoerg				return (EX_OSERR);
32578857Sjoerg			}
32678857Sjoerg			if (ioctl(fd, FD_GSTAT, &fdcs) == -1)
32778857Sjoerg				errx(EX_IOERR,
32878857Sjoerg				     "floppy IO error, but no FDC status");
32979110Sjoerg			printstatus(&fdcs, 0);
33078857Sjoerg			putc('\n', stderr);
33178857Sjoerg			rv = EX_IOERR;
33278857Sjoerg		}
33378857Sjoerg	}
33478857Sjoerg
33578857Sjoerg	return (rv);
33678857Sjoerg}
337