fdformat.c revision 79111
1205859Sjoel/* 2162874Snetchild * Copyright (C) 1992-1994,2001 by Joerg Wunsch, Dresden 3159687Snetchild * All rights reserved. 4159687Snetchild * 5159687Snetchild * Redistribution and use in source and binary forms, with or without 6159687Snetchild * modification, are permitted provided that the following conditions 7159687Snetchild * are met: 8159687Snetchild * 1. Redistributions of source code must retain the above copyright 9159687Snetchild * notice, this list of conditions and the following disclaimer. 10159687Snetchild * 2. Redistributions in binary form must reproduce the above copyright 11159687Snetchild * notice, this list of conditions and the following disclaimer in the 12159687Snetchild * documentation and/or other materials provided with the distribution. 13159687Snetchild * 14159687Snetchild * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15159687Snetchild * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16159687Snetchild * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17159687Snetchild * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, 18159687Snetchild * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19159687Snetchild * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20159687Snetchild * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21159687Snetchild * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22159687Snetchild * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 23159687Snetchild * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24159687Snetchild * POSSIBILITY OF SUCH DAMAGE. 25159687Snetchild * 26159687Snetchild * $FreeBSD: head/usr.sbin/fdformat/fdformat.c 79111 2001-07-02 21:24:03Z joerg $ 27159687Snetchild */ 28159687Snetchild 29159687Snetchild/* 30193640Sariff * FreeBSD: 31193640Sariff * format a floppy disk 32193640Sariff * 33193640Sariff * Added FD_GTYPE ioctl, verifying, proportional indicators. 34159687Snetchild * Serge Vakulenko, vak@zebub.msk.su 35159687Snetchild * Sat Dec 18 17:45:47 MSK 1993 36162874Snetchild * 37159687Snetchild * Final adaptation, change format/verify logic, add separate 38227293Sed * format gap/interleave values 39159687Snetchild * Andrew A. Chernov, ache@astral.msk.su 40162874Snetchild * Thu Jan 27 00:47:24 MSK 1994 41162874Snetchild */ 42159687Snetchild 43162874Snetchild#include <ctype.h> 44159687Snetchild#include <err.h> 45159687Snetchild#include <errno.h> 46159687Snetchild#include <fcntl.h> 47159687Snetchild#include <paths.h> 48159687Snetchild#include <stdio.h> 49159687Snetchild#include <stdlib.h> 50159687Snetchild#include <strings.h> 51162874Snetchild#include <unistd.h> 52166713Sariff 53159687Snetchild#include <sys/fdcio.h> 54159687Snetchild 55159687Snetchild#include "fdutil.h" 56162874Snetchild 57159687Snetchildstatic void 58159687Snetchildformat_track(int fd, int cyl, int secs, int head, int rate, 59159687Snetchild int gaplen, int secsize, int fill,int interleave) 60159687Snetchild{ 61159687Snetchild struct fd_formb f; 62159687Snetchild register int i,j; 63159687Snetchild int il[FD_MAX_NSEC + 1]; 64159687Snetchild 65159687Snetchild memset(il,0,sizeof il); 66159687Snetchild for(j = 0, i = 1; i <= secs; i++) { 67159687Snetchild while(il[(j%secs)+1]) j++; 68159687Snetchild il[(j%secs)+1] = i; 69159687Snetchild j += interleave; 70159687Snetchild } 71159687Snetchild 72159687Snetchild f.format_version = FD_FORMAT_VERSION; 73159687Snetchild f.head = head; 74159687Snetchild f.cyl = cyl; 75159687Snetchild f.transfer_rate = rate; 76162874Snetchild 77159687Snetchild f.fd_formb_secshift = secsize; 78159687Snetchild f.fd_formb_nsecs = secs; 79159687Snetchild f.fd_formb_gaplen = gaplen; 80159687Snetchild f.fd_formb_fillbyte = fill; 81162874Snetchild for(i = 0; i < secs; i++) { 82159687Snetchild f.fd_formb_cylno(i) = cyl; 83159687Snetchild f.fd_formb_headno(i) = head; 84159687Snetchild f.fd_formb_secno(i) = il[i+1]; 85159687Snetchild f.fd_formb_secsize(i) = secsize; 86159687Snetchild } 87159687Snetchild if(ioctl(fd, FD_FORM, (caddr_t)&f) < 0) 88159687Snetchild err(1, "ioctl(FD_FORM)"); 89162874Snetchild} 90162874Snetchild 91162874Snetchildstatic int 92162874Snetchildverify_track(int fd, int track, int tracksize) 93162874Snetchild{ 94162874Snetchild static char *buf = 0; 95170031Sjoel static int bufsz = 0; 96170031Sjoel int fdopts = -1, ofdopts, rv = 0; 97170031Sjoel 98170031Sjoel if (ioctl(fd, FD_GOPTS, &fdopts) < 0) 99170031Sjoel warn("warning: ioctl(FD_GOPTS)"); 100170031Sjoel else { 101162874Snetchild ofdopts = fdopts; 102159687Snetchild fdopts |= FDOPT_NORETRY; 103162874Snetchild (void)ioctl(fd, FD_SOPTS, &fdopts); 104162874Snetchild } 105162874Snetchild 106159687Snetchild if (bufsz < tracksize) { 107162874Snetchild if (buf) 108159687Snetchild free (buf); 109159687Snetchild bufsz = tracksize; 110162874Snetchild buf = 0; 111159687Snetchild } 112159687Snetchild if (! buf) 113162874Snetchild buf = malloc (bufsz); 114159687Snetchild if (! buf) 115159687Snetchild errx(2, "out of memory"); 116162874Snetchild if (lseek (fd, (long) track*tracksize, 0) < 0) 117162874Snetchild rv = -1; 118162874Snetchild /* try twice reading it, without using the normal retrier */ 119162874Snetchild else if (read (fd, buf, tracksize) != tracksize 120162874Snetchild && read (fd, buf, tracksize) != tracksize) 121162874Snetchild rv = -1; 122162874Snetchild if(fdopts != -1) 123162874Snetchild (void)ioctl(fd, FD_SOPTS, &ofdopts); 124162874Snetchild return (rv); 125162874Snetchild} 126162874Snetchild 127159687Snetchildstatic const char * 128159687Snetchildmakename(const char *arg, const char *suffix) 129159687Snetchild{ 130159687Snetchild static char namebuff[20]; /* big enough for "/dev/fd0a"... */ 131159687Snetchild 132159687Snetchild memset(namebuff, 0, 20); 133159687Snetchild if(*arg == '\0') /* ??? */ 134159687Snetchild return arg; 135159687Snetchild if(*arg == '/') /* do not convert absolute pathnames */ 136159687Snetchild return arg; 137159687Snetchild strcpy(namebuff, _PATH_DEV); 138159687Snetchild strncat(namebuff, arg, 3); 139162874Snetchild strcat(namebuff, suffix); 140162874Snetchild return namebuff; 141159687Snetchild} 142162874Snetchild 143159687Snetchildstatic void 144159687Snetchildusage (void) 145162874Snetchild{ 146159687Snetchild fprintf(stderr, "%s\n%s\n", 147162874Snetchild "usage: fdformat [-y] [-q] [-n | -v] [-f #] [-c #] [-s #] [-h #]", 148159687Snetchild " [-r #] [-g #] [-i #] [-S #] [-F #] [-t #] devname"); 149159687Snetchild exit(2); 150159687Snetchild} 151162874Snetchild 152159689Snetchildstatic int 153159687Snetchildyes (void) 154159687Snetchild{ 155159687Snetchild char reply [256], *p; 156159687Snetchild 157162874Snetchild reply[sizeof(reply)-1] = 0; 158159687Snetchild for (;;) { 159159687Snetchild fflush(stdout); 160159687Snetchild if (! fgets (reply, sizeof(reply)-1, stdin)) 161159687Snetchild return (0); 162159687Snetchild for (p=reply; *p==' ' || *p=='\t'; ++p) 163159687Snetchild continue; 164159687Snetchild if (*p=='y' || *p=='Y') 165159687Snetchild return (1); 166162874Snetchild if (*p=='n' || *p=='N' || *p=='\n' || *p=='\r') 167159687Snetchild return (0); 168159687Snetchild printf("Answer `yes' or `no': "); 169162874Snetchild } 170159687Snetchild} 171159687Snetchild 172159687Snetchildint 173162874Snetchildmain(int argc, char **argv) 174159687Snetchild{ 175159687Snetchild int format = -1, cyls = -1, secs = -1, heads = -1, intleave = -1; 176159687Snetchild int rate = -1, gaplen = -1, secsize = -1, steps = -1; 177159687Snetchild int fill = 0xf6, quiet = 0, verify = 1, verify_only = 0, confirm = 0; 178159687Snetchild int fd, c, i, track, error, tracks_per_dot, bytes_per_track, errs; 179159687Snetchild int fdopts; 180159687Snetchild const char *devname, *suffix; 181162874Snetchild struct fd_type fdt; 182159687Snetchild#define MAXPRINTERRS 10 183159687Snetchild struct fdc_status fdcs[MAXPRINTERRS]; 184159687Snetchild 185159687Snetchild while((c = getopt(argc, argv, "f:c:s:h:r:g:S:F:t:i:qyvn")) != -1) 186159687Snetchild switch(c) { 187159687Snetchild case 'f': /* format in kilobytes */ 188159687Snetchild format = atoi(optarg); 189162874Snetchild break; 190159687Snetchild 191159687Snetchild case 'c': /* # of cyls */ 192159687Snetchild cyls = atoi(optarg); 193159687Snetchild break; 194159687Snetchild 195159687Snetchild case 's': /* # of secs per track */ 196159687Snetchild secs = atoi(optarg); 197162874Snetchild break; 198159687Snetchild 199159687Snetchild case 'h': /* # of heads */ 200159689Snetchild heads = atoi(optarg); 201159687Snetchild break; 202159687Snetchild 203159687Snetchild case 'r': /* transfer rate, kilobyte/sec */ 204159687Snetchild rate = atoi(optarg); 205162874Snetchild break; 206159687Snetchild 207159687Snetchild case 'g': /* length of GAP3 to format with */ 208162874Snetchild gaplen = atoi(optarg); 209159687Snetchild break; 210159687Snetchild 211162874Snetchild case 'S': /* sector size shift factor (1 << S)*128 */ 212162874Snetchild secsize = atoi(optarg); 213159687Snetchild break; 214162874Snetchild 215159687Snetchild case 'F': /* fill byte, C-like notation allowed */ 216162874Snetchild fill = (int)strtol(optarg, (char **)0, 0); 217162874Snetchild break; 218159687Snetchild 219162874Snetchild case 't': /* steps per track */ 220159687Snetchild steps = atoi(optarg); 221162874Snetchild break; 222162874Snetchild 223162874Snetchild case 'i': /* interleave factor */ 224162874Snetchild intleave = atoi(optarg); 225162874Snetchild break; 226162874Snetchild 227162874Snetchild case 'q': 228162874Snetchild quiet = 1; 229162874Snetchild break; 230162874Snetchild 231162874Snetchild case 'y': 232162874Snetchild confirm = 1; 233162874Snetchild break; 234162874Snetchild 235162874Snetchild case 'n': 236162874Snetchild verify = 0; 237162874Snetchild break; 238162874Snetchild 239162874Snetchild case 'v': 240162874Snetchild verify = 1; 241188480Snetchild verify_only = 1; 242170031Sjoel break; 243170031Sjoel 244159687Snetchild case '?': default: 245159687Snetchild usage(); 246159687Snetchild } 247159687Snetchild 248162874Snetchild if(optind != argc - 1) 249159687Snetchild usage(); 250159687Snetchild 251162874Snetchild switch(format) { 252159687Snetchild default: 253162874Snetchild errx(2, "bad floppy size: %dK", format); 254159687Snetchild case -1: suffix = ""; break; 255162874Snetchild case 360: suffix = ".360"; break; 256162874Snetchild case 640: suffix = ".640"; break; 257159687Snetchild case 720: suffix = ".720"; break; 258162874Snetchild case 800: suffix = ".800"; break; 259162874Snetchild case 820: suffix = ".820"; break; 260162874Snetchild case 1200: suffix = ".1200"; break; 261162874Snetchild case 1232: suffix = ".1232"; break; 262162874Snetchild case 1440: suffix = ".1440"; break; 263162874Snetchild case 1480: suffix = ".1480"; break; 264162874Snetchild case 1720: suffix = ".1720"; break; 265159687Snetchild } 266159687Snetchild 267159687Snetchild devname = makename(argv[optind], suffix); 268159687Snetchild 269162874Snetchild if((fd = open(devname, O_RDWR)) < 0) 270159687Snetchild err(1, "%s", devname); 271159687Snetchild 272162874Snetchild if(ioctl(fd, FD_GTYPE, &fdt) < 0) 273159687Snetchild errx(1, "not a floppy disk: %s", devname); 274159687Snetchild fdopts = FDOPT_NOERRLOG; 275159687Snetchild if (ioctl(fd, FD_SOPTS, &fdopts) == -1) 276170031Sjoel err(1, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)"); 277170031Sjoel 278162874Snetchild switch(rate) { 279162874Snetchild case -1: break; 280162874Snetchild case 250: fdt.trans = FDC_250KBPS; break; 281159687Snetchild case 300: fdt.trans = FDC_300KBPS; break; 282162874Snetchild case 500: fdt.trans = FDC_500KBPS; break; 283162874Snetchild default: 284162874Snetchild errx(2, "invalid transfer rate: %d", rate); 285162874Snetchild } 286213779Srpaulo 287213779Srpaulo if (cyls >= 0) fdt.tracks = cyls; 288162874Snetchild if (secs >= 0) fdt.sectrac = secs; 289162874Snetchild if (fdt.sectrac > FD_MAX_NSEC) 290162874Snetchild errx(2, "too many sectors per track, max value is %d", FD_MAX_NSEC); 291162874Snetchild if (heads >= 0) fdt.heads = heads; 292162874Snetchild if (gaplen >= 0) fdt.f_gap = gaplen; 293159687Snetchild if (secsize >= 0) fdt.secsize = secsize; 294170031Sjoel if (steps >= 0) fdt.steptrac = steps; 295170031Sjoel if (intleave >= 0) fdt.f_inter = intleave; 296162874Snetchild 297162874Snetchild bytes_per_track = fdt.sectrac * (1<<fdt.secsize) * 128; 298162874Snetchild 299159687Snetchild /* XXX 20/40 = 0.5 */ 300162874Snetchild tracks_per_dot = (fdt.tracks * fdt.heads + 20) / 40; 301162874Snetchild 302162874Snetchild if (verify_only) { 303162874Snetchild if(!quiet) 304188480Snetchild printf("Verify %dK floppy `%s'.\n", 305188480Snetchild fdt.tracks * fdt.heads * bytes_per_track / 1024, 306162874Snetchild devname); 307162874Snetchild } 308162874Snetchild else if(!quiet && !confirm) { 309162874Snetchild printf("Format %dK floppy `%s'? (y/n): ", 310162874Snetchild fdt.tracks * fdt.heads * bytes_per_track / 1024, 311162874Snetchild devname); 312159687Snetchild if(! yes ()) { 313162874Snetchild printf("Not confirmed.\n"); 314159687Snetchild return 3; 315162874Snetchild } 316162874Snetchild } 317159687Snetchild 318162874Snetchild /* 319159687Snetchild * Formatting. 320162874Snetchild */ 321159687Snetchild if(!quiet) { 322162874Snetchild int i; 323162874Snetchild 324159687Snetchild printf("Processing "); 325162874Snetchild for (i = 0; i < (fdt.tracks * fdt.heads) / tracks_per_dot; i++) 326159687Snetchild putchar('-'); 327162874Snetchild printf("\rProcessing "); 328159687Snetchild fflush(stdout); 329162874Snetchild } 330162874Snetchild 331159687Snetchild error = errs = 0; 332162874Snetchild 333162874Snetchild for (track = 0; track < fdt.tracks * fdt.heads; track++) { 334162874Snetchild if (!verify_only) { 335162874Snetchild format_track(fd, track / fdt.heads, fdt.sectrac, 336162874Snetchild track % fdt.heads, fdt.trans, fdt.f_gap, 337162874Snetchild fdt.secsize, fill, fdt.f_inter); 338162874Snetchild if(!quiet && !((track + 1) % tracks_per_dot)) { 339162874Snetchild putchar('F'); 340162874Snetchild fflush(stdout); 341162874Snetchild } 342162874Snetchild } 343162874Snetchild if (verify) { 344162874Snetchild if (verify_track(fd, track, bytes_per_track) < 0) { 345162874Snetchild error = 1; 346162874Snetchild if (errs < MAXPRINTERRS && errno == EIO) { 347162874Snetchild if (ioctl(fd, FD_GSTAT, fdcs + errs) == 348162874Snetchild -1) 349162874Snetchild errx(1, 350162874Snetchild "floppy IO error, but no FDC status"); 351162874Snetchild errs++; 352162874Snetchild } 353162874Snetchild } 354170031Sjoel if(!quiet && !((track + 1) % tracks_per_dot)) { 355170031Sjoel if (!verify_only) 356170031Sjoel putchar('\b'); 357170031Sjoel if (error) { 358170031Sjoel putchar('E'); 359170031Sjoel error = 0; 360170031Sjoel } 361170031Sjoel else 362159687Snetchild putchar('V'); 363159687Snetchild fflush(stdout); 364159687Snetchild } 365162874Snetchild } 366162874Snetchild } 367 if(!quiet) 368 printf(" done.\n"); 369 370 if (!quiet && errs) { 371 fflush(stdout); 372 fprintf(stderr, "Errors encountered:\nCyl Head Sect Error\n"); 373 for (i = 0; i < errs && i < MAXPRINTERRS; i++) { 374 fprintf(stderr, " %2d %2d %2d ", 375 fdcs[i].status[3], fdcs[i].status[4], 376 fdcs[i].status[5]); 377 printstatus(fdcs + i, 1); 378 putc('\n', stderr); 379 } 380 if (errs >= MAXPRINTERRS) 381 fprintf(stderr, "(Further errors not printed.)\n"); 382 } 383 384 return errs != 0; 385} 386