fdformat.c revision 87992
11022Sache/* 278858Sjoerg * Copyright (C) 1992-1994,2001 by Joerg Wunsch, Dresden 31022Sache * All rights reserved. 41022Sache * 51022Sache * Redistribution and use in source and binary forms, with or without 61022Sache * modification, are permitted provided that the following conditions 71022Sache * are met: 81022Sache * 1. Redistributions of source code must retain the above copyright 91022Sache * notice, this list of conditions and the following disclaimer. 101022Sache * 2. Redistributions in binary form must reproduce the above copyright 111022Sache * notice, this list of conditions and the following disclaimer in the 121022Sache * documentation and/or other materials provided with the distribution. 131022Sache * 141533Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 151533Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 161533Sjoerg * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 171533Sjoerg * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, 181533Sjoerg * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 191533Sjoerg * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 201533Sjoerg * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211533Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 221533Sjoerg * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 231533Sjoerg * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 241533Sjoerg * POSSIBILITY OF SUCH DAMAGE. 2555541Skato * 2655541Skato * $FreeBSD: head/usr.sbin/fdformat/fdformat.c 87992 2001-12-15 19:09:04Z joerg $ 271022Sache */ 281022Sache 2987992Sjoerg#include <sys/types.h> 3087992Sjoerg#include <sys/fdcio.h> 3187992Sjoerg#include <sys/stat.h> 321022Sache 3329531Scharnier#include <ctype.h> 3429531Scharnier#include <err.h> 3579111Sjoerg#include <errno.h> 3629531Scharnier#include <fcntl.h> 3769793Sobrien#include <paths.h> 381022Sache#include <stdio.h> 391022Sache#include <stdlib.h> 4029531Scharnier#include <strings.h> 4187992Sjoerg#include <sysexits.h> 421022Sache#include <unistd.h> 431022Sache 4479111Sjoerg#include "fdutil.h" 4579111Sjoerg 461022Sachestatic void 471022Sacheformat_track(int fd, int cyl, int secs, int head, int rate, 4887992Sjoerg int gaplen, int secsize, int fill, int interleave, 4987992Sjoerg int offset) 501022Sache{ 511022Sache struct fd_formb f; 5287992Sjoerg int i, j, il[FD_MAX_NSEC + 1]; 531022Sache 5487992Sjoerg memset(il, 0, sizeof il); 5587992Sjoerg for(j = 0, i = 1 + offset; i <= secs + offset; i++) { 5687992Sjoerg while(il[(j % secs) + 1]) 5787992Sjoerg j++; 5887992Sjoerg il[(j % secs) + 1] = i; 591137Sache j += interleave; 601137Sache } 611137Sache 621022Sache f.format_version = FD_FORMAT_VERSION; 631022Sache f.head = head; 641022Sache f.cyl = cyl; 651022Sache f.transfer_rate = rate; 661022Sache 671022Sache f.fd_formb_secshift = secsize; 681022Sache f.fd_formb_nsecs = secs; 691022Sache f.fd_formb_gaplen = gaplen; 701022Sache f.fd_formb_fillbyte = fill; 711022Sache for(i = 0; i < secs; i++) { 721022Sache f.fd_formb_cylno(i) = cyl; 731022Sache f.fd_formb_headno(i) = head; 741137Sache f.fd_formb_secno(i) = il[i+1]; 751022Sache f.fd_formb_secsize(i) = secsize; 761022Sache } 7729531Scharnier if(ioctl(fd, FD_FORM, (caddr_t)&f) < 0) 7887992Sjoerg err(EX_OSERR, "ioctl(FD_FORM)"); 791022Sache} 801022Sache 811022Sachestatic int 821022Sacheverify_track(int fd, int track, int tracksize) 831022Sache{ 8487992Sjoerg static char *buf; 8587992Sjoerg static int bufsz; 861533Sjoerg int fdopts = -1, ofdopts, rv = 0; 871022Sache 881533Sjoerg if (ioctl(fd, FD_GOPTS, &fdopts) < 0) 8929531Scharnier warn("warning: ioctl(FD_GOPTS)"); 901533Sjoerg else { 911533Sjoerg ofdopts = fdopts; 921533Sjoerg fdopts |= FDOPT_NORETRY; 931533Sjoerg (void)ioctl(fd, FD_SOPTS, &fdopts); 941533Sjoerg } 958857Srgrimes 9687992Sjoerg if (bufsz < tracksize) 9787992Sjoerg buf = realloc(buf, bufsz = tracksize); 9887992Sjoerg if (buf == 0) 9987992Sjoerg errx(EX_UNAVAILABLE, "out of memory"); 10087992Sjoerg if (lseek (fd, (long) track * tracksize, 0) < 0) 1011533Sjoerg rv = -1; 1021533Sjoerg /* try twice reading it, without using the normal retrier */ 1031533Sjoerg else if (read (fd, buf, tracksize) != tracksize 1041533Sjoerg && read (fd, buf, tracksize) != tracksize) 1051533Sjoerg rv = -1; 10687992Sjoerg if (fdopts != -1) 1071533Sjoerg (void)ioctl(fd, FD_SOPTS, &ofdopts); 1081533Sjoerg return (rv); 1091022Sache} 1101022Sache 1111022Sachestatic void 1121533Sjoergusage (void) 1131022Sache{ 11487992Sjoerg errx(EX_USAGE, 11587992Sjoerg "usage: fdformat [-F fill] [-f fmt] [-s fmtstr] [-nqvy] device"); 1161022Sache} 1171022Sache 1181022Sachestatic int 1191533Sjoergyes (void) 1201022Sache{ 12187992Sjoerg char reply[256], *p; 1221022Sache 12387992Sjoerg reply[sizeof(reply) - 1] = 0; 1241022Sache for (;;) { 1251022Sache fflush(stdout); 12687992Sjoerg if (!fgets (reply, sizeof(reply) - 1, stdin)) 1271022Sache return (0); 1281022Sache for (p=reply; *p==' ' || *p=='\t'; ++p) 1291022Sache continue; 1301022Sache if (*p=='y' || *p=='Y') 1311022Sache return (1); 1321022Sache if (*p=='n' || *p=='N' || *p=='\n' || *p=='\r') 1331022Sache return (0); 1341022Sache printf("Answer `yes' or `no': "); 1351022Sache } 1361022Sache} 1371022Sache 1381022Sacheint 1391022Sachemain(int argc, char **argv) 1401022Sache{ 14187992Sjoerg enum fd_drivetype type; 14287992Sjoerg struct fd_type fdt, newft, *fdtp; 14387992Sjoerg struct stat sb; 14479111Sjoerg#define MAXPRINTERRS 10 14579111Sjoerg struct fdc_status fdcs[MAXPRINTERRS]; 14687992Sjoerg int format, fill, quiet, verify, verify_only, confirm; 14787992Sjoerg int fd, c, i, track, error, tracks_per_dot, bytes_per_track, errs; 14887992Sjoerg int fdopts, flags; 14987992Sjoerg char *fmtstring, *device; 15087992Sjoerg const char *name, *descr; 1511022Sache 15287992Sjoerg format = quiet = verify_only = confirm = 0; 15387992Sjoerg verify = 1; 15487992Sjoerg fill = 0xf6; 15587992Sjoerg fmtstring = 0; 15687992Sjoerg 15787992Sjoerg while((c = getopt(argc, argv, "F:f:nqs:vy")) != -1) 1581022Sache switch(c) { 15987992Sjoerg case 'F': /* fill byte */ 16087992Sjoerg if (getnum(optarg, &fill)) { 16187992Sjoerg fprintf(stderr, 16287992Sjoerg "Bad argument %s to -F option; must be numeric\n", 16387992Sjoerg optarg); 16487992Sjoerg usage(); 16587992Sjoerg } 1661022Sache break; 1671022Sache 16887992Sjoerg case 'f': /* format in kilobytes */ 16987992Sjoerg if (getnum(optarg, &format)) { 17087992Sjoerg fprintf(stderr, 17187992Sjoerg "Bad argument %s to -f option; must be numeric\n", 17287992Sjoerg optarg); 17387992Sjoerg usage(); 17487992Sjoerg } 1751022Sache break; 1761022Sache 17787992Sjoerg case 'n': /* don't verify */ 17887992Sjoerg verify = 0; 1791022Sache break; 1801022Sache 18187992Sjoerg case 'q': /* quiet */ 18287992Sjoerg quiet = 1; 1831022Sache break; 1841022Sache 18587992Sjoerg case 's': /* format string with detailed options */ 18687992Sjoerg fmtstring = optarg; 1871022Sache break; 1881022Sache 18987992Sjoerg case 'v': /* verify only */ 19087992Sjoerg verify = 1; 19187992Sjoerg verify_only = 1; 1921022Sache break; 1931022Sache 19487992Sjoerg case 'y': /* confirm */ 19561154Sphk confirm = 1; 19661154Sphk break; 19761154Sphk 19887992Sjoerg default: 1991022Sache usage(); 2001022Sache } 2011022Sache 2021022Sache if(optind != argc - 1) 2031022Sache usage(); 2041022Sache 20587992Sjoerg if (stat(argv[optind], &sb) == -1 && errno == ENOENT) { 20687992Sjoerg /* try prepending _PATH_DEV */ 20787992Sjoerg device = malloc(strlen(argv[optind] + sizeof _PATH_DEV + 1)); 20887992Sjoerg if (device == 0) 20987992Sjoerg errx(EX_UNAVAILABLE, "out of memory"); 21087992Sjoerg strcpy(device, _PATH_DEV); 21187992Sjoerg strcat(device, argv[optind]); 21287992Sjoerg if (stat(device, &sb) == -1) { 21387992Sjoerg free(device); 21487992Sjoerg device = argv[optind]; /* let it fail below */ 21587992Sjoerg } 21687992Sjoerg } else { 21787992Sjoerg device = argv[optind]; 2181022Sache } 2191022Sache 22087992Sjoerg if ((fd = open(device, O_RDWR | O_NONBLOCK)) < 0) 22187992Sjoerg err(EX_OSERR, "open(%s)", device); 2221022Sache 22387992Sjoerg /* 22487992Sjoerg * Device initialization. 22587992Sjoerg * 22687992Sjoerg * First, get the device type descriptor. This tells us about 22787992Sjoerg * the media geometry data we need to format a medium. It also 22887992Sjoerg * lets us know quickly whether the device name actually points 22987992Sjoerg * to a floppy disk drive. 23087992Sjoerg * 23187992Sjoerg * Then, obtain any drive options. We're mainly interested to 23287992Sjoerg * see whether we're currently working on a device with media 23387992Sjoerg * density autoselection (FDOPT_AUTOSEL). Then, we add the 23487992Sjoerg * device option to tell the kernel not to log media errors, 23587992Sjoerg * since we can handle them ourselves. If the device does 23687992Sjoerg * media density autoselection, we then need to set the device 23787992Sjoerg * type appropriately, since by opening with O_NONBLOCK we 23887992Sjoerg * told the driver to bypass media autoselection (otherwise we 23987992Sjoerg * wouldn't stand a chance to format an unformatted or damaged 24087992Sjoerg * medium). We do not attempt to set the media type on any 24187992Sjoerg * other devices since this is a privileged operation. For the 24287992Sjoerg * same reason, specifying -f and -s options is only possible 24387992Sjoerg * for autoselecting devices. 24487992Sjoerg * 24587992Sjoerg * Finally, we are ready to turn off O_NONBLOCK, and start to 24687992Sjoerg * actually format something. 24787992Sjoerg */ 24829531Scharnier if(ioctl(fd, FD_GTYPE, &fdt) < 0) 24987992Sjoerg errx(EX_OSERR, "not a floppy disk: %s", device); 25087992Sjoerg if (ioctl(fd, FD_GDTYPE, &type) == -1) 25187992Sjoerg err(EX_OSERR, "ioctl(FD_GDTYPE)"); 25287992Sjoerg if (ioctl(fd, FD_GOPTS, &fdopts) == -1) 25387992Sjoerg err(EX_OSERR, "ioctl(FD_GOPTS)"); 25487992Sjoerg fdopts |= FDOPT_NOERRLOG; 25578858Sjoerg if (ioctl(fd, FD_SOPTS, &fdopts) == -1) 25687992Sjoerg err(EX_OSERR, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)"); 25787992Sjoerg if (format) { 25887992Sjoerg getname(type, &name, &descr); 25987992Sjoerg fdtp = get_fmt(format, type); 26087992Sjoerg if (fdtp == 0) 26187992Sjoerg errx(EX_USAGE, 26287992Sjoerg "unknown format %d KB for drive type %s", 26387992Sjoerg format, name); 26487992Sjoerg fdt = *fdtp; 2651022Sache } 26687992Sjoerg if (fmtstring) { 26787992Sjoerg parse_fmt(fmtstring, type, fdt, &newft); 26887992Sjoerg fdt = newft; 26987992Sjoerg } 27087992Sjoerg if (fdopts & FDOPT_AUTOSEL) { 27187992Sjoerg if (ioctl(fd, FD_STYPE, &fdt) < 0) 27287992Sjoerg err(EX_OSERR, "ioctl(FD_STYPE)"); 27387992Sjoerg } else if (fmtstring || format) { 27487992Sjoerg errx(EX_USAGE, 27587992Sjoerg "-f fmt or -s fmtstr is only allowed for autoselecting devices"); 27687992Sjoerg } 27787992Sjoerg if ((flags = fcntl(fd, F_GETFL, 0)) == -1) 27887992Sjoerg err(EX_OSERR, "fcntl(F_GETFL)"); 27987992Sjoerg flags &= ~O_NONBLOCK; 28087992Sjoerg if (fcntl(fd, F_SETFL, flags) == -1) 28187992Sjoerg err(EX_OSERR, "fcntl(F_SETFL)"); 2821022Sache 28387992Sjoerg bytes_per_track = fdt.sectrac * (128 << fdt.secsize); 2841022Sache 28555541Skato /* XXX 20/40 = 0.5 */ 28655541Skato tracks_per_dot = (fdt.tracks * fdt.heads + 20) / 40; 28755541Skato 2881022Sache if (verify_only) { 2891022Sache if(!quiet) 2901022Sache printf("Verify %dK floppy `%s'.\n", 2911022Sache fdt.tracks * fdt.heads * bytes_per_track / 1024, 29279161Sjoerg device); 2931022Sache } 29461154Sphk else if(!quiet && !confirm) { 2951022Sache printf("Format %dK floppy `%s'? (y/n): ", 2961022Sache fdt.tracks * fdt.heads * bytes_per_track / 1024, 29779161Sjoerg device); 29887992Sjoerg if(!yes()) { 2991022Sache printf("Not confirmed.\n"); 30087992Sjoerg return (EX_UNAVAILABLE); 3011022Sache } 3021022Sache } 3031022Sache 3041022Sache /* 3051022Sache * Formatting. 3061022Sache */ 3071022Sache if(!quiet) { 3081022Sache printf("Processing "); 30955541Skato for (i = 0; i < (fdt.tracks * fdt.heads) / tracks_per_dot; i++) 31055541Skato putchar('-'); 31155541Skato printf("\rProcessing "); 3121022Sache fflush(stdout); 3131022Sache } 3141022Sache 3151022Sache error = errs = 0; 3161022Sache 3171022Sache for (track = 0; track < fdt.tracks * fdt.heads; track++) { 3181022Sache if (!verify_only) { 3191183Srgrimes format_track(fd, track / fdt.heads, fdt.sectrac, 3201183Srgrimes track % fdt.heads, fdt.trans, fdt.f_gap, 32187992Sjoerg fdt.secsize, fill, fdt.f_inter, 32287992Sjoerg track % fdt.heads? fdt.offset_side2: 0); 3231022Sache if(!quiet && !((track + 1) % tracks_per_dot)) { 3241022Sache putchar('F'); 3251022Sache fflush(stdout); 3261022Sache } 3271022Sache } 3281022Sache if (verify) { 32979111Sjoerg if (verify_track(fd, track, bytes_per_track) < 0) { 33079111Sjoerg error = 1; 33179111Sjoerg if (errs < MAXPRINTERRS && errno == EIO) { 33279111Sjoerg if (ioctl(fd, FD_GSTAT, fdcs + errs) == 33379111Sjoerg -1) 33487992Sjoerg errx(EX_IOERR, 33579111Sjoerg "floppy IO error, but no FDC status"); 33679111Sjoerg errs++; 33779111Sjoerg } 33879111Sjoerg } 3391022Sache if(!quiet && !((track + 1) % tracks_per_dot)) { 3401022Sache if (!verify_only) 3411022Sache putchar('\b'); 3421022Sache if (error) { 3431022Sache putchar('E'); 3441022Sache error = 0; 3451022Sache } 3461022Sache else 3471022Sache putchar('V'); 3481022Sache fflush(stdout); 3491022Sache } 3501022Sache } 3511022Sache } 3521022Sache if(!quiet) 3531022Sache printf(" done.\n"); 3541022Sache 35579111Sjoerg if (!quiet && errs) { 35679111Sjoerg fflush(stdout); 35779111Sjoerg fprintf(stderr, "Errors encountered:\nCyl Head Sect Error\n"); 35879111Sjoerg for (i = 0; i < errs && i < MAXPRINTERRS; i++) { 35979111Sjoerg fprintf(stderr, " %2d %2d %2d ", 36079111Sjoerg fdcs[i].status[3], fdcs[i].status[4], 36179111Sjoerg fdcs[i].status[5]); 36279111Sjoerg printstatus(fdcs + i, 1); 36379111Sjoerg putc('\n', stderr); 36479111Sjoerg } 36579111Sjoerg if (errs >= MAXPRINTERRS) 36679111Sjoerg fprintf(stderr, "(Further errors not printed.)\n"); 36779111Sjoerg } 36879111Sjoerg 36979111Sjoerg return errs != 0; 3701022Sache} 371