diff options
Diffstat (limited to 'usr.sbin/fdread/fdread.c')
-rw-r--r-- | usr.sbin/fdread/fdread.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/usr.sbin/fdread/fdread.c b/usr.sbin/fdread/fdread.c new file mode 100644 index 0000000..770f92d --- /dev/null +++ b/usr.sbin/fdread/fdread.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2001 Joerg Wunsch + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/fdcio.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> + +#include <dev/ic/nec765.h> + +#include "fdutil.h" + +static int quiet, recover; +static unsigned char fillbyte = 0xf0; /* "foo" */ + +static int doread(int fd, FILE *of, const char *_devname); +static int doreadid(int fd, unsigned int numids, unsigned int trackno); +static void usage(void); + +static void +usage(void) +{ + + errx(EX_USAGE, + "usage: fdread [-qr] [-d device] [-f fillbyte]\n" + " fdread [-d device] -I numids [-t trackno]"); +} + + +int +main(int argc, char **argv) +{ + int c, errs = 0; + unsigned int numids = 0, trackno = 0; + const char *fname = 0, *_devname = "/dev/fd0"; + char *cp; + FILE *of = stdout; + int fd; + unsigned long ul; + + while ((c = getopt(argc, argv, "d:f:I:o:qrt:")) != -1) + switch (c) { + case 'd': + _devname = optarg; + break; + + case 'f': + ul = strtoul(optarg, &cp, 0); + if (*cp != '\0') { + fprintf(stderr, + "Bad argument %s to -f option; must be numeric\n", + optarg); + usage(); + } + if (ul > 0xff) + warnx( + "Warning: fillbyte %#lx too large, truncating\n", + ul); + fillbyte = ul & 0xff; + break; + + case 'I': + ul = strtoul(optarg, &cp, 0); + if (*cp != '\0') { + fprintf(stderr, + "Bad argument %s to -I option; must be numeric\n", + optarg); + usage(); + } + numids = ul; + break; + + case 'o': + fname = optarg; + break; + + case 'q': + quiet++; + break; + + case 'r': + recover++; + break; + + case 't': + ul = strtoul(optarg, &cp, 0); + if (*cp != '\0') { + fprintf(stderr, + "Bad argument %s to -t option; must be numeric\n", + optarg); + usage(); + } + trackno = ul; + break; + + default: + errs++; + } + argc -= optind; + argv += optind; + + if (argc != 0 || errs) + usage(); + /* check for mutually exclusive options */ + if (numids) { + if (fname || quiet || recover) + usage(); + } else { + if (trackno) + usage(); + } + + if (fname) { + if ((of = fopen(fname, "w")) == NULL) + err(EX_OSERR, "cannot create output file %s", fname); + } + + if ((fd = open(_devname, O_RDONLY)) == -1) + err(EX_OSERR, "cannot open device %s", _devname); + + return (numids? doreadid(fd, numids, trackno): doread(fd, of, _devname)); +} + +static int +doread(int fd, FILE *of, const char *_devname) +{ + char *trackbuf; + int rv, fdopts, recoverable, nerrs = 0; + unsigned int nbytes, tracksize, mediasize, secsize, n; + struct fdc_status fdcs; + struct fd_type fdt; + + if (ioctl(fd, FD_GTYPE, &fdt) == -1) + err(EX_OSERR, "ioctl(FD_GTYPE) failed -- not a floppy?"); + + secsize = 128 << fdt.secsize; + tracksize = fdt.sectrac * secsize; + mediasize = tracksize * fdt.tracks * fdt.heads; + if ((trackbuf = malloc(tracksize)) == 0) + errx(EX_TEMPFAIL, "out of memory"); + + if (!quiet) + fprintf(stderr, "Reading %d * %d * %d * %d medium at %s\n", + fdt.tracks, fdt.heads, fdt.sectrac, secsize, _devname); + + for (nbytes = 0; nbytes < mediasize;) { + if (lseek(fd, nbytes, SEEK_SET) != nbytes) + err(EX_OSERR, "cannot lseek()"); + rv = read(fd, trackbuf, tracksize); + if (rv == 0) { + /* EOF? */ + warnx("premature EOF after %u bytes", nbytes); + return (EX_OK); + } + if ((unsigned)rv == tracksize) { + nbytes += rv; + if (!quiet) + fprintf(stderr, "%5d KB\r", nbytes / 1024); + fwrite(trackbuf, sizeof(unsigned char), rv, of); + fflush(of); + continue; + } + if (rv == -1) { + /* fall back reading one sector at a time */ + for (n = 0; n < tracksize; n += secsize) { + if (lseek(fd, nbytes, SEEK_SET) != nbytes) + err(EX_OSERR, "cannot lseek()"); + rv = read(fd, trackbuf, secsize); + if ((unsigned) rv == secsize) { + nbytes += rv; + if (!quiet) + fprintf(stderr, "%5d KB\r", + nbytes / 1024); + fwrite(trackbuf, sizeof(unsigned char), + rv, of); + fflush(of); + continue; + } + if (rv == -1) { + if (errno != EIO) { + if (!quiet) + putc('\n', stderr); + perror("non-IO error"); + return (EX_OSERR); + } + if (ioctl(fd, FD_GSTAT, &fdcs) == -1) + errx(EX_IOERR, + "floppy IO error, but no FDC status"); + nerrs++; + recoverable = fdcs.status[2] & + NE7_ST2_DD; + if (!quiet) { + printstatus(&fdcs, 0); + fputs(" (", stderr); + if (!recoverable) + fputs("not ", stderr); + fputs("recoverable)", stderr); + } + if (!recover) { + if (!quiet) + putc('\n', stderr); + return (EX_IOERR); + } + memset(trackbuf, fillbyte, secsize); + if (recoverable) { + fdopts |= FDOPT_NOERROR; + if (ioctl(fd, FD_SOPTS, + &fdopts) == -1) + err(EX_OSERR, + "ioctl(fd, FD_SOPTS, FDOPT_NOERROR)"); + rv = read(fd, trackbuf, + secsize); + if ((unsigned)rv != secsize) + err(EX_IOERR, + "read() with FDOPT_NOERROR still fails"); + fdopts &= ~FDOPT_NOERROR; + (void)ioctl(fd, FD_SOPTS, + &fdopts); + } + if (!quiet) { + if (recoverable) + fprintf(stderr, + ": recovered"); + else + fprintf(stderr, + ": dummy"); + fprintf(stderr, + " data @ %#x ... %#x\n", + nbytes, + nbytes + secsize - 1); + } + nbytes += secsize; + fwrite(trackbuf, sizeof(unsigned char), + secsize, of); + fflush(of); + continue; + } + errx(EX_OSERR, "unexpected read() result: %d", + rv); + } + } + if ((unsigned)rv < tracksize) { + /* should not happen */ + nbytes += rv; + if (!quiet) + fprintf(stderr, "\nshort after %5d KB\r", + nbytes / 1024); + fwrite(trackbuf, sizeof(unsigned char), rv, of); + fflush(of); + continue; + } + } + if (!quiet) { + putc('\n', stderr); + if (nerrs) + fprintf(stderr, "%d error%s\n", + nerrs, nerrs > 1? "s": ""); + } + + return (nerrs? EX_IOERR: EX_OK); +} + +static int +doreadid(int fd, unsigned int numids, unsigned int trackno) +{ + int rv = 0; + unsigned int i; + struct fdc_readid info; + struct fdc_status fdcs; + struct fd_type fdt; + + if (ioctl(fd, FD_GTYPE, &fdt) == -1) + err(EX_OSERR, "ioctl(FD_GTYPE) failed -- not a floppy?"); + + for (i = 0; i < numids; i++) { + info.cyl = trackno / fdt.heads; + info.head = fdt.heads > 1? trackno % fdt.heads: 0; + if (ioctl(fd, FD_READID, &info) == 0) { + printf("C = %d, H = %d, R = %d, N = %d\n", + info.cyl, info.head, info.sec, info.secshift); + } else { + if (errno != EIO) { + perror("non-IO error"); + return (EX_OSERR); + } + if (ioctl(fd, FD_GSTAT, &fdcs) == -1) + errx(EX_IOERR, + "floppy IO error, but no FDC status"); + printstatus(&fdcs, 0); + putc('\n', stderr); + rv = EX_IOERR; + } + } + + return (rv); +} |