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