diff options
Diffstat (limited to 'usr.sbin/fdformat/fdformat.c')
-rw-r--r-- | usr.sbin/fdformat/fdformat.c | 297 |
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++; } |