fdformat.c revision 134081
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 134081 2004-08-20 15:14:25Z phk $ 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> 4093590Smike#include <string.h> 4129531Scharnier#include <strings.h> 4287992Sjoerg#include <sysexits.h> 431022Sache#include <unistd.h> 441022Sache 4579111Sjoerg#include "fdutil.h" 4679111Sjoerg 471022Sachestatic void 481022Sacheformat_track(int fd, int cyl, int secs, int head, int rate, 4987992Sjoerg int gaplen, int secsize, int fill, int interleave, 5087992Sjoerg int offset) 511022Sache{ 521022Sache struct fd_formb f; 5387992Sjoerg int i, j, il[FD_MAX_NSEC + 1]; 541022Sache 5587992Sjoerg memset(il, 0, sizeof il); 5687992Sjoerg for(j = 0, i = 1 + offset; i <= secs + offset; i++) { 5787992Sjoerg while(il[(j % secs) + 1]) 5887992Sjoerg j++; 5987992Sjoerg il[(j % secs) + 1] = i; 601137Sache j += interleave; 611137Sache } 621137Sache 631022Sache f.format_version = FD_FORMAT_VERSION; 641022Sache f.head = head; 651022Sache f.cyl = cyl; 661022Sache f.transfer_rate = rate; 671022Sache 681022Sache f.fd_formb_secshift = secsize; 691022Sache f.fd_formb_nsecs = secs; 701022Sache f.fd_formb_gaplen = gaplen; 711022Sache f.fd_formb_fillbyte = fill; 721022Sache for(i = 0; i < secs; i++) { 731022Sache f.fd_formb_cylno(i) = cyl; 741022Sache f.fd_formb_headno(i) = head; 751137Sache f.fd_formb_secno(i) = il[i+1]; 761022Sache f.fd_formb_secsize(i) = secsize; 771022Sache } 7829531Scharnier if(ioctl(fd, FD_FORM, (caddr_t)&f) < 0) 7987992Sjoerg err(EX_OSERR, "ioctl(FD_FORM)"); 801022Sache} 811022Sache 821022Sachestatic int 831022Sacheverify_track(int fd, int track, int tracksize) 841022Sache{ 8587992Sjoerg static char *buf; 8687992Sjoerg static int bufsz; 871533Sjoerg int fdopts = -1, ofdopts, rv = 0; 881022Sache 891533Sjoerg if (ioctl(fd, FD_GOPTS, &fdopts) < 0) 9029531Scharnier warn("warning: ioctl(FD_GOPTS)"); 911533Sjoerg else { 921533Sjoerg ofdopts = fdopts; 931533Sjoerg fdopts |= FDOPT_NORETRY; 941533Sjoerg (void)ioctl(fd, FD_SOPTS, &fdopts); 951533Sjoerg } 968857Srgrimes 9787992Sjoerg if (bufsz < tracksize) 9887992Sjoerg buf = realloc(buf, bufsz = tracksize); 9987992Sjoerg if (buf == 0) 10087992Sjoerg errx(EX_UNAVAILABLE, "out of memory"); 10187992Sjoerg if (lseek (fd, (long) track * tracksize, 0) < 0) 1021533Sjoerg rv = -1; 1031533Sjoerg /* try twice reading it, without using the normal retrier */ 1041533Sjoerg else if (read (fd, buf, tracksize) != tracksize 1051533Sjoerg && read (fd, buf, tracksize) != tracksize) 1061533Sjoerg rv = -1; 10787992Sjoerg if (fdopts != -1) 1081533Sjoerg (void)ioctl(fd, FD_SOPTS, &ofdopts); 1091533Sjoerg return (rv); 1101022Sache} 1111022Sache 1121022Sachestatic void 1131533Sjoergusage (void) 1141022Sache{ 11587992Sjoerg errx(EX_USAGE, 11687992Sjoerg "usage: fdformat [-F fill] [-f fmt] [-s fmtstr] [-nqvy] device"); 1171022Sache} 1181022Sache 1191022Sachestatic int 1201533Sjoergyes (void) 1211022Sache{ 12287992Sjoerg char reply[256], *p; 1231022Sache 12487992Sjoerg reply[sizeof(reply) - 1] = 0; 1251022Sache for (;;) { 1261022Sache fflush(stdout); 12787992Sjoerg if (!fgets (reply, sizeof(reply) - 1, stdin)) 1281022Sache return (0); 1291022Sache for (p=reply; *p==' ' || *p=='\t'; ++p) 1301022Sache continue; 1311022Sache if (*p=='y' || *p=='Y') 1321022Sache return (1); 1331022Sache if (*p=='n' || *p=='N' || *p=='\n' || *p=='\r') 1341022Sache return (0); 1351022Sache printf("Answer `yes' or `no': "); 1361022Sache } 1371022Sache} 1381022Sache 1391022Sacheint 1401022Sachemain(int argc, char **argv) 1411022Sache{ 14287992Sjoerg enum fd_drivetype type; 14387992Sjoerg struct fd_type fdt, newft, *fdtp; 14487992Sjoerg struct stat sb; 14579111Sjoerg#define MAXPRINTERRS 10 14679111Sjoerg struct fdc_status fdcs[MAXPRINTERRS]; 14787992Sjoerg int format, fill, quiet, verify, verify_only, confirm; 14887992Sjoerg int fd, c, i, track, error, tracks_per_dot, bytes_per_track, errs; 14987992Sjoerg int fdopts, flags; 15087992Sjoerg char *fmtstring, *device; 15187992Sjoerg const char *name, *descr; 1521022Sache 15387992Sjoerg format = quiet = verify_only = confirm = 0; 15487992Sjoerg verify = 1; 15587992Sjoerg fill = 0xf6; 15687992Sjoerg fmtstring = 0; 15787992Sjoerg 15887992Sjoerg while((c = getopt(argc, argv, "F:f:nqs:vy")) != -1) 1591022Sache switch(c) { 16087992Sjoerg case 'F': /* fill byte */ 16187992Sjoerg if (getnum(optarg, &fill)) { 16287992Sjoerg fprintf(stderr, 16387992Sjoerg "Bad argument %s to -F option; must be numeric\n", 16487992Sjoerg optarg); 16587992Sjoerg usage(); 16687992Sjoerg } 1671022Sache break; 1681022Sache 16987992Sjoerg case 'f': /* format in kilobytes */ 17087992Sjoerg if (getnum(optarg, &format)) { 17187992Sjoerg fprintf(stderr, 17287992Sjoerg "Bad argument %s to -f option; must be numeric\n", 17387992Sjoerg optarg); 17487992Sjoerg usage(); 17587992Sjoerg } 1761022Sache break; 1771022Sache 17887992Sjoerg case 'n': /* don't verify */ 17987992Sjoerg verify = 0; 1801022Sache break; 1811022Sache 18287992Sjoerg case 'q': /* quiet */ 18387992Sjoerg quiet = 1; 1841022Sache break; 1851022Sache 18687992Sjoerg case 's': /* format string with detailed options */ 18787992Sjoerg fmtstring = optarg; 1881022Sache break; 1891022Sache 19087992Sjoerg case 'v': /* verify only */ 19187992Sjoerg verify = 1; 19287992Sjoerg verify_only = 1; 1931022Sache break; 1941022Sache 19587992Sjoerg case 'y': /* confirm */ 19661154Sphk confirm = 1; 19761154Sphk break; 19861154Sphk 19987992Sjoerg default: 2001022Sache usage(); 2011022Sache } 2021022Sache 2031022Sache if(optind != argc - 1) 2041022Sache usage(); 2051022Sache 20687992Sjoerg if (stat(argv[optind], &sb) == -1 && errno == ENOENT) { 20787992Sjoerg /* try prepending _PATH_DEV */ 208124200Sanholt device = malloc(strlen(argv[optind]) + sizeof(_PATH_DEV) + 1); 20987992Sjoerg if (device == 0) 21087992Sjoerg errx(EX_UNAVAILABLE, "out of memory"); 21187992Sjoerg strcpy(device, _PATH_DEV); 21287992Sjoerg strcat(device, argv[optind]); 21387992Sjoerg if (stat(device, &sb) == -1) { 21487992Sjoerg free(device); 21587992Sjoerg device = argv[optind]; /* let it fail below */ 21687992Sjoerg } 21787992Sjoerg } else { 21887992Sjoerg device = argv[optind]; 2191022Sache } 2201022Sache 22187992Sjoerg if ((fd = open(device, O_RDWR | O_NONBLOCK)) < 0) 22287992Sjoerg err(EX_OSERR, "open(%s)", device); 2231022Sache 22487992Sjoerg /* 22587992Sjoerg * Device initialization. 22687992Sjoerg * 22787992Sjoerg * First, get the device type descriptor. This tells us about 22887992Sjoerg * the media geometry data we need to format a medium. It also 22987992Sjoerg * lets us know quickly whether the device name actually points 23087992Sjoerg * to a floppy disk drive. 23187992Sjoerg * 23287992Sjoerg * Then, obtain any drive options. We're mainly interested to 23387992Sjoerg * see whether we're currently working on a device with media 23487992Sjoerg * density autoselection (FDOPT_AUTOSEL). Then, we add the 23587992Sjoerg * device option to tell the kernel not to log media errors, 23687992Sjoerg * since we can handle them ourselves. If the device does 23787992Sjoerg * media density autoselection, we then need to set the device 23887992Sjoerg * type appropriately, since by opening with O_NONBLOCK we 23987992Sjoerg * told the driver to bypass media autoselection (otherwise we 24087992Sjoerg * wouldn't stand a chance to format an unformatted or damaged 24187992Sjoerg * medium). We do not attempt to set the media type on any 24287992Sjoerg * other devices since this is a privileged operation. For the 24387992Sjoerg * same reason, specifying -f and -s options is only possible 24487992Sjoerg * for autoselecting devices. 24587992Sjoerg * 24687992Sjoerg * Finally, we are ready to turn off O_NONBLOCK, and start to 24787992Sjoerg * actually format something. 24887992Sjoerg */ 24929531Scharnier if(ioctl(fd, FD_GTYPE, &fdt) < 0) 25087992Sjoerg errx(EX_OSERR, "not a floppy disk: %s", device); 25187992Sjoerg if (ioctl(fd, FD_GDTYPE, &type) == -1) 25287992Sjoerg err(EX_OSERR, "ioctl(FD_GDTYPE)"); 25387992Sjoerg if (ioctl(fd, FD_GOPTS, &fdopts) == -1) 25487992Sjoerg err(EX_OSERR, "ioctl(FD_GOPTS)"); 25587992Sjoerg fdopts |= FDOPT_NOERRLOG; 25678858Sjoerg if (ioctl(fd, FD_SOPTS, &fdopts) == -1) 25787992Sjoerg err(EX_OSERR, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)"); 25887992Sjoerg if (format) { 25987992Sjoerg getname(type, &name, &descr); 26087992Sjoerg fdtp = get_fmt(format, type); 26187992Sjoerg if (fdtp == 0) 26287992Sjoerg errx(EX_USAGE, 26387992Sjoerg "unknown format %d KB for drive type %s", 26487992Sjoerg format, name); 26587992Sjoerg fdt = *fdtp; 2661022Sache } 26787992Sjoerg if (fmtstring) { 26887992Sjoerg parse_fmt(fmtstring, type, fdt, &newft); 26987992Sjoerg fdt = newft; 27087992Sjoerg } 271134081Sphk if (ioctl(fd, FD_STYPE, &fdt) < 0) 272134081Sphk err(EX_OSERR, "ioctl(FD_STYPE)"); 27387992Sjoerg if ((flags = fcntl(fd, F_GETFL, 0)) == -1) 27487992Sjoerg err(EX_OSERR, "fcntl(F_GETFL)"); 27587992Sjoerg flags &= ~O_NONBLOCK; 27687992Sjoerg if (fcntl(fd, F_SETFL, flags) == -1) 27787992Sjoerg err(EX_OSERR, "fcntl(F_SETFL)"); 2781022Sache 27987992Sjoerg bytes_per_track = fdt.sectrac * (128 << fdt.secsize); 2801022Sache 28155541Skato /* XXX 20/40 = 0.5 */ 28255541Skato tracks_per_dot = (fdt.tracks * fdt.heads + 20) / 40; 28355541Skato 2841022Sache if (verify_only) { 2851022Sache if(!quiet) 2861022Sache printf("Verify %dK floppy `%s'.\n", 2871022Sache fdt.tracks * fdt.heads * bytes_per_track / 1024, 28879161Sjoerg device); 2891022Sache } 29061154Sphk else if(!quiet && !confirm) { 2911022Sache printf("Format %dK floppy `%s'? (y/n): ", 2921022Sache fdt.tracks * fdt.heads * bytes_per_track / 1024, 29379161Sjoerg device); 29487992Sjoerg if(!yes()) { 2951022Sache printf("Not confirmed.\n"); 29687992Sjoerg return (EX_UNAVAILABLE); 2971022Sache } 2981022Sache } 2991022Sache 3001022Sache /* 3011022Sache * Formatting. 3021022Sache */ 3031022Sache if(!quiet) { 3041022Sache printf("Processing "); 30555541Skato for (i = 0; i < (fdt.tracks * fdt.heads) / tracks_per_dot; i++) 30655541Skato putchar('-'); 30755541Skato printf("\rProcessing "); 3081022Sache fflush(stdout); 3091022Sache } 3101022Sache 3111022Sache error = errs = 0; 3121022Sache 3131022Sache for (track = 0; track < fdt.tracks * fdt.heads; track++) { 3141022Sache if (!verify_only) { 3151183Srgrimes format_track(fd, track / fdt.heads, fdt.sectrac, 3161183Srgrimes track % fdt.heads, fdt.trans, fdt.f_gap, 31787992Sjoerg fdt.secsize, fill, fdt.f_inter, 31887992Sjoerg track % fdt.heads? fdt.offset_side2: 0); 3191022Sache if(!quiet && !((track + 1) % tracks_per_dot)) { 3201022Sache putchar('F'); 3211022Sache fflush(stdout); 3221022Sache } 3231022Sache } 3241022Sache if (verify) { 32579111Sjoerg if (verify_track(fd, track, bytes_per_track) < 0) { 32679111Sjoerg error = 1; 32779111Sjoerg if (errs < MAXPRINTERRS && errno == EIO) { 32879111Sjoerg if (ioctl(fd, FD_GSTAT, fdcs + errs) == 32979111Sjoerg -1) 33087992Sjoerg errx(EX_IOERR, 33179111Sjoerg "floppy IO error, but no FDC status"); 33279111Sjoerg errs++; 33379111Sjoerg } 33479111Sjoerg } 3351022Sache if(!quiet && !((track + 1) % tracks_per_dot)) { 3361022Sache if (!verify_only) 3371022Sache putchar('\b'); 3381022Sache if (error) { 3391022Sache putchar('E'); 3401022Sache error = 0; 3411022Sache } 3421022Sache else 3431022Sache putchar('V'); 3441022Sache fflush(stdout); 3451022Sache } 3461022Sache } 3471022Sache } 3481022Sache if(!quiet) 3491022Sache printf(" done.\n"); 3501022Sache 35179111Sjoerg if (!quiet && errs) { 35279111Sjoerg fflush(stdout); 35379111Sjoerg fprintf(stderr, "Errors encountered:\nCyl Head Sect Error\n"); 35479111Sjoerg for (i = 0; i < errs && i < MAXPRINTERRS; i++) { 35579111Sjoerg fprintf(stderr, " %2d %2d %2d ", 35679111Sjoerg fdcs[i].status[3], fdcs[i].status[4], 35779111Sjoerg fdcs[i].status[5]); 35879111Sjoerg printstatus(fdcs + i, 1); 35979111Sjoerg putc('\n', stderr); 36079111Sjoerg } 36179111Sjoerg if (errs >= MAXPRINTERRS) 36279111Sjoerg fprintf(stderr, "(Further errors not printed.)\n"); 36379111Sjoerg } 36479111Sjoerg 36579111Sjoerg return errs != 0; 3661022Sache} 367