diff options
Diffstat (limited to 'disk-utils/fdformat.c')
-rw-r--r-- | disk-utils/fdformat.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/disk-utils/fdformat.c b/disk-utils/fdformat.c new file mode 100644 index 0000000..38849eb --- /dev/null +++ b/disk-utils/fdformat.c @@ -0,0 +1,256 @@ +/* + * fdformat.c - Low-level formats a floppy disk - Werner Almesberger + */ +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <linux/fd.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "c.h" +#include "blkdev.h" +#include "strutils.h" +#include "closestream.h" +#include "nls.h" +#include "xalloc.h" + +#define SECTOR_SIZE 512 + +static struct floppy_struct param; + + +static void format_begin(int ctrl) +{ + if (ioctl(ctrl, FDFMTBEG, NULL) < 0) + err(EXIT_FAILURE, "ioctl: FDFMTBEG"); +} + +static void format_end(int ctrl) +{ + if (ioctl(ctrl, FDFMTEND, NULL) < 0) + err(EXIT_FAILURE, "ioctl: FDFMTEND"); +} + +static void format_track_head(int ctrl, struct format_descr *descr) +{ + if (ioctl(ctrl, FDFMTTRK, (long) descr) < 0) + err(EXIT_FAILURE, "ioctl: FDFMTTRK"); +} + +static void seek_track_head(int ctrl, struct format_descr *descr) +{ + lseek(ctrl, ((off_t) descr->track * param.head + descr->head) + * param.sect * SECTOR_SIZE, SEEK_SET); +} + +static void format_disk(int ctrl, unsigned int track_from, unsigned int track_to) +{ + struct format_descr current; + + printf(_("Formatting ... ")); + fflush(stdout); + + format_begin(ctrl); + + for (current.track = track_from; current.track <= track_to; current.track++) { + for (current.head = 0; current.head < param.head; current.head++) { + printf("%3u/%u\b\b\b\b\b", current.track, current.head); + fflush(stdout); + format_track_head(ctrl, ¤t); + } + } + + format_end(ctrl); + + printf(" \b\b\b\b\b%s", _("done\n")); +} + +static void verify_disk(int ctrl, unsigned int track_from, unsigned int track_to, unsigned int repair) +{ + unsigned char *data; + struct format_descr current; + int track_size, count; + unsigned int retries_left; + + track_size = param.sect * SECTOR_SIZE; + data = xmalloc(track_size); + printf(_("Verifying ... ")); + fflush(stdout); + + current.track = track_from; + current.head = 0; + seek_track_head (ctrl, ¤t); + + for (current.track = track_from; current.track <= track_to; current.track++) { + for (current.head = 0; current.head < param.head; current.head++) { + int read_bytes; + + printf("%3u\b\b\b", current.track); + fflush(stdout); + + retries_left = repair; + do { + read_bytes = read(ctrl, data, track_size); + if (read_bytes != track_size) { + if (retries_left) { + format_begin(ctrl); + format_track_head(ctrl, ¤t); + format_end(ctrl); + seek_track_head (ctrl, ¤t); + retries_left--; + if (retries_left) + continue; + } + if (read_bytes < 0) + perror(_("Read: ")); + fprintf(stderr, + _("Problem reading track/head %u/%u," + " expected %d, read %d\n"), + current.track, current.head, track_size, read_bytes); + free(data); + exit(EXIT_FAILURE); + } + for (count = 0; count < track_size; count++) + if (data[count] != FD_FILL_BYTE) { + if (retries_left) { + format_begin(ctrl); + format_track_head(ctrl, ¤t); + format_end(ctrl); + seek_track_head (ctrl, ¤t); + retries_left--; + if (retries_left) + continue; + } + printf(_("bad data in track/head %u/%u\n" + "Continuing ... "), current.track, current.head); + fflush(stdout); + break; + } + break; + } while (retries_left); + } + } + + free(data); + printf(_("done\n")); +} + +static void __attribute__((__noreturn__)) usage(void) +{ + FILE *out = stdout; + fputs(USAGE_HEADER, out); + fprintf(out, _(" %s [options] <device>\n"), + program_invocation_short_name); + + fputs(USAGE_SEPARATOR, out); + fputs(_("Do a low-level formatting of a floppy disk.\n"), out); + + fputs(USAGE_OPTIONS, out); + fputs(_(" -f, --from <N> start at the track N (default 0)\n"), out); + fputs(_(" -t, --to <N> stop at the track N\n"), out); + fputs(_(" -r, --repair <N> try to repair tracks failed during\n" + " the verification (max N retries)\n"), out); + fputs(_(" -n, --no-verify disable the verification after the format\n"), out); + + fputs(USAGE_SEPARATOR, out); + printf(USAGE_HELP_OPTIONS(19)); + printf(USAGE_MAN_TAIL("fdformat(8)")); + + exit(EXIT_SUCCESS); +} + +int main(int argc, char **argv) +{ + int ch; + int ctrl; + int verify = 1; + unsigned int repair = 0; + unsigned int track_from = 0; + unsigned int track_to = 0; + int has_user_defined_track_to = 0; + struct stat st; + + static const struct option longopts[] = { + {"from", required_argument, NULL, 'f'}, + {"to", required_argument, NULL, 't'}, + {"repair", required_argument, NULL, 'r'}, + {"no-verify", no_argument, NULL, 'n'}, + {"version", no_argument, NULL, 'V'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + close_stdout_atexit(); + + while ((ch = getopt_long(argc, argv, "f:t:r:nVh", longopts, NULL)) != -1) + switch (ch) { + case 'f': + track_from = strtou32_or_err(optarg, _("invalid argument - from")); + break; + case 't': + has_user_defined_track_to = 1; + track_to = strtou32_or_err(optarg, _("invalid argument - to")); + break; + case 'r': + repair = strtou32_or_err(optarg, _("invalid argument - repair")); + break; + case 'n': + verify = 0; + break; + case 'V': + print_version(EXIT_SUCCESS); + case 'h': + usage(); + default: + errtryhelp(EXIT_FAILURE); + } + + argc -= optind; + argv += optind; + + if (argc < 1) { + warnx(_("no device specified")); + errtryhelp(EXIT_FAILURE); + } + if (stat(argv[0], &st) < 0) + err(EXIT_FAILURE, _("stat of %s failed"), argv[0]); + if (!S_ISBLK(st.st_mode)) + /* do not test major - perhaps this was an USB floppy */ + errx(EXIT_FAILURE, _("%s: not a block device"), argv[0]); + ctrl = open_blkdev_or_file(&st, argv[0], O_RDWR); + if (ctrl < 0) + err(EXIT_FAILURE, _("cannot open %s"), argv[0]); + if (ioctl(ctrl, FDGETPRM, (long) ¶m) < 0) + err(EXIT_FAILURE, _("could not determine current format type")); + + printf(_("%s-sided, %d tracks, %d sec/track. Total capacity %d kB.\n"), + (param.head == 2) ? _("Double") : _("Single"), + param.track, param.sect, param.size >> 1); + + if (!has_user_defined_track_to) + track_to = param.track - 1; + + if (track_from >= param.track) + err(EXIT_FAILURE, _("user defined start track exceeds the medium specific maximum")); + if (track_to >= param.track) + err(EXIT_FAILURE, _("user defined end track exceeds the medium specific maximum")); + if (track_from > track_to) + err(EXIT_FAILURE, _("user defined start track exceeds the user defined end track")); + + format_disk(ctrl, track_from, track_to); + + if (verify) + verify_disk(ctrl, track_from, track_to, repair); + + if (close_fd(ctrl) != 0) + err(EXIT_FAILURE, _("close failed")); + + return EXIT_SUCCESS; +} |