1 /* $NetBSD: fdformat.c,v 1.14 2007/12/15 19:44:50 perry Exp $ */ 2 3 /*- 4 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by John Kohl. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * fdformat: format a floppy diskette, using interface provided in 41 * <sys/fdio.h> 42 */ 43 #include <sys/cdefs.h> 44 45 #ifndef lint 46 __RCSID("$NetBSD: fdformat.c,v 1.14 2007/12/15 19:44:50 perry Exp $"); 47 #endif 48 49 #include <sys/types.h> 50 #include <sys/fdio.h> 51 #include <sys/ioctl.h> 52 53 #include <err.h> 54 #include <errno.h> 55 #include <fcntl.h> 56 #include <limits.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <unistd.h> 60 #include "pathnames.h" 61 62 static const char *fdb_array[2] = {_PATH_FLOPPYTAB, 0}; 63 64 #define MASK_NBPS 0x0001 65 #define MASK_NCYL 0x0002 66 #define MASK_NSPT 0x0004 67 #define MASK_NTRK 0x0008 68 #define MASK_STEPSPERCYL 0x0010 69 #define MASK_GAPLEN 0x0020 70 #define MASK_FILLBYTE 0x0040 71 #define MASK_XFER_RATE 0x0080 72 #define MASK_INTERLEAVE 0x0100 73 74 #define ALLPARMS (MASK_NBPS|MASK_NCYL|MASK_NSPT|MASK_NTRK|MASK_STEPSPERCYL|MASK_GAPLEN|MASK_FILLBYTE|MASK_XFER_RATE|MASK_INTERLEAVE) 75 76 static int confirm(int); 77 static void usage(void) __dead; 78 static int verify_track(int, int, int, struct fdformat_parms *, char *); 79 80 int main(int, char **); 81 82 static int 83 confirm(int def) 84 { 85 int ch; 86 87 (void)printf(" Yes/no [%c]?", def ? 'y' : 'n'); 88 ch = getchar(); 89 switch (ch) { 90 case 'y': 91 case 'Y': 92 return 1; 93 case '\n': 94 return def; 95 case EOF: 96 case 'n': 97 case 'N': 98 default: 99 return 0; 100 } 101 } 102 103 static int 104 verify_track(int fd, int cyl, int trk, struct fdformat_parms *parms, char *buf) 105 { 106 size_t tracksize; 107 off_t offset; 108 109 tracksize = parms->nbps * parms->nspt; /* bytes per track */ 110 offset = tracksize * (cyl * parms->ntrk + trk); /* track offset */ 111 112 if (lseek(fd, offset, SEEK_SET) == (off_t) -1) { 113 (void)printf("- SEEK ERROR\n"); 114 return 1; 115 } 116 if (read(fd, buf, tracksize) != tracksize) { 117 (void)printf("- VERIFY ERROR\n"); 118 return 1; 119 } 120 return 0; 121 } 122 123 static void 124 usage(void) 125 { 126 (void)fprintf(stderr, 127 "Usage: %s [-f device] [-t type] [-n] [-B nbps] [-S nspt]\n" 128 "\t[-T ntrk] [-C ncyl] [-P stepspercyl] [-G gaplen]\n" 129 "\t[-F fillbyte] [-X xfer_rate] [-I interleave]\n", getprogname()); 130 exit(1); 131 } 132 133 #define numarg(which, maskn, op) \ 134 do { \ 135 tmplong = strtol(optarg, &tmpcharp, 0); \ 136 if (*tmpcharp != '\0' || tmplong op 0) \ 137 errx(1, \ 138 "Invalid numerical argument `%s' for " \ 139 # which, optarg); \ 140 if (errno == ERANGE && (tmplong == LONG_MIN || \ 141 tmplong == LONG_MAX)) \ 142 err(1, \ 143 "Bad numerical argument `%s' for " \ 144 # which, optarg); \ 145 parms.which = tmplong; \ 146 parmmask |= MASK_##maskn; \ 147 } while (/* CONSTCOND */0) 148 149 #define getparm(structname, maskname) \ 150 do { \ 151 if (cgetnum(fdbuf, # structname, &tmplong) == -1) \ 152 errx(1, "Parameter " # structname \ 153 " missing for type `%s'", optarg); \ 154 parms.structname = tmplong; \ 155 parmmask |= MASK_ ## maskname; \ 156 } while (/* CONSTCOND */0) 157 158 159 #define copyparm(which, mask) \ 160 if ((parmmask & MASK_##mask) == 0) \ 161 parms.which = fetchparms.which 162 163 int 164 main(int argc, char *argv[]) 165 { 166 char *fdbuf = NULL, *trackbuf = NULL; 167 int errcnt = 0; 168 int verify = 1; 169 int ch; 170 long tmplong; 171 int tmpint; 172 char *tmpcharp; 173 int parmmask = 0; 174 struct fdformat_parms parms, fetchparms; 175 struct fdformat_cmd cmd; 176 const char *filename = _PATH_FLOPPY_DEV; 177 int fd; 178 int trk, cyl; 179 180 while ((ch = getopt(argc, argv, "f:t:nB:C:S:T:P:G:F:X:I:")) != -1) 181 switch (ch) { 182 case 't': /* disk type */ 183 switch (cgetent(&fdbuf, fdb_array, optarg)) { 184 case 0: 185 break; 186 case 1: 187 case -3: 188 errx(1, "tc= loop or missing entry entry in " 189 _PATH_FLOPPYTAB " for type %s", optarg); 190 break; 191 case -1: 192 errx(1, "Unknown floppy disk type %s", optarg); 193 break; 194 default: 195 err(1, "Problem accessing " _PATH_FLOPPYTAB); 196 break; 197 } 198 199 getparm(nbps, NBPS); 200 getparm(ncyl, NCYL); 201 getparm(nspt, NSPT); 202 getparm(ntrk, NTRK); 203 getparm(stepspercyl, STEPSPERCYL); 204 getparm(gaplen, GAPLEN); 205 getparm(fillbyte, FILLBYTE); 206 getparm(xfer_rate, XFER_RATE); 207 getparm(interleave, INTERLEAVE); 208 break; 209 case 'f': /* device name */ 210 filename = optarg; 211 break; 212 case 'n': /* no verify */ 213 verify = 0; 214 break; 215 case 'B': 216 numarg(nbps, NBPS, <=); 217 break; 218 case 'C': 219 numarg(ncyl, NCYL, <=); 220 break; 221 case 'S': 222 numarg(nspt, NSPT, <=); 223 break; 224 case 'T': 225 numarg(ntrk, NTRK, <=); 226 break; 227 case 'P': 228 numarg(stepspercyl, STEPSPERCYL, <=); 229 break; 230 case 'G': 231 numarg(gaplen, GAPLEN, <=); 232 break; 233 case 'F': 234 numarg(fillbyte, FILLBYTE, <); 235 break; 236 case 'X': 237 numarg(xfer_rate, XFER_RATE, <=); 238 break; 239 case 'I': 240 numarg(interleave, INTERLEAVE, <=); 241 break; 242 case '?': 243 default: 244 usage(); 245 } 246 247 if (optind < argc) 248 usage(); 249 250 fd = open(filename, O_RDWR); 251 if (fd == -1) 252 err(1, "Cannot open %s", filename); 253 if (ioctl(fd, FDIOCGETFORMAT, &fetchparms) == -1) { 254 if (errno == ENOTTY) 255 err(1, "Device `%s' does not support floppy formatting", 256 filename); 257 else 258 err(1, "Cannot fetch current floppy" 259 " formatting parameters"); 260 } 261 262 copyparm(nbps, NBPS); 263 copyparm(ncyl, NCYL); 264 copyparm(nspt, NSPT); 265 copyparm(ntrk, NTRK); 266 copyparm(stepspercyl, STEPSPERCYL); 267 copyparm(gaplen, GAPLEN); 268 copyparm(fillbyte, FILLBYTE); 269 copyparm(xfer_rate, XFER_RATE); 270 copyparm(interleave, INTERLEAVE); 271 272 parms.fdformat_version = FDFORMAT_VERSION; 273 274 tmpint = FDOPT_NORETRY|FDOPT_SILENT; 275 if (ioctl(fd, FDIOCSETOPTS, &tmpint) == -1 || 276 ioctl(fd, FDIOCSETFORMAT, &parms) == -1) { 277 errx(1, "Cannot set requested formatting parameters:" 278 " %d cylinders, %d tracks, %d sectors of %d bytes", 279 parms.ncyl, parms.ntrk, parms.nspt, parms.nbps); 280 } 281 282 (void)printf("Ready to format %s with %d cylinders, %d tracks," 283 " %d sectors of %d bytes\n(%d KB)", 284 filename, parms.ncyl, parms.ntrk, parms.nspt, parms.nbps, 285 parms.ncyl * parms.ntrk * parms.nspt * parms.nbps / 1024); 286 if (!confirm(1)) 287 errx(1,"Formatting abandoned -- not confirmed."); 288 289 if (verify) { 290 trackbuf = malloc(parms.nbps * parms.nspt); 291 if (trackbuf == NULL) 292 warn("Cannot allocate verification buffer"); 293 } 294 295 cmd.formatcmd_version = FDFORMAT_VERSION; 296 for (cyl = 0; cyl < parms.ncyl; cyl++) { 297 cmd.cylinder = cyl; 298 for (trk = 0; trk < parms.ntrk; trk++) { 299 cmd.head = trk; 300 (void)printf("\rFormatting track %i / head %i ", cyl, trk); 301 (void)fflush(stdout); 302 if (ioctl(fd, FDIOCFORMAT_TRACK, &cmd) == 0) { 303 if (verify) 304 errcnt += verify_track(fd, cyl, trk, 305 &parms, trackbuf); 306 } else if (errno == EINVAL) { 307 (void)putchar('\n'); 308 errx(1, "Formatting botch at <%d,%d>", 309 cyl, trk); 310 } else if (errno == EIO) { 311 (void)printf("- IO ERROR\n"); 312 errcnt++; 313 } 314 } 315 } 316 (void)printf("\rFormatting %i tracks total complete.\n", 317 parms.ncyl * parms.ntrk); 318 if (errcnt) 319 errx(1, "%d track formatting error%s", 320 errcnt, errcnt == 1 ? "" : "s"); 321 return 0; 322 } 323