1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (C) 1992-1994,2001 by Joerg Wunsch, Dresden 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/types.h> 32 #include <sys/fdcio.h> 33 #include <sys/stat.h> 34 35 #include <ctype.h> 36 #include <err.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <paths.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <strings.h> 44 #include <sysexits.h> 45 #include <unistd.h> 46 47 #include "fdutil.h" 48 49 static void 50 format_track(int fd, int cyl, int secs, int head, int rate, 51 int gaplen, int secsize, int fill, int interleave, 52 int offset) 53 { 54 struct fd_formb f; 55 int i, j, il[FD_MAX_NSEC + 1]; 56 57 memset(il, 0, sizeof il); 58 for(j = 0, i = 1 + offset; i <= secs + offset; i++) { 59 while(il[(j % secs) + 1]) 60 j++; 61 il[(j % secs) + 1] = i; 62 j += interleave; 63 } 64 65 f.format_version = FD_FORMAT_VERSION; 66 f.head = head; 67 f.cyl = cyl; 68 f.transfer_rate = rate; 69 70 f.fd_formb_secshift = secsize; 71 f.fd_formb_nsecs = secs; 72 f.fd_formb_gaplen = gaplen; 73 f.fd_formb_fillbyte = fill; 74 for(i = 0; i < secs; i++) { 75 f.fd_formb_cylno(i) = cyl; 76 f.fd_formb_headno(i) = head; 77 f.fd_formb_secno(i) = il[i+1]; 78 f.fd_formb_secsize(i) = secsize; 79 } 80 (void)ioctl(fd, FD_FORM, (caddr_t)&f); 81 } 82 83 static int 84 verify_track(int fd, int track, int tracksize) 85 { 86 static char *buf; 87 static int bufsz; 88 int fdopts = -1, ofdopts, rv = 0; 89 90 if (ioctl(fd, FD_GOPTS, &fdopts) < 0) 91 warn("warning: ioctl(FD_GOPTS)"); 92 else { 93 ofdopts = fdopts; 94 fdopts |= FDOPT_NORETRY; 95 (void)ioctl(fd, FD_SOPTS, &fdopts); 96 } 97 98 if (bufsz < tracksize) 99 buf = realloc(buf, bufsz = tracksize); 100 if (buf == NULL) 101 errx(EX_UNAVAILABLE, "out of memory"); 102 if (lseek (fd, (long) track * tracksize, 0) < 0) 103 rv = -1; 104 /* try twice reading it, without using the normal retrier */ 105 else if (read (fd, buf, tracksize) != tracksize 106 && read (fd, buf, tracksize) != tracksize) 107 rv = -1; 108 if (fdopts != -1) 109 (void)ioctl(fd, FD_SOPTS, &ofdopts); 110 return (rv); 111 } 112 113 static void 114 usage (void) 115 { 116 errx(EX_USAGE, 117 "usage: fdformat [-F fill] [-f fmt] [-s fmtstr] [-nqvy] device"); 118 } 119 120 static int 121 yes (void) 122 { 123 char reply[256], *p; 124 125 reply[sizeof(reply) - 1] = 0; 126 for (;;) { 127 fflush(stdout); 128 if (!fgets (reply, sizeof(reply) - 1, stdin)) 129 return (0); 130 for (p=reply; *p==' ' || *p=='\t'; ++p) 131 continue; 132 if (*p=='y' || *p=='Y') 133 return (1); 134 if (*p=='n' || *p=='N' || *p=='\n' || *p=='\r') 135 return (0); 136 printf("Answer `yes' or `no': "); 137 } 138 } 139 140 int 141 main(int argc, char **argv) 142 { 143 enum fd_drivetype type; 144 struct fd_type fdt, newft, *fdtp; 145 struct stat sb; 146 #define MAXPRINTERRS 10 147 struct fdc_status fdcs[MAXPRINTERRS]; 148 int format, fill, quiet, verify, verify_only, confirm; 149 int fd, c, i, track, error, tracks_per_dot, bytes_per_track, errs; 150 int flags; 151 char *fmtstring, *device; 152 const char *name, *descr; 153 154 format = quiet = verify_only = confirm = 0; 155 verify = 1; 156 fill = 0xf6; 157 fmtstring = 0; 158 159 while((c = getopt(argc, argv, "F:f:nqs:vy")) != -1) 160 switch(c) { 161 case 'F': /* fill byte */ 162 if (getnum(optarg, &fill)) { 163 fprintf(stderr, 164 "Bad argument %s to -F option; must be numeric\n", 165 optarg); 166 usage(); 167 } 168 break; 169 170 case 'f': /* format in kilobytes */ 171 if (getnum(optarg, &format)) { 172 fprintf(stderr, 173 "Bad argument %s to -f option; must be numeric\n", 174 optarg); 175 usage(); 176 } 177 break; 178 179 case 'n': /* don't verify */ 180 verify = 0; 181 break; 182 183 case 'q': /* quiet */ 184 quiet = 1; 185 break; 186 187 case 's': /* format string with detailed options */ 188 fmtstring = optarg; 189 break; 190 191 case 'v': /* verify only */ 192 verify = 1; 193 verify_only = 1; 194 break; 195 196 case 'y': /* confirm */ 197 confirm = 1; 198 break; 199 200 default: 201 usage(); 202 } 203 204 if(optind != argc - 1) 205 usage(); 206 207 if (stat(argv[optind], &sb) == -1 && errno == ENOENT) { 208 /* try prepending _PATH_DEV */ 209 device = malloc(strlen(argv[optind]) + sizeof(_PATH_DEV) + 1); 210 if (device == NULL) 211 errx(EX_UNAVAILABLE, "out of memory"); 212 strcpy(device, _PATH_DEV); 213 strcat(device, argv[optind]); 214 if (stat(device, &sb) == -1) { 215 free(device); 216 device = argv[optind]; /* let it fail below */ 217 } 218 } else { 219 device = argv[optind]; 220 } 221 222 if ((fd = open(device, O_RDWR | O_NONBLOCK)) < 0) 223 err(EX_OSERR, "open(%s)", device); 224 225 /* 226 * Device initialization. 227 * 228 * First, get the device type descriptor. This tells us about 229 * the media geometry data we need to format a medium. It also 230 * lets us know quickly whether the device name actually points 231 * to a floppy disk drive. 232 * 233 * Then, obtain any drive options. We're mainly interested to 234 * see whether we're currently working on a device with media 235 * density autoselection (FDOPT_AUTOSEL). Then, we add the 236 * device option to tell the kernel not to log media errors, 237 * since we can handle them ourselves. If the device does 238 * media density autoselection, we then need to set the device 239 * type appropriately, since by opening with O_NONBLOCK we 240 * told the driver to bypass media autoselection (otherwise we 241 * wouldn't stand a chance to format an unformatted or damaged 242 * medium). We do not attempt to set the media type on any 243 * other devices since this is a privileged operation. For the 244 * same reason, specifying -f and -s options is only possible 245 * for autoselecting devices. 246 * 247 * Finally, we are ready to turn off O_NONBLOCK, and start to 248 * actually format something. 249 */ 250 if(ioctl(fd, FD_GTYPE, &fdt) < 0) 251 errx(EX_OSERR, "not a floppy disk: %s", device); 252 if (ioctl(fd, FD_GDTYPE, &type) == -1) 253 err(EX_OSERR, "ioctl(FD_GDTYPE)"); 254 if (format) { 255 getname(type, &name, &descr); 256 fdtp = get_fmt(format, type); 257 if (fdtp == NULL) 258 errx(EX_USAGE, 259 "unknown format %d KB for drive type %s", 260 format, name); 261 fdt = *fdtp; 262 } 263 if (fmtstring) { 264 parse_fmt(fmtstring, type, fdt, &newft); 265 fdt = newft; 266 } 267 if (ioctl(fd, FD_STYPE, &fdt) < 0) 268 err(EX_OSERR, "ioctl(FD_STYPE)"); 269 if ((flags = fcntl(fd, F_GETFL, 0)) == -1) 270 err(EX_OSERR, "fcntl(F_GETFL)"); 271 flags &= ~O_NONBLOCK; 272 if (fcntl(fd, F_SETFL, flags) == -1) 273 err(EX_OSERR, "fcntl(F_SETFL)"); 274 275 bytes_per_track = fdt.sectrac * (128 << fdt.secsize); 276 277 /* XXX 20/40 = 0.5 */ 278 tracks_per_dot = (fdt.tracks * fdt.heads + 20) / 40; 279 280 if (verify_only) { 281 if(!quiet) 282 printf("Verify %dK floppy `%s'.\n", 283 fdt.tracks * fdt.heads * bytes_per_track / 1024, 284 device); 285 } 286 else if(!quiet && !confirm) { 287 printf("Format %dK floppy `%s'? (y/n): ", 288 fdt.tracks * fdt.heads * bytes_per_track / 1024, 289 device); 290 if(!yes()) { 291 printf("Not confirmed.\n"); 292 return (EX_UNAVAILABLE); 293 } 294 } 295 296 /* 297 * Formatting. 298 */ 299 if(!quiet) { 300 printf("Processing "); 301 for (i = 0; i < (fdt.tracks * fdt.heads) / tracks_per_dot; i++) 302 putchar('-'); 303 printf("\rProcessing "); 304 fflush(stdout); 305 } 306 307 error = errs = 0; 308 309 for (track = 0; track < fdt.tracks * fdt.heads; track++) { 310 if (!verify_only) { 311 format_track(fd, track / fdt.heads, fdt.sectrac, 312 track % fdt.heads, fdt.trans, fdt.f_gap, 313 fdt.secsize, fill, fdt.f_inter, 314 track % fdt.heads? fdt.offset_side2: 0); 315 if(!quiet && !((track + 1) % tracks_per_dot)) { 316 putchar('F'); 317 fflush(stdout); 318 } 319 } 320 if (verify) { 321 if (verify_track(fd, track, bytes_per_track) < 0) { 322 error = 1; 323 if (errs < MAXPRINTERRS && errno == EIO) { 324 if (ioctl(fd, FD_GSTAT, fdcs + errs) == 325 -1) 326 errx(EX_IOERR, 327 "floppy IO error, but no FDC status"); 328 errs++; 329 } 330 } 331 if(!quiet && !((track + 1) % tracks_per_dot)) { 332 if (!verify_only) 333 putchar('\b'); 334 if (error) { 335 putchar('E'); 336 error = 0; 337 } 338 else 339 putchar('V'); 340 fflush(stdout); 341 } 342 } 343 } 344 if(!quiet) 345 printf(" done.\n"); 346 347 if (!quiet && errs) { 348 fflush(stdout); 349 fprintf(stderr, "Errors encountered:\nCyl Head Sect Error\n"); 350 for (i = 0; i < errs && i < MAXPRINTERRS; i++) { 351 fprintf(stderr, " %2d %2d %2d ", 352 fdcs[i].status[3], fdcs[i].status[4], 353 fdcs[i].status[5]); 354 printstatus(fdcs + i, 1); 355 putc('\n', stderr); 356 } 357 if (errs >= MAXPRINTERRS) 358 fprintf(stderr, "(Further errors not printed.)\n"); 359 } 360 361 return errs != 0; 362 } 363