summaryrefslogtreecommitdiffstats
path: root/usr.sbin/fdformat
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/fdformat')
-rw-r--r--usr.sbin/fdformat/fdformat.c297
1 files changed, 142 insertions, 155 deletions
diff --git a/usr.sbin/fdformat/fdformat.c b/usr.sbin/fdformat/fdformat.c
index 0c194b3..0e037b4 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++;
}
OpenPOWER on IntegriCloud