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: releng/10.3/usr.sbin/fdformat/fdformat.c 218910 2011-02-21 09:56:08Z brucec $ 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 } 78218910Sbrucec (void)ioctl(fd, FD_FORM, (caddr_t)&f); 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; 148194892Sjoerg int 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 */ 207124200Sanholt 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 (format) { 25387992Sjoerg getname(type, &name, &descr); 25487992Sjoerg fdtp = get_fmt(format, type); 25587992Sjoerg if (fdtp == 0) 25687992Sjoerg errx(EX_USAGE, 25787992Sjoerg "unknown format %d KB for drive type %s", 25887992Sjoerg format, name); 25987992Sjoerg fdt = *fdtp; 2601022Sache } 26187992Sjoerg if (fmtstring) { 26287992Sjoerg parse_fmt(fmtstring, type, fdt, &newft); 26387992Sjoerg fdt = newft; 26487992Sjoerg } 265134081Sphk if (ioctl(fd, FD_STYPE, &fdt) < 0) 266134081Sphk err(EX_OSERR, "ioctl(FD_STYPE)"); 26787992Sjoerg if ((flags = fcntl(fd, F_GETFL, 0)) == -1) 26887992Sjoerg err(EX_OSERR, "fcntl(F_GETFL)"); 26987992Sjoerg flags &= ~O_NONBLOCK; 27087992Sjoerg if (fcntl(fd, F_SETFL, flags) == -1) 27187992Sjoerg err(EX_OSERR, "fcntl(F_SETFL)"); 2721022Sache 27387992Sjoerg bytes_per_track = fdt.sectrac * (128 << fdt.secsize); 2741022Sache 27555541Skato /* XXX 20/40 = 0.5 */ 27655541Skato tracks_per_dot = (fdt.tracks * fdt.heads + 20) / 40; 27755541Skato 2781022Sache if (verify_only) { 2791022Sache if(!quiet) 2801022Sache printf("Verify %dK floppy `%s'.\n", 2811022Sache fdt.tracks * fdt.heads * bytes_per_track / 1024, 28279161Sjoerg device); 2831022Sache } 28461154Sphk else if(!quiet && !confirm) { 2851022Sache printf("Format %dK floppy `%s'? (y/n): ", 2861022Sache fdt.tracks * fdt.heads * bytes_per_track / 1024, 28779161Sjoerg device); 28887992Sjoerg if(!yes()) { 2891022Sache printf("Not confirmed.\n"); 29087992Sjoerg return (EX_UNAVAILABLE); 2911022Sache } 2921022Sache } 2931022Sache 2941022Sache /* 2951022Sache * Formatting. 2961022Sache */ 2971022Sache if(!quiet) { 2981022Sache printf("Processing "); 29955541Skato for (i = 0; i < (fdt.tracks * fdt.heads) / tracks_per_dot; i++) 30055541Skato putchar('-'); 30155541Skato printf("\rProcessing "); 3021022Sache fflush(stdout); 3031022Sache } 3041022Sache 3051022Sache error = errs = 0; 3061022Sache 3071022Sache for (track = 0; track < fdt.tracks * fdt.heads; track++) { 3081022Sache if (!verify_only) { 3091183Srgrimes format_track(fd, track / fdt.heads, fdt.sectrac, 3101183Srgrimes track % fdt.heads, fdt.trans, fdt.f_gap, 31187992Sjoerg fdt.secsize, fill, fdt.f_inter, 31287992Sjoerg track % fdt.heads? fdt.offset_side2: 0); 3131022Sache if(!quiet && !((track + 1) % tracks_per_dot)) { 3141022Sache putchar('F'); 3151022Sache fflush(stdout); 3161022Sache } 3171022Sache } 3181022Sache if (verify) { 31979111Sjoerg if (verify_track(fd, track, bytes_per_track) < 0) { 32079111Sjoerg error = 1; 32179111Sjoerg if (errs < MAXPRINTERRS && errno == EIO) { 32279111Sjoerg if (ioctl(fd, FD_GSTAT, fdcs + errs) == 32379111Sjoerg -1) 32487992Sjoerg errx(EX_IOERR, 32579111Sjoerg "floppy IO error, but no FDC status"); 32679111Sjoerg errs++; 32779111Sjoerg } 32879111Sjoerg } 3291022Sache if(!quiet && !((track + 1) % tracks_per_dot)) { 3301022Sache if (!verify_only) 3311022Sache putchar('\b'); 3321022Sache if (error) { 3331022Sache putchar('E'); 3341022Sache error = 0; 3351022Sache } 3361022Sache else 3371022Sache putchar('V'); 3381022Sache fflush(stdout); 3391022Sache } 3401022Sache } 3411022Sache } 3421022Sache if(!quiet) 3431022Sache printf(" done.\n"); 3441022Sache 34579111Sjoerg if (!quiet && errs) { 34679111Sjoerg fflush(stdout); 34779111Sjoerg fprintf(stderr, "Errors encountered:\nCyl Head Sect Error\n"); 34879111Sjoerg for (i = 0; i < errs && i < MAXPRINTERRS; i++) { 34979111Sjoerg fprintf(stderr, " %2d %2d %2d ", 35079111Sjoerg fdcs[i].status[3], fdcs[i].status[4], 35179111Sjoerg fdcs[i].status[5]); 35279111Sjoerg printstatus(fdcs + i, 1); 35379111Sjoerg putc('\n', stderr); 35479111Sjoerg } 35579111Sjoerg if (errs >= MAXPRINTERRS) 35679111Sjoerg fprintf(stderr, "(Further errors not printed.)\n"); 35779111Sjoerg } 35879111Sjoerg 35979111Sjoerg return errs != 0; 3601022Sache} 361