fdformat.c revision 134081
1218792Snp/* 2218792Snp * Copyright (C) 1992-1994,2001 by Joerg Wunsch, Dresden 3218792Snp * All rights reserved. 4218792Snp * 5218792Snp * Redistribution and use in source and binary forms, with or without 6218792Snp * modification, are permitted provided that the following conditions 7218792Snp * are met: 8218792Snp * 1. Redistributions of source code must retain the above copyright 9218792Snp * notice, this list of conditions and the following disclaimer. 10218792Snp * 2. Redistributions in binary form must reproduce the above copyright 11218792Snp * notice, this list of conditions and the following disclaimer in the 12218792Snp * documentation and/or other materials provided with the distribution. 13218792Snp * 14218792Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15218792Snp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16218792Snp * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17218792Snp * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, 18218792Snp * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19218792Snp * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20218792Snp * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21218792Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22218792Snp * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 23218792Snp * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24218792Snp * POSSIBILITY OF SUCH DAMAGE. 25218792Snp * 26218792Snp * $FreeBSD: head/usr.sbin/fdformat/fdformat.c 134081 2004-08-20 15:14:25Z phk $ 27218792Snp */ 28218792Snp 29218792Snp#include <sys/types.h> 30218792Snp#include <sys/fdcio.h> 31218792Snp#include <sys/stat.h> 32218792Snp 33218792Snp#include <ctype.h> 34218792Snp#include <err.h> 35218792Snp#include <errno.h> 36218792Snp#include <fcntl.h> 37218792Snp#include <paths.h> 38218792Snp#include <stdio.h> 39218792Snp#include <stdlib.h> 40218792Snp#include <string.h> 41218792Snp#include <strings.h> 42218792Snp#include <sysexits.h> 43218792Snp#include <unistd.h> 44218792Snp 45218792Snp#include "fdutil.h" 46218792Snp 47218792Snpstatic void 48218792Snpformat_track(int fd, int cyl, int secs, int head, int rate, 49218792Snp int gaplen, int secsize, int fill, int interleave, 50218792Snp int offset) 51218792Snp{ 52218792Snp struct fd_formb f; 53218792Snp int i, j, il[FD_MAX_NSEC + 1]; 54218792Snp 55218792Snp memset(il, 0, sizeof il); 56218792Snp for(j = 0, i = 1 + offset; i <= secs + offset; i++) { 57218792Snp while(il[(j % secs) + 1]) 58218792Snp j++; 59218792Snp il[(j % secs) + 1] = i; 60218792Snp j += interleave; 61218792Snp } 62218792Snp 63218792Snp f.format_version = FD_FORMAT_VERSION; 64218792Snp f.head = head; 65218792Snp f.cyl = cyl; 66218792Snp f.transfer_rate = rate; 67218792Snp 68218792Snp f.fd_formb_secshift = secsize; 69218792Snp f.fd_formb_nsecs = secs; 70218792Snp f.fd_formb_gaplen = gaplen; 71218792Snp f.fd_formb_fillbyte = fill; 72218792Snp for(i = 0; i < secs; i++) { 73218792Snp f.fd_formb_cylno(i) = cyl; 74218792Snp f.fd_formb_headno(i) = head; 75218792Snp f.fd_formb_secno(i) = il[i+1]; 76218792Snp f.fd_formb_secsize(i) = secsize; 77218792Snp } 78218792Snp if(ioctl(fd, FD_FORM, (caddr_t)&f) < 0) 79218792Snp err(EX_OSERR, "ioctl(FD_FORM)"); 80218792Snp} 81218792Snp 82218792Snpstatic int 83218792Snpverify_track(int fd, int track, int tracksize) 84218792Snp{ 85218792Snp static char *buf; 86218792Snp static int bufsz; 87218792Snp int fdopts = -1, ofdopts, rv = 0; 88218792Snp 89218792Snp if (ioctl(fd, FD_GOPTS, &fdopts) < 0) 90218792Snp warn("warning: ioctl(FD_GOPTS)"); 91218792Snp else { 92218792Snp ofdopts = fdopts; 93218792Snp fdopts |= FDOPT_NORETRY; 94218792Snp (void)ioctl(fd, FD_SOPTS, &fdopts); 95218792Snp } 96218792Snp 97218792Snp if (bufsz < tracksize) 98218792Snp buf = realloc(buf, bufsz = tracksize); 99218792Snp if (buf == 0) 100218792Snp errx(EX_UNAVAILABLE, "out of memory"); 101218792Snp if (lseek (fd, (long) track * tracksize, 0) < 0) 102218792Snp rv = -1; 103218792Snp /* try twice reading it, without using the normal retrier */ 104218792Snp else if (read (fd, buf, tracksize) != tracksize 105218792Snp && read (fd, buf, tracksize) != tracksize) 106218792Snp rv = -1; 107218792Snp if (fdopts != -1) 108218792Snp (void)ioctl(fd, FD_SOPTS, &ofdopts); 109218792Snp return (rv); 110218792Snp} 111218792Snp 112218792Snpstatic void 113218792Snpusage (void) 114218792Snp{ 115218792Snp errx(EX_USAGE, 116218792Snp "usage: fdformat [-F fill] [-f fmt] [-s fmtstr] [-nqvy] device"); 117218792Snp} 118218792Snp 119218792Snpstatic int 120218792Snpyes (void) 121218792Snp{ 122218792Snp char reply[256], *p; 123218792Snp 124218792Snp reply[sizeof(reply) - 1] = 0; 125218792Snp for (;;) { 126218792Snp fflush(stdout); 127218792Snp if (!fgets (reply, sizeof(reply) - 1, stdin)) 128218792Snp return (0); 129218792Snp for (p=reply; *p==' ' || *p=='\t'; ++p) 130218792Snp continue; 131218792Snp if (*p=='y' || *p=='Y') 132218792Snp return (1); 133218792Snp if (*p=='n' || *p=='N' || *p=='\n' || *p=='\r') 134218792Snp return (0); 135218792Snp printf("Answer `yes' or `no': "); 136218792Snp } 137218792Snp} 138218792Snp 139218792Snpint 140218792Snpmain(int argc, char **argv) 141218792Snp{ 142218792Snp enum fd_drivetype type; 143218792Snp struct fd_type fdt, newft, *fdtp; 144218792Snp struct stat sb; 145218792Snp#define MAXPRINTERRS 10 146218792Snp struct fdc_status fdcs[MAXPRINTERRS]; 147218792Snp int format, fill, quiet, verify, verify_only, confirm; 148218792Snp int fd, c, i, track, error, tracks_per_dot, bytes_per_track, errs; 149218792Snp int fdopts, flags; 150218792Snp char *fmtstring, *device; 151218792Snp const char *name, *descr; 152218792Snp 153218792Snp format = quiet = verify_only = confirm = 0; 154218792Snp verify = 1; 155218792Snp fill = 0xf6; 156218792Snp fmtstring = 0; 157218792Snp 158218792Snp while((c = getopt(argc, argv, "F:f:nqs:vy")) != -1) 159218792Snp switch(c) { 160218792Snp case 'F': /* fill byte */ 161218792Snp if (getnum(optarg, &fill)) { 162218792Snp fprintf(stderr, 163218792Snp "Bad argument %s to -F option; must be numeric\n", 164218792Snp optarg); 165218792Snp usage(); 166218792Snp } 167218792Snp break; 168218792Snp 169218792Snp case 'f': /* format in kilobytes */ 170218792Snp if (getnum(optarg, &format)) { 171218792Snp fprintf(stderr, 172218792Snp "Bad argument %s to -f option; must be numeric\n", 173218792Snp optarg); 174218792Snp usage(); 175218792Snp } 176218792Snp break; 177218792Snp 178218792Snp case 'n': /* don't verify */ 179218792Snp verify = 0; 180218792Snp break; 181218792Snp 182218792Snp case 'q': /* quiet */ 183218792Snp quiet = 1; 184218792Snp break; 185218792Snp 186218792Snp case 's': /* format string with detailed options */ 187218792Snp fmtstring = optarg; 188218792Snp break; 189218792Snp 190218792Snp case 'v': /* verify only */ 191218792Snp verify = 1; 192218792Snp verify_only = 1; 193218792Snp break; 194218792Snp 195218792Snp case 'y': /* confirm */ 196218792Snp confirm = 1; 197218792Snp break; 198218792Snp 199218792Snp default: 200218792Snp usage(); 201218792Snp } 202218792Snp 203218792Snp if(optind != argc - 1) 204218792Snp usage(); 205218792Snp 206218792Snp if (stat(argv[optind], &sb) == -1 && errno == ENOENT) { 207218792Snp /* try prepending _PATH_DEV */ 208218792Snp device = malloc(strlen(argv[optind]) + sizeof(_PATH_DEV) + 1); 209218792Snp if (device == 0) 210218792Snp errx(EX_UNAVAILABLE, "out of memory"); 211218792Snp strcpy(device, _PATH_DEV); 212218792Snp strcat(device, argv[optind]); 213218792Snp if (stat(device, &sb) == -1) { 214218792Snp free(device); 215218792Snp device = argv[optind]; /* let it fail below */ 216218792Snp } 217218792Snp } else { 218218792Snp device = argv[optind]; 219218792Snp } 220218792Snp 221218792Snp if ((fd = open(device, O_RDWR | O_NONBLOCK)) < 0) 222218792Snp err(EX_OSERR, "open(%s)", device); 223218792Snp 224218792Snp /* 225218792Snp * Device initialization. 226218792Snp * 227218792Snp * First, get the device type descriptor. This tells us about 228218792Snp * the media geometry data we need to format a medium. It also 229218792Snp * lets us know quickly whether the device name actually points 230218792Snp * to a floppy disk drive. 231218792Snp * 232218792Snp * Then, obtain any drive options. We're mainly interested to 233218792Snp * see whether we're currently working on a device with media 234218792Snp * density autoselection (FDOPT_AUTOSEL). Then, we add the 235218792Snp * device option to tell the kernel not to log media errors, 236218792Snp * since we can handle them ourselves. If the device does 237218792Snp * media density autoselection, we then need to set the device 238218792Snp * type appropriately, since by opening with O_NONBLOCK we 239218792Snp * told the driver to bypass media autoselection (otherwise we 240218792Snp * wouldn't stand a chance to format an unformatted or damaged 241218792Snp * medium). We do not attempt to set the media type on any 242218792Snp * other devices since this is a privileged operation. For the 243218792Snp * same reason, specifying -f and -s options is only possible 244218792Snp * for autoselecting devices. 245218792Snp * 246218792Snp * Finally, we are ready to turn off O_NONBLOCK, and start to 247218792Snp * actually format something. 248218792Snp */ 249218792Snp if(ioctl(fd, FD_GTYPE, &fdt) < 0) 250218792Snp errx(EX_OSERR, "not a floppy disk: %s", device); 251218792Snp if (ioctl(fd, FD_GDTYPE, &type) == -1) 252218792Snp err(EX_OSERR, "ioctl(FD_GDTYPE)"); 253218792Snp if (ioctl(fd, FD_GOPTS, &fdopts) == -1) 254218792Snp err(EX_OSERR, "ioctl(FD_GOPTS)"); 255218792Snp fdopts |= FDOPT_NOERRLOG; 256218792Snp if (ioctl(fd, FD_SOPTS, &fdopts) == -1) 257218792Snp err(EX_OSERR, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)"); 258218792Snp if (format) { 259218792Snp getname(type, &name, &descr); 260218792Snp fdtp = get_fmt(format, type); 261218792Snp if (fdtp == 0) 262218792Snp errx(EX_USAGE, 263218792Snp "unknown format %d KB for drive type %s", 264218792Snp format, name); 265218792Snp fdt = *fdtp; 266218792Snp } 267218792Snp if (fmtstring) { 268218792Snp parse_fmt(fmtstring, type, fdt, &newft); 269218792Snp fdt = newft; 270218792Snp } 271218792Snp if (ioctl(fd, FD_STYPE, &fdt) < 0) 272218792Snp err(EX_OSERR, "ioctl(FD_STYPE)"); 273218792Snp if ((flags = fcntl(fd, F_GETFL, 0)) == -1) 274218792Snp err(EX_OSERR, "fcntl(F_GETFL)"); 275218792Snp flags &= ~O_NONBLOCK; 276218792Snp if (fcntl(fd, F_SETFL, flags) == -1) 277218792Snp err(EX_OSERR, "fcntl(F_SETFL)"); 278218792Snp 279218792Snp bytes_per_track = fdt.sectrac * (128 << fdt.secsize); 280218792Snp 281218792Snp /* XXX 20/40 = 0.5 */ 282218792Snp tracks_per_dot = (fdt.tracks * fdt.heads + 20) / 40; 283218792Snp 284218792Snp if (verify_only) { 285218792Snp if(!quiet) 286218792Snp printf("Verify %dK floppy `%s'.\n", 287218792Snp fdt.tracks * fdt.heads * bytes_per_track / 1024, 288218792Snp device); 289218792Snp } 290218792Snp else if(!quiet && !confirm) { 291218792Snp printf("Format %dK floppy `%s'? (y/n): ", 292218792Snp fdt.tracks * fdt.heads * bytes_per_track / 1024, 293218792Snp device); 294218792Snp if(!yes()) { 295218792Snp printf("Not confirmed.\n"); 296218792Snp return (EX_UNAVAILABLE); 297218792Snp } 298218792Snp } 299218792Snp 300218792Snp /* 301218792Snp * Formatting. 302218792Snp */ 303218792Snp if(!quiet) { 304218792Snp printf("Processing "); 305218792Snp for (i = 0; i < (fdt.tracks * fdt.heads) / tracks_per_dot; i++) 306218792Snp putchar('-'); 307218792Snp printf("\rProcessing "); 308218792Snp fflush(stdout); 309218792Snp } 310218792Snp 311218792Snp error = errs = 0; 312218792Snp 313218792Snp for (track = 0; track < fdt.tracks * fdt.heads; track++) { 314218792Snp if (!verify_only) { 315218792Snp format_track(fd, track / fdt.heads, fdt.sectrac, 316218792Snp track % fdt.heads, fdt.trans, fdt.f_gap, 317218792Snp fdt.secsize, fill, fdt.f_inter, 318218792Snp track % fdt.heads? fdt.offset_side2: 0); 319218792Snp if(!quiet && !((track + 1) % tracks_per_dot)) { 320218792Snp putchar('F'); 321218792Snp fflush(stdout); 322218792Snp } 323218792Snp } 324218792Snp if (verify) { 325218792Snp if (verify_track(fd, track, bytes_per_track) < 0) { 326218792Snp error = 1; 327218792Snp if (errs < MAXPRINTERRS && errno == EIO) { 328218792Snp if (ioctl(fd, FD_GSTAT, fdcs + errs) == 329218792Snp -1) 330218792Snp errx(EX_IOERR, 331218792Snp "floppy IO error, but no FDC status"); 332218792Snp errs++; 333218792Snp } 334218792Snp } 335218792Snp if(!quiet && !((track + 1) % tracks_per_dot)) { 336218792Snp if (!verify_only) 337218792Snp putchar('\b'); 338218792Snp if (error) { 339218792Snp putchar('E'); 340218792Snp error = 0; 341218792Snp } 342218792Snp else 343218792Snp putchar('V'); 344218792Snp fflush(stdout); 345218792Snp } 346218792Snp } 347218792Snp } 348218792Snp if(!quiet) 349218792Snp printf(" done.\n"); 350218792Snp 351218792Snp if (!quiet && errs) { 352218792Snp fflush(stdout); 353218792Snp fprintf(stderr, "Errors encountered:\nCyl Head Sect Error\n"); 354218792Snp for (i = 0; i < errs && i < MAXPRINTERRS; i++) { 355218792Snp fprintf(stderr, " %2d %2d %2d ", 356218792Snp fdcs[i].status[3], fdcs[i].status[4], 357218792Snp fdcs[i].status[5]); 358218792Snp printstatus(fdcs + i, 1); 359218792Snp putc('\n', stderr); 360218792Snp } 361218792Snp if (errs >= MAXPRINTERRS) 362218792Snp fprintf(stderr, "(Further errors not printed.)\n"); 363218792Snp } 364218792Snp 365218792Snp return errs != 0; 366218792Snp} 367218792Snp