fdformat.c revision 79111
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 79111 2001-07-02 21:24:03Z joerg $ 271022Sache */ 281022Sache 291022Sache/* 301022Sache * FreeBSD: 311022Sache * format a floppy disk 328857Srgrimes * 331022Sache * Added FD_GTYPE ioctl, verifying, proportional indicators. 341022Sache * Serge Vakulenko, vak@zebub.msk.su 351022Sache * Sat Dec 18 17:45:47 MSK 1993 361022Sache * 371022Sache * Final adaptation, change format/verify logic, add separate 381022Sache * format gap/interleave values 391022Sache * Andrew A. Chernov, ache@astral.msk.su 401022Sache * Thu Jan 27 00:47:24 MSK 1994 411022Sache */ 421022Sache 4329531Scharnier#include <ctype.h> 4429531Scharnier#include <err.h> 4579111Sjoerg#include <errno.h> 4629531Scharnier#include <fcntl.h> 4769793Sobrien#include <paths.h> 481022Sache#include <stdio.h> 491022Sache#include <stdlib.h> 5029531Scharnier#include <strings.h> 511022Sache#include <unistd.h> 521022Sache 5377801Sjoerg#include <sys/fdcio.h> 541022Sache 5579111Sjoerg#include "fdutil.h" 5679111Sjoerg 571022Sachestatic void 581022Sacheformat_track(int fd, int cyl, int secs, int head, int rate, 591137Sache int gaplen, int secsize, int fill,int interleave) 601022Sache{ 611022Sache struct fd_formb f; 621137Sache register int i,j; 631138Sache int il[FD_MAX_NSEC + 1]; 641022Sache 651137Sache memset(il,0,sizeof il); 661137Sache for(j = 0, i = 1; i <= secs; i++) { 671137Sache while(il[(j%secs)+1]) j++; 681137Sache il[(j%secs)+1] = i; 691137Sache j += interleave; 701137Sache } 711137Sache 721022Sache f.format_version = FD_FORMAT_VERSION; 731022Sache f.head = head; 741022Sache f.cyl = cyl; 751022Sache f.transfer_rate = rate; 761022Sache 771022Sache f.fd_formb_secshift = secsize; 781022Sache f.fd_formb_nsecs = secs; 791022Sache f.fd_formb_gaplen = gaplen; 801022Sache f.fd_formb_fillbyte = fill; 811022Sache for(i = 0; i < secs; i++) { 821022Sache f.fd_formb_cylno(i) = cyl; 831022Sache f.fd_formb_headno(i) = head; 841137Sache f.fd_formb_secno(i) = il[i+1]; 851022Sache f.fd_formb_secsize(i) = secsize; 861022Sache } 8729531Scharnier if(ioctl(fd, FD_FORM, (caddr_t)&f) < 0) 8829531Scharnier err(1, "ioctl(FD_FORM)"); 891022Sache} 901022Sache 911022Sachestatic int 921022Sacheverify_track(int fd, int track, int tracksize) 931022Sache{ 941022Sache static char *buf = 0; 951022Sache static int bufsz = 0; 961533Sjoerg int fdopts = -1, ofdopts, rv = 0; 971022Sache 981533Sjoerg if (ioctl(fd, FD_GOPTS, &fdopts) < 0) 9929531Scharnier warn("warning: ioctl(FD_GOPTS)"); 1001533Sjoerg else { 1011533Sjoerg ofdopts = fdopts; 1021533Sjoerg fdopts |= FDOPT_NORETRY; 1031533Sjoerg (void)ioctl(fd, FD_SOPTS, &fdopts); 1041533Sjoerg } 1058857Srgrimes 1061022Sache if (bufsz < tracksize) { 1071022Sache if (buf) 1081022Sache free (buf); 1091022Sache bufsz = tracksize; 1101022Sache buf = 0; 1111022Sache } 1121022Sache if (! buf) 1131022Sache buf = malloc (bufsz); 11429531Scharnier if (! buf) 11529531Scharnier errx(2, "out of memory"); 1161022Sache if (lseek (fd, (long) track*tracksize, 0) < 0) 1171533Sjoerg rv = -1; 1181533Sjoerg /* try twice reading it, without using the normal retrier */ 1191533Sjoerg else if (read (fd, buf, tracksize) != tracksize 1201533Sjoerg && read (fd, buf, tracksize) != tracksize) 1211533Sjoerg rv = -1; 1221533Sjoerg if(fdopts != -1) 1231533Sjoerg (void)ioctl(fd, FD_SOPTS, &ofdopts); 1241533Sjoerg return (rv); 1251022Sache} 1261022Sache 1271022Sachestatic const char * 1281022Sachemakename(const char *arg, const char *suffix) 1291022Sache{ 13056447Sasmodai static char namebuff[20]; /* big enough for "/dev/fd0a"... */ 1311022Sache 1321022Sache memset(namebuff, 0, 20); 1331022Sache if(*arg == '\0') /* ??? */ 1341022Sache return arg; 1351022Sache if(*arg == '/') /* do not convert absolute pathnames */ 1361022Sache return arg; 13769793Sobrien strcpy(namebuff, _PATH_DEV); 1381022Sache strncat(namebuff, arg, 3); 1391022Sache strcat(namebuff, suffix); 1401022Sache return namebuff; 1411022Sache} 1421022Sache 1431022Sachestatic void 1441533Sjoergusage (void) 1451022Sache{ 14629531Scharnier fprintf(stderr, "%s\n%s\n", 14761154Sphk "usage: fdformat [-y] [-q] [-n | -v] [-f #] [-c #] [-s #] [-h #]", 14829531Scharnier " [-r #] [-g #] [-i #] [-S #] [-F #] [-t #] devname"); 1491022Sache exit(2); 1501022Sache} 1511022Sache 1521022Sachestatic int 1531533Sjoergyes (void) 1541022Sache{ 1551022Sache char reply [256], *p; 1561022Sache 1571022Sache reply[sizeof(reply)-1] = 0; 1581022Sache for (;;) { 1591022Sache fflush(stdout); 1601022Sache if (! fgets (reply, sizeof(reply)-1, stdin)) 1611022Sache return (0); 1621022Sache for (p=reply; *p==' ' || *p=='\t'; ++p) 1631022Sache continue; 1641022Sache if (*p=='y' || *p=='Y') 1651022Sache return (1); 1661022Sache if (*p=='n' || *p=='N' || *p=='\n' || *p=='\r') 1671022Sache return (0); 1681022Sache printf("Answer `yes' or `no': "); 1691022Sache } 1701022Sache} 1711022Sache 1721022Sacheint 1731022Sachemain(int argc, char **argv) 1741022Sache{ 1751022Sache int format = -1, cyls = -1, secs = -1, heads = -1, intleave = -1; 1761022Sache int rate = -1, gaplen = -1, secsize = -1, steps = -1; 17761154Sphk int fill = 0xf6, quiet = 0, verify = 1, verify_only = 0, confirm = 0; 17879111Sjoerg int fd, c, i, track, error, tracks_per_dot, bytes_per_track, errs; 17978858Sjoerg int fdopts; 1801022Sache const char *devname, *suffix; 1811022Sache struct fd_type fdt; 18279111Sjoerg#define MAXPRINTERRS 10 18379111Sjoerg struct fdc_status fdcs[MAXPRINTERRS]; 1841022Sache 18561154Sphk while((c = getopt(argc, argv, "f:c:s:h:r:g:S:F:t:i:qyvn")) != -1) 1861022Sache switch(c) { 1871022Sache case 'f': /* format in kilobytes */ 1881022Sache format = atoi(optarg); 1891022Sache break; 1901022Sache 1911022Sache case 'c': /* # of cyls */ 1921022Sache cyls = atoi(optarg); 1931022Sache break; 1941022Sache 1951022Sache case 's': /* # of secs per track */ 1961022Sache secs = atoi(optarg); 1971022Sache break; 1981022Sache 1991022Sache case 'h': /* # of heads */ 2001022Sache heads = atoi(optarg); 2011022Sache break; 2021022Sache 2031022Sache case 'r': /* transfer rate, kilobyte/sec */ 2041022Sache rate = atoi(optarg); 2051022Sache break; 2061022Sache 2071022Sache case 'g': /* length of GAP3 to format with */ 2081022Sache gaplen = atoi(optarg); 2091022Sache break; 2101022Sache 2111022Sache case 'S': /* sector size shift factor (1 << S)*128 */ 2121022Sache secsize = atoi(optarg); 2131022Sache break; 2141022Sache 2151022Sache case 'F': /* fill byte, C-like notation allowed */ 2161022Sache fill = (int)strtol(optarg, (char **)0, 0); 2171022Sache break; 2181022Sache 2191022Sache case 't': /* steps per track */ 2201022Sache steps = atoi(optarg); 2211022Sache break; 2221022Sache 2231022Sache case 'i': /* interleave factor */ 2241022Sache intleave = atoi(optarg); 2251022Sache break; 2261022Sache 2271022Sache case 'q': 2281022Sache quiet = 1; 2291022Sache break; 2301022Sache 23161154Sphk case 'y': 23261154Sphk confirm = 1; 23361154Sphk break; 23461154Sphk 2351022Sache case 'n': 2361022Sache verify = 0; 2371022Sache break; 2381022Sache 2391022Sache case 'v': 2401022Sache verify = 1; 2411022Sache verify_only = 1; 2421022Sache break; 2431022Sache 2441022Sache case '?': default: 2451022Sache usage(); 2461022Sache } 2471022Sache 2481022Sache if(optind != argc - 1) 2491022Sache usage(); 2501022Sache 2511022Sache switch(format) { 2521022Sache default: 25329531Scharnier errx(2, "bad floppy size: %dK", format); 2541022Sache case -1: suffix = ""; break; 2551022Sache case 360: suffix = ".360"; break; 25655541Skato case 640: suffix = ".640"; break; 2571022Sache case 720: suffix = ".720"; break; 2581022Sache case 800: suffix = ".800"; break; 2591022Sache case 820: suffix = ".820"; break; 2601022Sache case 1200: suffix = ".1200"; break; 26155541Skato case 1232: suffix = ".1232"; break; 2621022Sache case 1440: suffix = ".1440"; break; 2631022Sache case 1480: suffix = ".1480"; break; 2641022Sache case 1720: suffix = ".1720"; break; 2651022Sache } 2661022Sache 2671022Sache devname = makename(argv[optind], suffix); 2681022Sache 26929531Scharnier if((fd = open(devname, O_RDWR)) < 0) 27029531Scharnier err(1, "%s", devname); 2711022Sache 27229531Scharnier if(ioctl(fd, FD_GTYPE, &fdt) < 0) 27329531Scharnier errx(1, "not a floppy disk: %s", devname); 27478858Sjoerg fdopts = FDOPT_NOERRLOG; 27578858Sjoerg if (ioctl(fd, FD_SOPTS, &fdopts) == -1) 27678858Sjoerg err(1, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)"); 2771022Sache 2781022Sache switch(rate) { 2791022Sache case -1: break; 2801022Sache case 250: fdt.trans = FDC_250KBPS; break; 2811022Sache case 300: fdt.trans = FDC_300KBPS; break; 2821022Sache case 500: fdt.trans = FDC_500KBPS; break; 2831022Sache default: 28429531Scharnier errx(2, "invalid transfer rate: %d", rate); 2851022Sache } 2861022Sache 2871022Sache if (cyls >= 0) fdt.tracks = cyls; 2881022Sache if (secs >= 0) fdt.sectrac = secs; 28929531Scharnier if (fdt.sectrac > FD_MAX_NSEC) 29029531Scharnier errx(2, "too many sectors per track, max value is %d", FD_MAX_NSEC); 2911022Sache if (heads >= 0) fdt.heads = heads; 2921022Sache if (gaplen >= 0) fdt.f_gap = gaplen; 2931022Sache if (secsize >= 0) fdt.secsize = secsize; 2941022Sache if (steps >= 0) fdt.steptrac = steps; 2951022Sache if (intleave >= 0) fdt.f_inter = intleave; 2961022Sache 2971022Sache bytes_per_track = fdt.sectrac * (1<<fdt.secsize) * 128; 2981022Sache 29955541Skato /* XXX 20/40 = 0.5 */ 30055541Skato tracks_per_dot = (fdt.tracks * fdt.heads + 20) / 40; 30155541Skato 3021022Sache if (verify_only) { 3031022Sache if(!quiet) 3041022Sache printf("Verify %dK floppy `%s'.\n", 3051022Sache fdt.tracks * fdt.heads * bytes_per_track / 1024, 3061022Sache devname); 3071022Sache } 30861154Sphk else if(!quiet && !confirm) { 3091022Sache printf("Format %dK floppy `%s'? (y/n): ", 3101022Sache fdt.tracks * fdt.heads * bytes_per_track / 1024, 3111022Sache devname); 3121022Sache if(! yes ()) { 3131022Sache printf("Not confirmed.\n"); 31477063Sphk return 3; 3151022Sache } 3161022Sache } 3171022Sache 3181022Sache /* 3191022Sache * Formatting. 3201022Sache */ 3211022Sache if(!quiet) { 32255541Skato int i; 32355541Skato 3241022Sache printf("Processing "); 32555541Skato for (i = 0; i < (fdt.tracks * fdt.heads) / tracks_per_dot; i++) 32655541Skato putchar('-'); 32755541Skato printf("\rProcessing "); 3281022Sache fflush(stdout); 3291022Sache } 3301022Sache 3311022Sache error = errs = 0; 3321022Sache 3331022Sache for (track = 0; track < fdt.tracks * fdt.heads; track++) { 3341022Sache if (!verify_only) { 3351183Srgrimes format_track(fd, track / fdt.heads, fdt.sectrac, 3361183Srgrimes track % fdt.heads, fdt.trans, fdt.f_gap, 3371183Srgrimes fdt.secsize, fill, fdt.f_inter); 3381022Sache if(!quiet && !((track + 1) % tracks_per_dot)) { 3391022Sache putchar('F'); 3401022Sache fflush(stdout); 3411022Sache } 3421022Sache } 3431022Sache if (verify) { 34479111Sjoerg if (verify_track(fd, track, bytes_per_track) < 0) { 34579111Sjoerg error = 1; 34679111Sjoerg if (errs < MAXPRINTERRS && errno == EIO) { 34779111Sjoerg if (ioctl(fd, FD_GSTAT, fdcs + errs) == 34879111Sjoerg -1) 34979111Sjoerg errx(1, 35079111Sjoerg "floppy IO error, but no FDC status"); 35179111Sjoerg errs++; 35279111Sjoerg } 35379111Sjoerg } 3541022Sache if(!quiet && !((track + 1) % tracks_per_dot)) { 3551022Sache if (!verify_only) 3561022Sache putchar('\b'); 3571022Sache if (error) { 3581022Sache putchar('E'); 3591022Sache error = 0; 3601022Sache } 3611022Sache else 3621022Sache putchar('V'); 3631022Sache fflush(stdout); 3641022Sache } 3651022Sache } 3661022Sache } 3671022Sache if(!quiet) 3681022Sache printf(" done.\n"); 3691022Sache 37079111Sjoerg if (!quiet && errs) { 37179111Sjoerg fflush(stdout); 37279111Sjoerg fprintf(stderr, "Errors encountered:\nCyl Head Sect Error\n"); 37379111Sjoerg for (i = 0; i < errs && i < MAXPRINTERRS; i++) { 37479111Sjoerg fprintf(stderr, " %2d %2d %2d ", 37579111Sjoerg fdcs[i].status[3], fdcs[i].status[4], 37679111Sjoerg fdcs[i].status[5]); 37779111Sjoerg printstatus(fdcs + i, 1); 37879111Sjoerg putc('\n', stderr); 37979111Sjoerg } 38079111Sjoerg if (errs >= MAXPRINTERRS) 38179111Sjoerg fprintf(stderr, "(Further errors not printed.)\n"); 38279111Sjoerg } 38379111Sjoerg 38479111Sjoerg return errs != 0; 3851022Sache} 386