The SPDX folks have obsoleted the BSD-2-Clause-FreeBSD identifier. Catch up to that fact and revert to their recommended match of BSD-2-Clause. Discussed with: pfg MFC After: 3 days Sponsored by: Netflix
337 lines
8.0 KiB
C
337 lines
8.0 KiB
C
/*-
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* 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)) == NULL)
|
|
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);
|
|
free(trackbuf);
|
|
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");
|
|
free(trackbuf);
|
|
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);
|
|
free(trackbuf);
|
|
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;
|
|
}
|
|
}
|
|
free(trackbuf);
|
|
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);
|
|
}
|