aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/fdcontrol/Makefile4
-rw-r--r--usr.sbin/fdcontrol/fdcontrol.c206
-rw-r--r--usr.sbin/fdformat/fdformat.c297
-rw-r--r--usr.sbin/fdread/fdutil.c392
-rw-r--r--usr.sbin/fdread/fdutil.h8
5 files changed, 663 insertions, 244 deletions
diff --git a/usr.sbin/fdcontrol/Makefile b/usr.sbin/fdcontrol/Makefile
index ec411d7a48a0..38f9a1ed3bb0 100644
--- a/usr.sbin/fdcontrol/Makefile
+++ b/usr.sbin/fdcontrol/Makefile
@@ -1,8 +1,12 @@
# $FreeBSD$
+.PATH: ${.CURDIR}/../fdread
+
PROG= fdcontrol
+SRCS= fdcontrol.c fdutil.c
MAN= fdcontrol.8
WARNS?= 2
+CFLAGS+= -I${.CURDIR}/../fdread
.include <bsd.prog.mk>
diff --git a/usr.sbin/fdcontrol/fdcontrol.c b/usr.sbin/fdcontrol/fdcontrol.c
index e1200592a2b5..9d447a5447a6 100644
--- a/usr.sbin/fdcontrol/fdcontrol.c
+++ b/usr.sbin/fdcontrol/fdcontrol.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1994 by Joerg Wunsch, Dresden
+ * Copyright (C) 1994, 2001 by Joerg Wunsch, Dresden
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,110 +36,144 @@ static const char rcsid[] =
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
#include <unistd.h>
-static int getnumber(void);
-static void usage(void);
+#include "fdutil.h"
-static int
-getnumber(void)
-{
- int i;
- char b[80];
- fgets(b, 80, stdin);
- if(b[0] == '\n') return -1;
+static int debug = -1, format, verbose, show = 1, showfmt;
+static char *fmtstring;
- sscanf(b, " %i", &i);
- return i;
-}
+static void showdev(enum fd_drivetype, const char *);
+static void usage(void);
static void
usage(void)
{
- fprintf(stderr, "usage: fdcontrol [-d 0|1] | [-s] device-node\n");
- exit(2);
+ errx(EX_USAGE,
+ "usage: fdcontrol [-F] [-d dbg] [-f fmt] [-s fmtstr] [-v] device");
}
+void
+showdev(enum fd_drivetype type, const char *fname)
+{
+ const char *name, *descr;
-#define ask(name, fmt) \
-printf(#name "? [" fmt "]: ", ft.name); fflush(stdout); \
-if((i = getnumber()) != -1) ft.name = i
+ getname(type, &name, &descr);
+ if (verbose)
+ printf("%s: %s drive (%s)\n", fname, name, descr);
+ else
+ printf("%s\n", name);
+}
int
main(int argc, char **argv)
{
- struct fd_type ft;
- int fd, i;
- int debug = -1, settype = 1;
-
- while((i = getopt(argc, argv, "d:s")) != -1)
- switch(i)
- {
- case 'd':
- debug = atoi(optarg);
- settype = 0;
- break;
-
- case 's':
- debug = -1;
- settype = 1;
- break;
-
- case '?':
- default:
- usage();
- }
-
- argc -= optind;
- argv += optind;
-
- if(argc != 1)
- usage();
-
- if((fd = open(argv[0], 0)) < 0)
- {
- warn("open(floppy)");
- return 1;
- }
-
- if(debug != -1)
- {
- if(ioctl(fd, FD_DEBUG, &debug) < 0)
- {
- warn("ioctl(FD_DEBUG)");
- return 1;
+ enum fd_drivetype type;
+ struct fd_type ft, newft, *fdtp;
+ const char *name, *descr;
+ int fd, i, mode;
+
+ while((i = getopt(argc, argv, "d:Ff:s:v")) != -1)
+ switch(i) {
+ case 'd':
+ if (strcmp(optarg, "0") == 0)
+ debug = 0;
+ else if (strcmp(optarg, "1") == 0)
+ debug = 1;
+ else
+ usage();
+ show = 0;
+ break;
+
+ case 'F':
+ showfmt = 1;
+ show = 0;
+ break;
+
+ case 'f':
+ if (getnum(optarg, &format)) {
+ fprintf(stderr,
+ "Bad argument %s to -f option; must be numeric\n",
+ optarg);
+ usage();
+ }
+ show = 0;
+ break;
+
+ case 's':
+ fmtstring = optarg;
+ show = 0;
+ break;
+
+ case 'v':
+ verbose++;
+ break;
+
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if(argc != 1)
+ usage();
+
+ if (show || showfmt)
+ mode = O_RDONLY | O_NONBLOCK;
+ else
+ mode = O_RDWR;
+
+ if((fd = open(argv[0], mode)) < 0)
+ err(EX_UNAVAILABLE, "open(%s)", argv[0]);
+
+ if (ioctl(fd, FD_GDTYPE, &type) == -1)
+ err(EX_OSERR, "ioctl(FD_GDTYPE)");
+ if (ioctl(fd, FD_GTYPE, &ft) == -1)
+ err(EX_OSERR, "ioctl(FD_GTYPE)");
+
+ if (show) {
+ showdev(type, argv[0]);
+ return (0);
}
- return 0;
- }
-
- if(settype)
- {
- if(ioctl(fd, FD_GTYPE, &ft) < 0)
- {
- warn("ioctl(FD_GTYPE)");
- return 1;
+
+ if (format) {
+ getname(type, &name, &descr);
+ fdtp = get_fmt(format, type);
+ if (fdtp == 0)
+ errx(EX_USAGE,
+ "unknown format %d KB for drive type %s",
+ format, name);
+ ft = *fdtp;
+ }
+
+ if (fmtstring) {
+ parse_fmt(fmtstring, type, ft, &newft);
+ ft = newft;
+ }
+
+ if (showfmt) {
+ if (verbose)
+ printf("%s: %d KB media type, fmt = ",
+ argv[0], ft.size / 2);
+ print_fmt(ft);
+ return (0);
+ }
+
+ if (format || fmtstring) {
+ if (ioctl(fd, FD_STYPE, &ft) == -1)
+ err(EX_OSERR, "ioctl(FD_STYPE)");
+ return (0);
}
- ask(sectrac, "%d");
- ask(secsize, "%d");
- ask(datalen, "0x%x");
- ask(gap, "0x%x");
- ask(tracks, "%d");
- ask(size, "%d");
- ask(steptrac, "%d");
- ask(trans, "%d");
- ask(heads, "%d");
- ask(f_gap, "0x%x");
- ask(f_inter, "%d");
-
- if(ioctl(fd, FD_STYPE, &ft) < 0)
- {
- warn("ioctl(FD_STYPE)");
- return 1;
+ if (debug != -1) {
+ if (ioctl(fd, FD_DEBUG, &debug) == -1)
+ err(EX_OSERR, "ioctl(FD_DEBUG)");
+ return (0);
}
- return 0;
- }
- return 0;
+ return 0;
}
diff --git a/usr.sbin/fdformat/fdformat.c b/usr.sbin/fdformat/fdformat.c
index 0c194b3e0817..0e037b4fec0c 100644
--- a/usr.sbin/fdformat/fdformat.c
+++ b/usr.sbin/fdformat/fdformat.c
@@ -26,19 +26,9 @@
* $FreeBSD$
*/
-/*
- * FreeBSD:
- * format a floppy disk
- *
- * Added FD_GTYPE ioctl, verifying, proportional indicators.
- * Serge Vakulenko, vak@zebub.msk.su
- * Sat Dec 18 17:45:47 MSK 1993
- *
- * Final adaptation, change format/verify logic, add separate
- * format gap/interleave values
- * Andrew A. Chernov, ache@astral.msk.su
- * Thu Jan 27 00:47:24 MSK 1994
- */
+#include <sys/types.h>
+#include <sys/fdcio.h>
+#include <sys/stat.h>
#include <ctype.h>
#include <err.h>
@@ -48,24 +38,24 @@
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
+#include <sysexits.h>
#include <unistd.h>
-#include <sys/fdcio.h>
-
#include "fdutil.h"
static void
format_track(int fd, int cyl, int secs, int head, int rate,
- int gaplen, int secsize, int fill,int interleave)
+ int gaplen, int secsize, int fill, int interleave,
+ int offset)
{
struct fd_formb f;
- register int i,j;
- int il[FD_MAX_NSEC + 1];
+ int i, j, il[FD_MAX_NSEC + 1];
- memset(il,0,sizeof il);
- for(j = 0, i = 1; i <= secs; i++) {
- while(il[(j%secs)+1]) j++;
- il[(j%secs)+1] = i;
+ memset(il, 0, sizeof il);
+ for(j = 0, i = 1 + offset; i <= secs + offset; i++) {
+ while(il[(j % secs) + 1])
+ j++;
+ il[(j % secs) + 1] = i;
j += interleave;
}
@@ -85,14 +75,14 @@ format_track(int fd, int cyl, int secs, int head, int rate,
f.fd_formb_secsize(i) = secsize;
}
if(ioctl(fd, FD_FORM, (caddr_t)&f) < 0)
- err(1, "ioctl(FD_FORM)");
+ err(EX_OSERR, "ioctl(FD_FORM)");
}
static int
verify_track(int fd, int track, int tracksize)
{
- static char *buf = 0;
- static int bufsz = 0;
+ static char *buf;
+ static int bufsz;
int fdopts = -1, ofdopts, rv = 0;
if (ioctl(fd, FD_GOPTS, &fdopts) < 0)
@@ -103,61 +93,37 @@ verify_track(int fd, int track, int tracksize)
(void)ioctl(fd, FD_SOPTS, &fdopts);
}
- if (bufsz < tracksize) {
- if (buf)
- free (buf);
- bufsz = tracksize;
- buf = 0;
- }
- if (! buf)
- buf = malloc (bufsz);
- if (! buf)
- errx(2, "out of memory");
- if (lseek (fd, (long) track*tracksize, 0) < 0)
+ if (bufsz < tracksize)
+ buf = realloc(buf, bufsz = tracksize);
+ if (buf == 0)
+ errx(EX_UNAVAILABLE, "out of memory");
+ if (lseek (fd, (long) track * tracksize, 0) < 0)
rv = -1;
/* try twice reading it, without using the normal retrier */
else if (read (fd, buf, tracksize) != tracksize
&& read (fd, buf, tracksize) != tracksize)
rv = -1;
- if(fdopts != -1)
+ if (fdopts != -1)
(void)ioctl(fd, FD_SOPTS, &ofdopts);
return (rv);
}
-static const char *
-makename(const char *arg, const char *suffix)
-{
- static char namebuff[20]; /* big enough for "/dev/fd0a"... */
-
- memset(namebuff, 0, 20);
- if(*arg == '\0') /* ??? */
- return arg;
- if(*arg == '/') /* do not convert absolute pathnames */
- return arg;
- strcpy(namebuff, _PATH_DEV);
- strncat(namebuff, arg, 3);
- strcat(namebuff, suffix);
- return namebuff;
-}
-
static void
usage (void)
{
- fprintf(stderr, "%s\n%s\n",
- "usage: fdformat [-y] [-q] [-n | -v] [-f #] [-c #] [-s #] [-h #]",
- " [-r #] [-g #] [-i #] [-S #] [-F #] [-t #] device_name");
- exit(2);
+ errx(EX_USAGE,
+ "usage: fdformat [-F fill] [-f fmt] [-s fmtstr] [-nqvy] device");
}
static int
yes (void)
{
- char reply [256], *p;
+ char reply[256], *p;
- reply[sizeof(reply)-1] = 0;
+ reply[sizeof(reply) - 1] = 0;
for (;;) {
fflush(stdout);
- if (! fgets (reply, sizeof(reply)-1, stdin))
+ if (!fgets (reply, sizeof(reply) - 1, stdin))
return (0);
for (p=reply; *p==' ' || *p=='\t'; ++p)
continue;
@@ -172,129 +138,149 @@ yes (void)
int
main(int argc, char **argv)
{
- int format = -1, cyls = -1, secs = -1, heads = -1, intleave = -1;
- int rate = -1, gaplen = -1, secsize = -1, steps = -1;
- int fill = 0xf6, quiet = 0, verify = 1, verify_only = 0, confirm = 0;
- int fd, c, i, track, error, tracks_per_dot, bytes_per_track, errs;
- int fdopts;
- const char *device, *suffix;
- struct fd_type fdt;
+ enum fd_drivetype type;
+ struct fd_type fdt, newft, *fdtp;
+ struct stat sb;
#define MAXPRINTERRS 10
struct fdc_status fdcs[MAXPRINTERRS];
+ int format, fill, quiet, verify, verify_only, confirm;
+ int fd, c, i, track, error, tracks_per_dot, bytes_per_track, errs;
+ int fdopts, flags;
+ char *fmtstring, *device;
+ const char *name, *descr;
- while((c = getopt(argc, argv, "f:c:s:h:r:g:S:F:t:i:qyvn")) != -1)
- switch(c) {
- case 'f': /* format in kilobytes */
- format = atoi(optarg);
- break;
-
- case 'c': /* # of cyls */
- cyls = atoi(optarg);
- break;
-
- case 's': /* # of secs per track */
- secs = atoi(optarg);
- break;
-
- case 'h': /* # of heads */
- heads = atoi(optarg);
- break;
-
- case 'r': /* transfer rate, kilobyte/sec */
- rate = atoi(optarg);
- break;
-
- case 'g': /* length of GAP3 to format with */
- gaplen = atoi(optarg);
- break;
-
- case 'S': /* sector size shift factor (1 << S)*128 */
- secsize = atoi(optarg);
- break;
+ format = quiet = verify_only = confirm = 0;
+ verify = 1;
+ fill = 0xf6;
+ fmtstring = 0;
- case 'F': /* fill byte, C-like notation allowed */
- fill = (int)strtol(optarg, (char **)0, 0);
+ while((c = getopt(argc, argv, "F:f:nqs:vy")) != -1)
+ switch(c) {
+ case 'F': /* fill byte */
+ if (getnum(optarg, &fill)) {
+ fprintf(stderr,
+ "Bad argument %s to -F option; must be numeric\n",
+ optarg);
+ usage();
+ }
break;
- case 't': /* steps per track */
- steps = atoi(optarg);
+ case 'f': /* format in kilobytes */
+ if (getnum(optarg, &format)) {
+ fprintf(stderr,
+ "Bad argument %s to -f option; must be numeric\n",
+ optarg);
+ usage();
+ }
break;
- case 'i': /* interleave factor */
- intleave = atoi(optarg);
+ case 'n': /* don't verify */
+ verify = 0;
break;
- case 'q':
+ case 'q': /* quiet */
quiet = 1;
break;
- case 'y':
- confirm = 1;
+ case 's': /* format string with detailed options */
+ fmtstring = optarg;
break;
- case 'n':
- verify = 0;
- break;
-
- case 'v':
+ case 'v': /* verify only */
verify = 1;
verify_only = 1;
break;
- case '?': default:
+ case 'y': /* confirm */
+ confirm = 1;
+ break;
+
+ default:
usage();
}
if(optind != argc - 1)
usage();
- switch(format) {
- default:
- errx(2, "bad floppy size: %dK", format);
- case -1: suffix = ""; break;
- case 360: suffix = ".360"; break;
- case 640: suffix = ".640"; break;
- case 720: suffix = ".720"; break;
- case 800: suffix = ".800"; break;
- case 820: suffix = ".820"; break;
- case 1200: suffix = ".1200"; break;
- case 1232: suffix = ".1232"; break;
- case 1440: suffix = ".1440"; break;
- case 1480: suffix = ".1480"; break;
- case 1720: suffix = ".1720"; break;
+ if (stat(argv[optind], &sb) == -1 && errno == ENOENT) {
+ /* try prepending _PATH_DEV */
+ device = malloc(strlen(argv[optind] + sizeof _PATH_DEV + 1));
+ if (device == 0)
+ errx(EX_UNAVAILABLE, "out of memory");
+ strcpy(device, _PATH_DEV);
+ strcat(device, argv[optind]);
+ if (stat(device, &sb) == -1) {
+ free(device);
+ device = argv[optind]; /* let it fail below */
+ }
+ } else {
+ device = argv[optind];
}
- device = makename(argv[optind], suffix);
-
- if((fd = open(device, O_RDWR)) < 0)
- err(1, "%s", device);
+ if ((fd = open(device, O_RDWR | O_NONBLOCK)) < 0)
+ err(EX_OSERR, "open(%s)", device);
+ /*
+ * Device initialization.
+ *
+ * First, get the device type descriptor. This tells us about
+ * the media geometry data we need to format a medium. It also
+ * lets us know quickly whether the device name actually points
+ * to a floppy disk drive.
+ *
+ * Then, obtain any drive options. We're mainly interested to
+ * see whether we're currently working on a device with media
+ * density autoselection (FDOPT_AUTOSEL). Then, we add the
+ * device option to tell the kernel not to log media errors,
+ * since we can handle them ourselves. If the device does
+ * media density autoselection, we then need to set the device
+ * type appropriately, since by opening with O_NONBLOCK we
+ * told the driver to bypass media autoselection (otherwise we
+ * wouldn't stand a chance to format an unformatted or damaged
+ * medium). We do not attempt to set the media type on any
+ * other devices since this is a privileged operation. For the
+ * same reason, specifying -f and -s options is only possible
+ * for autoselecting devices.
+ *
+ * Finally, we are ready to turn off O_NONBLOCK, and start to
+ * actually format something.
+ */
if(ioctl(fd, FD_GTYPE, &fdt) < 0)
- errx(1, "not a floppy disk: %s", device);
- fdopts = FDOPT_NOERRLOG;
+ errx(EX_OSERR, "not a floppy disk: %s", device);
+ if (ioctl(fd, FD_GDTYPE, &type) == -1)
+ err(EX_OSERR, "ioctl(FD_GDTYPE)");
+ if (ioctl(fd, FD_GOPTS, &fdopts) == -1)
+ err(EX_OSERR, "ioctl(FD_GOPTS)");
+ fdopts |= FDOPT_NOERRLOG;
if (ioctl(fd, FD_SOPTS, &fdopts) == -1)
- err(1, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)");
-
- switch(rate) {
- case -1: break;
- case 250: fdt.trans = FDC_250KBPS; break;
- case 300: fdt.trans = FDC_300KBPS; break;
- case 500: fdt.trans = FDC_500KBPS; break;
- default:
- errx(2, "invalid transfer rate: %d", rate);
+ err(EX_OSERR, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)");
+ if (format) {
+ getname(type, &name, &descr);
+ fdtp = get_fmt(format, type);
+ if (fdtp == 0)
+ errx(EX_USAGE,
+ "unknown format %d KB for drive type %s",
+ format, name);
+ fdt = *fdtp;
}
+ if (fmtstring) {
+ parse_fmt(fmtstring, type, fdt, &newft);
+ fdt = newft;
+ }
+ if (fdopts & FDOPT_AUTOSEL) {
+ if (ioctl(fd, FD_STYPE, &fdt) < 0)
+ err(EX_OSERR, "ioctl(FD_STYPE)");
+ } else if (fmtstring || format) {
+ errx(EX_USAGE,
+ "-f fmt or -s fmtstr is only allowed for autoselecting devices");
+ }
+ if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
+ err(EX_OSERR, "fcntl(F_GETFL)");
+ flags &= ~O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, flags) == -1)
+ err(EX_OSERR, "fcntl(F_SETFL)");
- if (cyls >= 0) fdt.tracks = cyls;
- if (secs >= 0) fdt.sectrac = secs;
- if (fdt.sectrac > FD_MAX_NSEC)
- errx(2, "too many sectors per track, max value is %d", FD_MAX_NSEC);
- if (heads >= 0) fdt.heads = heads;
- if (gaplen >= 0) fdt.f_gap = gaplen;
- if (secsize >= 0) fdt.secsize = secsize;
- if (steps >= 0) fdt.steptrac = steps;
- if (intleave >= 0) fdt.f_inter = intleave;
-
- bytes_per_track = fdt.sectrac * (1<<fdt.secsize) * 128;
+ bytes_per_track = fdt.sectrac * (128 << fdt.secsize);
/* XXX 20/40 = 0.5 */
tracks_per_dot = (fdt.tracks * fdt.heads + 20) / 40;
@@ -309,9 +295,9 @@ main(int argc, char **argv)
printf("Format %dK floppy `%s'? (y/n): ",
fdt.tracks * fdt.heads * bytes_per_track / 1024,
device);
- if(! yes ()) {
+ if(!yes()) {
printf("Not confirmed.\n");
- return 3;
+ return (EX_UNAVAILABLE);
}
}
@@ -332,7 +318,8 @@ main(int argc, char **argv)
if (!verify_only) {
format_track(fd, track / fdt.heads, fdt.sectrac,
track % fdt.heads, fdt.trans, fdt.f_gap,
- fdt.secsize, fill, fdt.f_inter);
+ fdt.secsize, fill, fdt.f_inter,
+ track % fdt.heads? fdt.offset_side2: 0);
if(!quiet && !((track + 1) % tracks_per_dot)) {
putchar('F');
fflush(stdout);
@@ -344,7 +331,7 @@ main(int argc, char **argv)
if (errs < MAXPRINTERRS && errno == EIO) {
if (ioctl(fd, FD_GSTAT, fdcs + errs) ==
-1)
- errx(1,
+ errx(EX_IOERR,
"floppy IO error, but no FDC status");
errs++;
}
diff --git a/usr.sbin/fdread/fdutil.c b/usr.sbin/fdread/fdutil.c
index fb61b30a0bf9..9990790bcc82 100644
--- a/usr.sbin/fdread/fdutil.c
+++ b/usr.sbin/fdread/fdutil.c
@@ -26,16 +26,23 @@
* $FreeBSD$
*/
-#include <sys/types.h>
+#include <dev/ic/nec765.h>
+
#include <sys/fdcio.h>
+#include <err.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-
-#include <dev/ic/nec765.h>
+#include <sysexits.h>
#include "fdutil.h"
+/*
+ * Decode the FDC status pointed to by `fdcsp', and print a textual
+ * translation to stderr. If `terse' is false, the numerical FDC
+ * register status is printed, too.
+ */
void
printstatus(struct fdc_status *fdcsp, int terse)
{
@@ -78,3 +85,382 @@ printstatus(struct fdc_status *fdcsp, int terse)
fputs(msgbuf, stderr);
}
+static struct fd_type fd_types_288m[] =
+{
+#if 0
+{ 36,2,0xFF,0x1B,80,5760,FDC_1MBPS, 2,0x4C,1,1,FL_MFM|FL_PERPND } /*2.88M*/
+#endif
+{ 21,2,0xFF,0x04,82,3444,FDC_500KBPS,2,0x0C,2,0,FL_MFM }, /* 1.72M */
+{ 18,2,0xFF,0x1B,82,2952,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.48M */
+{ 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.44M */
+{ 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* 1.2M */
+{ 10,2,0xFF,0x10,82,1640,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 820K */
+{ 10,2,0xFF,0x10,80,1600,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 800K */
+{ 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */
+};
+
+static struct fd_type fd_types_144m[] =
+{
+{ 21,2,0xFF,0x04,82,3444,FDC_500KBPS,2,0x0C,2,0,FL_MFM }, /* 1.72M */
+{ 18,2,0xFF,0x1B,82,2952,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.48M */
+{ 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.44M */
+{ 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* 1.2M */
+{ 10,2,0xFF,0x10,82,1640,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 820K */
+{ 10,2,0xFF,0x10,80,1600,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 800K */
+{ 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */
+};
+
+static struct fd_type fd_types_12m[] =
+{
+{ 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* 1.2M */
+{ 8,3,0xFF,0x35,77,1232,FDC_500KBPS,2,0x74,1,0,FL_MFM }, /* 1.23M */
+{ 18,2,0xFF,0x02,82,2952,FDC_500KBPS,2,0x02,2,0,FL_MFM }, /* 1.48M */
+{ 18,2,0xFF,0x02,80,2880,FDC_500KBPS,2,0x02,2,0,FL_MFM }, /* 1.44M */
+{ 10,2,0xFF,0x10,82,1640,FDC_300KBPS,2,0x2E,1,0,FL_MFM }, /* 820K */
+{ 10,2,0xFF,0x10,80,1600,FDC_300KBPS,2,0x2E,1,0,FL_MFM }, /* 800K */
+{ 9,2,0xFF,0x20,80,1440,FDC_300KBPS,2,0x50,1,0,FL_MFM }, /* 720K */
+{ 9,2,0xFF,0x23,40, 720,FDC_300KBPS,2,0x50,1,0,FL_MFM|FL_2STEP }, /* 360K */
+{ 8,2,0xFF,0x2A,80,1280,FDC_300KBPS,2,0x50,1,0,FL_MFM }, /* 640K */
+};
+
+static struct fd_type fd_types_720k[] =
+{
+{ 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */
+};
+
+static struct fd_type fd_types_360k[] =
+{
+{ 9,2,0xFF,0x2A,40, 720,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 360K */
+};
+
+/*
+ * Parse a format string, and fill in the parameter pointed to by `out'.
+ *
+ * sectrac,secsize,datalen,gap,ncyls,speed,heads,f_gap,f_inter,offs2,flags[...]
+ *
+ * sectrac = sectors per track
+ * secsize = sector size in bytes
+ * datalen = length of sector if secsize == 128
+ * gap = gap length when reading
+ * ncyls = number of cylinders
+ * speed = transfer speed 250/300/500/1000 KB/s
+ * heads = number of heads
+ * f_gap = gap length when formatting
+ * f_inter = sector interleave when formatting
+ * offs2 = offset of sectors on side 2
+ * flags = +/-mfm | +/-2step | +/-perpend
+ * mfm - use MFM recording
+ * 2step - use 2 steps between cylinders
+ * perpend - user perpendicular (vertical) recording
+ *
+ * Any omitted value will be passed on from parameter `in'.
+ */
+void
+parse_fmt(const char *s, enum fd_drivetype type,
+ struct fd_type in, struct fd_type *out)
+{
+ int i, j;
+ const char *cp;
+ char *s1;
+
+ *out = in;
+
+ for (i = 0;; i++) {
+ if (s == 0)
+ break;
+
+ if ((cp = strchr(s, ',')) == 0) {
+ s1 = strdup(s);
+ if (s1 == NULL)
+ abort();
+ s = 0;
+ } else {
+ s1 = malloc(cp - s + 1);
+ if (s1 == NULL)
+ abort();
+ memcpy(s1, s, cp - s);
+ s1[cp - s] = 0;
+
+ s = cp + 1;
+ }
+ if (strlen(s1) == 0) {
+ free(s1);
+ continue;
+ }
+
+ switch (i) {
+ case 0: /* sectrac */
+ if (getnum(s1, &out->sectrac))
+ errx(EX_USAGE,
+ "bad numeric value for sectrac: %s", s1);
+ break;
+
+ case 1: /* secsize */
+ if (getnum(s1, &j))
+ errx(EX_USAGE,
+ "bad numeric value for secsize: %s", s1);
+ if (j == 128) out->secsize = 0;
+ else if (j == 256) out->secsize = 1;
+ else if (j == 512) out->secsize = 2;
+ else if (j == 1024) out->secsize = 3;
+ else
+ errx(EX_USAGE, "bad sector size %d", j);
+ break;
+
+ case 2: /* datalen */
+ if (getnum(s1, &j))
+ errx(EX_USAGE,
+ "bad numeric value for datalen: %s", s1);
+ if (j >= 256)
+ errx(EX_USAGE, "bad datalen %d", j);
+ out->datalen = j;
+ break;
+
+ case 3: /* gap */
+ if (getnum(s1, &out->gap))
+ errx(EX_USAGE,
+ "bad numeric value for gap: %s", s1);
+ break;
+
+ case 4: /* ncyls */
+ if (getnum(s1, &j))
+ errx(EX_USAGE,
+ "bad numeric value for ncyls: %s", s1);
+ if (j > 85)
+ errx(EX_USAGE, "bad # of cylinders %d", j);
+ out->tracks = j;
+ break;
+
+ case 5: /* speed */
+ if (getnum(s1, &j))
+ errx(EX_USAGE,
+ "bad numeric value for speed: %s", s1);
+ switch (type) {
+ default:
+ abort(); /* paranoia */
+
+ case FDT_360K:
+ case FDT_720K:
+ if (j == 250)
+ out->trans = FDC_250KBPS;
+ else {
+ badspeed:
+ errx(EX_USAGE, "bad speed %d", j);
+ }
+ break;
+
+ case FDT_12M:
+ if (j == 300)
+ out->trans = FDC_300KBPS;
+ else if (j == 500)
+ out->trans = FDC_500KBPS;
+ else
+ goto badspeed;
+ break;
+
+ case FDT_288M:
+ if (j == 1000)
+ out->trans = FDC_1MBPS;
+ /* FALLTHROUGH */
+ case FDT_144M:
+ if (j == 250)
+ out->trans = FDC_250KBPS;
+ else if (j == 500)
+ out->trans = FDC_500KBPS;
+ else
+ goto badspeed;
+ break;
+ }
+ break;
+
+ case 6: /* heads */
+ if (getnum(s1, &j))
+ errx(EX_USAGE,
+ "bad numeric value for heads: %s", s1);
+ if (j == 1 || j == 2)
+ out->heads = j;
+ else
+ errx(EX_USAGE, "bad # of heads %d", j);
+ break;
+
+ case 7: /* f_gap */
+ if (getnum(s1, &out->f_gap))
+ errx(EX_USAGE,
+ "bad numeric value for f_gap: %s", s1);
+ break;
+
+ case 8: /* f_inter */
+ if (getnum(s1, &out->f_inter))
+ errx(EX_USAGE,
+ "bad numeric value for f_inter: %s", s1);
+ break;
+
+ case 9: /* offs2 */
+ if (getnum(s1, &out->offset_side2))
+ errx(EX_USAGE,
+ "bad numeric value for offs2: %s", s1);
+ break;
+
+ default:
+ if (strcmp(s1, "+mfm") == 0)
+ out->flags |= FL_MFM;
+ else if (strcmp(s1, "-mfm") == 0)
+ out->flags &= ~FL_MFM;
+ else if (strcmp(s1, "+2step") == 0)
+ out->flags |= FL_2STEP;
+ else if (strcmp(s1, "-2step") == 0)
+ out->flags &= ~FL_2STEP;
+ else if (strcmp(s1, "+perpnd") == 0)
+ out->flags |= FL_PERPND;
+ else if (strcmp(s1, "-perpnd") == 0)
+ out->flags &= ~FL_PERPND;
+ else
+ errx(EX_USAGE, "bad flag: %s", s1);
+ break;
+ }
+ free(s1);
+ }
+
+ out->size = out->tracks * out->heads * out->sectrac *
+ (128 << out->secsize) / 512;
+}
+
+/*
+ * Print a textual translation of the drive (density) type described
+ * by `in' to stdout. The string uses the same form that is parseable
+ * by parse_fmt().
+ */
+void
+print_fmt(struct fd_type in)
+{
+ int secsize, speed;
+
+ secsize = 128 << in.secsize;
+ switch (in.trans) {
+ case FDC_250KBPS: speed = 250; break;
+ case FDC_300KBPS: speed = 300; break;
+ case FDC_500KBPS: speed = 500; break;
+ case FDC_1MBPS: speed = 1000; break;
+ default: speed = 1; break;
+ }
+
+ printf("%d,%d,%#x,%#x,%d,%d,%d,%#x,%d,%d",
+ in.sectrac, secsize, in.datalen, in.gap, in.tracks,
+ speed, in.heads, in.f_gap, in.f_inter, in.offset_side2);
+ if (in.flags & FL_MFM)
+ printf(",+mfm");
+ if (in.flags & FL_2STEP)
+ printf(",+2step");
+ if (in.flags & FL_PERPND)
+ printf(",+perpnd");
+ putc('\n', stdout);
+}
+
+/*
+ * Based on `size' (in kilobytes), walk through the table of known
+ * densities for drive type `type' and see if we can find one. If
+ * found, return it (as a pointer to static storage), otherwise return
+ * NULL.
+ */
+struct fd_type *
+get_fmt(int size, enum fd_drivetype type)
+{
+ int i, n;
+ struct fd_type *fdtp;
+
+ switch (type) {
+ default:
+ return (0);
+
+ case FDT_360K:
+ fdtp = fd_types_360k;
+ n = sizeof fd_types_360k / sizeof(struct fd_type);
+ break;
+
+ case FDT_720K:
+ fdtp = fd_types_720k;
+ n = sizeof fd_types_720k / sizeof(struct fd_type);
+ break;
+
+ case FDT_12M:
+ fdtp = fd_types_12m;
+ n = sizeof fd_types_12m / sizeof(struct fd_type);
+ break;
+
+ case FDT_144M:
+ fdtp = fd_types_144m;
+ n = sizeof fd_types_144m / sizeof(struct fd_type);
+ break;
+
+ case FDT_288M:
+ fdtp = fd_types_288m;
+ n = sizeof fd_types_288m / sizeof(struct fd_type);
+ break;
+ }
+
+ for (i = 0; i < n; i++, fdtp++)
+ if (fdtp->size / 2 == size)
+ return (fdtp);
+
+ return (0);
+}
+
+/*
+ * Parse a number from `s'. If the string cannot be converted into a
+ * number completely, return -1, otherwise 0. The result is returned
+ * in `*res'.
+ */
+int
+getnum(const char *s, int *res)
+{
+ unsigned long ul;
+ char *cp;
+
+ ul = strtoul(s, &cp, 0);
+ if (*cp != '\0')
+ return (-1);
+
+ *res = (int)ul;
+ return (0);
+}
+
+/*
+ * Return a short name and a verbose description for the drive
+ * described by `t'.
+ */
+void
+getname(enum fd_drivetype t, const char **name, const char **descr)
+{
+
+ switch (t) {
+ default:
+ *name = "unknown";
+ *descr = "unknown drive type";
+ break;
+
+ case FDT_360K:
+ *name = "360K";
+ *descr = "5.25\" double-density";
+ break;
+
+ case FDT_12M:
+ *name = "1.2M";
+ *descr = "5.25\" high-density";
+ break;
+
+ case FDT_720K:
+ *name = "720K";
+ *descr = "3.5\" double-density";
+ break;
+
+ case FDT_144M:
+ *name = "1.44M";
+ *descr = "3.5\" high-density";
+ break;
+
+ case FDT_288M:
+ *name = "2.88M";
+ *descr = "3.5\" extra-density";
+ break;
+ }
+}
diff --git a/usr.sbin/fdread/fdutil.h b/usr.sbin/fdread/fdutil.h
index f4993908f047..a09322850897 100644
--- a/usr.sbin/fdread/fdutil.h
+++ b/usr.sbin/fdread/fdutil.h
@@ -26,4 +26,12 @@
* $FreeBSD$
*/
+
void printstatus(struct fdc_status *fdcsp, int terse);
+void parse_fmt(const char *, enum fd_drivetype,
+ struct fd_type, struct fd_type *);
+struct fd_type *get_fmt(int, enum fd_drivetype);
+void print_fmt(struct fd_type);
+int getnum(const char *, int *);
+void getname(enum fd_drivetype, const char **, const char **);
+