fdread.c revision 76589
1/* 2 * Copyright (c) 2001 Joerg Wunsch 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD: cvs2svn/branches/JOERG/usr.sbin/fdread/fdread.c 76589 2001-05-14 20:22:49Z joerg $ 27 */ 28 29#include <sys/types.h> 30#include <sys/stat.h> 31 32#include <machine/ioctl_fd.h> 33 34#include <err.h> 35#include <errno.h> 36#include <fcntl.h> 37#include <paths.h> 38#include <stdio.h> 39#include <stdlib.h> 40#include <string.h> 41#include <sysexits.h> 42#include <unistd.h> 43 44/* XXX -- header file should probably be installed somewhere */ 45#include "/sys/isa/ic/nec765.h" 46 47int quiet, recover; 48unsigned char fillbyte = 0xf0; /* "foo" */ 49 50int doread(int fd, FILE *of, const char *devname); 51void printstatus(struct fdc_status *fdcsp); 52void usage(void); 53 54void 55usage(void) 56{ 57 58 errx(EX_USAGE, 59 "usage: fdread [-qr] [-d device] [-f fillbyte] [-o file]"); 60} 61 62 63int 64main(int argc, char **argv) 65{ 66 int c, errs = 0; 67 const char *fname = 0, *devname = "/dev/fd0"; 68 char *cp; 69 FILE *of = stdout; 70 int fd; 71 unsigned long ul; 72 73 while ((c = getopt(argc, argv, "d:f:o:qr")) != -1) 74 switch (c) { 75 case 'd': 76 devname = optarg; 77 break; 78 79 case 'f': 80 ul = strtoul(optarg, &cp, 0); 81 if (*cp != '\0') { 82 fprintf(stderr, 83 "Bad argument %s to -f option; must be numeric\n", 84 optarg); 85 usage(); 86 } 87 if (ul > 0xff) 88 warnx( 89 "Warning: fillbyte %#lx too large, truncating\n", 90 ul); 91 fillbyte = ul & 0xff; 92 break; 93 94 case 'o': 95 fname = optarg; 96 break; 97 98 case 'q': 99 quiet++; 100 break; 101 102 case 'r': 103 recover++; 104 break; 105 106 default: 107 errs++; 108 } 109 argc -= optind; 110 argv += optind; 111 112 if (argc != 0 || errs) 113 usage(); 114 115 if (fname) { 116 if ((of = fopen(fname, "w")) == NULL) 117 err(EX_OSERR, "cannot create output file %s", fname); 118 } 119 120 if ((fd = open(devname, O_RDONLY)) == -1) 121 err(EX_OSERR, "cannot open device %s", devname); 122 123 return (doread(fd, of, devname)); 124} 125 126int 127doread(int fd, FILE *of, const char *devname) 128{ 129 char *trackbuf; 130 int rv, fdopts, recoverable, nerrs = 0; 131 unsigned int nbytes, tracksize, mediasize, secsize, n; 132 struct fdc_status fdcs; 133 struct fd_type fdt; 134 135 if (ioctl(fd, FD_GTYPE, &fdt) == -1) 136 err(EX_OSERR, "ioctl(FD_GTYPE) failed -- not a floppy?"); 137 fdopts = FDOPT_NOERRLOG; 138 if (ioctl(fd, FD_SOPTS, &fdopts) == -1) 139 err(EX_OSERR, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)"); 140 141 secsize = 128 << fdt.secsize; 142 tracksize = fdt.sectrac * secsize; 143 mediasize = tracksize * fdt.tracks * fdt.heads; 144 if ((trackbuf = malloc(tracksize)) == 0) 145 errx(EX_TEMPFAIL, "out of memory"); 146 147 if (!quiet) 148 fprintf(stderr, "Reading %d * %d * %d * %d medium at %s\n", 149 fdt.tracks, fdt.heads, fdt.sectrac, secsize, devname); 150 151 for (nbytes = 0; nbytes < mediasize;) { 152 if (lseek(fd, nbytes, SEEK_SET) != nbytes) 153 err(EX_OSERR, "cannot lseek()"); 154 rv = read(fd, trackbuf, tracksize); 155 if (rv == 0) { 156 /* EOF? */ 157 warnx("premature EOF after %u bytes", nbytes); 158 return (EX_OK); 159 } 160 if (rv == tracksize) { 161 nbytes += rv; 162 if (!quiet) 163 fprintf(stderr, "%5d KB\r", nbytes / 1024); 164 fwrite(trackbuf, sizeof(unsigned char), rv, of); 165 fflush(of); 166 continue; 167 } 168 if (rv < tracksize) { 169 /* should not happen */ 170 nbytes += rv; 171 if (!quiet) 172 fprintf(stderr, "\nshort after %5d KB\r", 173 nbytes / 1024); 174 fwrite(trackbuf, sizeof(unsigned char), rv, of); 175 fflush(of); 176 continue; 177 } 178 if (rv == -1) { 179 /* fall back reading one sector at a time */ 180 for (n = 0; n < tracksize; n += secsize) { 181 if (lseek(fd, nbytes, SEEK_SET) != nbytes) 182 err(EX_OSERR, "cannot lseek()"); 183 rv = read(fd, trackbuf, secsize); 184 if (rv == secsize) { 185 nbytes += rv; 186 if (!quiet) 187 fprintf(stderr, "%5d KB\r", 188 nbytes / 1024); 189 fwrite(trackbuf, sizeof(unsigned char), 190 rv, of); 191 fflush(of); 192 continue; 193 } 194 if (rv == -1) { 195 if (errno != EIO) { 196 if (!quiet) 197 putc('\n', stderr); 198 perror("non-IO error"); 199 return (EX_OSERR); 200 } 201 if (ioctl(fd, FD_GSTAT, &fdcs) == -1) 202 errx(EX_IOERR, 203 "floppy IO error, but no FDC status"); 204 nerrs++; 205 recoverable = fdcs.status[2] & 206 NE7_ST2_DD; 207 if (!quiet) { 208 printstatus(&fdcs); 209 fputs(" (", stderr); 210 if (!recoverable) 211 fputs("not ", stderr); 212 fputs("recoverable)", stderr); 213 } 214 if (!recover) { 215 if (!quiet) 216 putc('\n', stderr); 217 return (EX_IOERR); 218 } 219 memset(trackbuf, fillbyte, secsize); 220 if (recoverable) { 221 fdopts |= FDOPT_NOERROR; 222 if (ioctl(fd, FD_SOPTS, 223 &fdopts) == -1) 224 err(EX_OSERR, 225 "ioctl(fd, FD_SOPTS, FDOPT_NOERROR)"); 226 rv = read(fd, trackbuf, 227 secsize); 228 if (rv != secsize) 229 err(EX_IOERR, 230 "read() with FDOPT_NOERROR still fails"); 231 fdopts &= ~FDOPT_NOERROR; 232 (void)ioctl(fd, FD_SOPTS, 233 &fdopts); 234 } 235 if (!quiet) { 236 if (recoverable) 237 fprintf(stderr, 238 ": recovered"); 239 else 240 fprintf(stderr, 241 ": dummy"); 242 fprintf(stderr, 243 " data @ %#x ... %#x\n", 244 nbytes, 245 nbytes + secsize - 1); 246 } 247 nbytes += secsize; 248 fwrite(trackbuf, sizeof(unsigned char), 249 secsize, of); 250 fflush(of); 251 continue; 252 } 253 errx(EX_OSERR, "unexpected read() result: %d", 254 rv); 255 } 256 } 257 } 258 if (!quiet) { 259 putc('\n', stderr); 260 if (nerrs) 261 fprintf(stderr, "%d error%s\n", 262 nerrs, nerrs > 1? "s": ""); 263 } 264 265 return (nerrs? EX_IOERR: EX_OK); 266} 267 268void 269printstatus(struct fdc_status *fdcsp) 270{ 271 char msgbuf[100]; 272 273 fprintf(stderr, 274 "\nFDC status ST0=%#x ST1=%#x ST2=%#x C=%u H=%u R=%u N=%u:\n", 275 fdcsp->status[0] & 0xff, 276 fdcsp->status[1] & 0xff, 277 fdcsp->status[2] & 0xff, 278 fdcsp->status[3] & 0xff, 279 fdcsp->status[4] & 0xff, 280 fdcsp->status[5] & 0xff, 281 fdcsp->status[6] & 0xff); 282 283 if ((fdcsp->status[0] & NE7_ST0_IC_RC) != NE7_ST0_IC_AT) { 284 sprintf(msgbuf, "unexcpted interrupt code %#x", 285 fdcsp->status[0] & NE7_ST0_IC_RC); 286 } else { 287 strcpy(msgbuf, "unexpected error code in ST1/ST2"); 288 289 if (fdcsp->status[1] & NE7_ST1_EN) 290 strcpy(msgbuf, "end of cylinder (wrong format)"); 291 else if (fdcsp->status[1] & NE7_ST1_DE) { 292 if (fdcsp->status[2] & NE7_ST2_DD) 293 strcpy(msgbuf, "CRC error in data field"); 294 else 295 strcpy(msgbuf, "CRC error in ID field"); 296 } else if (fdcsp->status[1] & NE7_ST1_MA) { 297 if (fdcsp->status[2] & NE7_ST2_MD) 298 strcpy(msgbuf, "no address mark in data field"); 299 else 300 strcpy(msgbuf, "no address mark in ID field"); 301 } else if (fdcsp->status[2] & NE7_ST2_WC) 302 strcpy(msgbuf, "wrong cylinder (format mismatch)"); 303 else if (fdcsp->status[1] & NE7_ST1_ND) 304 strcpy(msgbuf, "no data (sector not found)"); 305 } 306 fputs(msgbuf, stderr); 307} 308