diff options
author | Jaromir Capik | 2014-07-28 20:47:09 +0200 |
---|---|---|
committer | Karel Zak | 2014-07-29 13:44:04 +0200 |
commit | e0402441a143533d33d3c450471b2cd655407d77 (patch) | |
tree | 620657db417fb29b209584eb0cb7d499a03a6750 | |
parent | docs: update TODO (diff) | |
download | kernel-qcow2-util-linux-e0402441a143533d33d3c450471b2cd655407d77.tar.gz kernel-qcow2-util-linux-e0402441a143533d33d3c450471b2cd655407d77.tar.xz kernel-qcow2-util-linux-e0402441a143533d33d3c450471b2cd655407d77.zip |
fdformat: Add new switches -f/--from, -t/--to, -r/--repair
This commit introduces a support for user configurable
from/to track and a basic repair mode for broken floppies.
It also fixes a recently introduced bug that causes
a line breakage when printing the track number.
Signed-off-by: Karel Zak <kzak@redhat.com>
-rw-r--r-- | disk-utils/Makemodule.am | 1 | ||||
-rw-r--r-- | disk-utils/fdformat.8 | 11 | ||||
-rw-r--r-- | disk-utils/fdformat.c | 210 |
3 files changed, 157 insertions, 65 deletions
diff --git a/disk-utils/Makemodule.am b/disk-utils/Makemodule.am index c6183f5ca..995e08552 100644 --- a/disk-utils/Makemodule.am +++ b/disk-utils/Makemodule.am @@ -110,6 +110,7 @@ if BUILD_FDFORMAT usrsbin_exec_PROGRAMS += fdformat dist_man_MANS += disk-utils/fdformat.8 fdformat_SOURCES = disk-utils/fdformat.c +fdformat_LDADD = $(LDADD) libcommon.la endif if BUILD_BLOCKDEV diff --git a/disk-utils/fdformat.8 b/disk-utils/fdformat.8 index df4153f23..797f50f5c 100644 --- a/disk-utils/fdformat.8 +++ b/disk-utils/fdformat.8 @@ -1,6 +1,6 @@ .\" Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu) .\" May be distributed under the GNU General Public License -.TH FDFORMAT 8 "July 2011" "util-linux" "System Administration" +.TH FDFORMAT 8 "July 2014" "util-linux" "System Administration" .SH NAME fdformat \- low-level format a floppy disk .SH SYNOPSIS @@ -45,6 +45,15 @@ autodetected earlier. In this case, use to load the disk parameters. .SH OPTIONS .TP +\fB\-f\fR, \fB\-\-from\fR \fIN\fR +Start at the track \fIN\fR (default is 0). +.TP +\fB\-t\fR, \fB\-\-to\fR \fIN\fR +Stop at the track \fIN\fR (default is 0). +.TP +\fB\-r\fR, \fB\-\-repair\fR \fIN\fR +Try to repair tracks failed during the verification (max \fIN\fR retries). +.TP \fB\-n\fR, \fB\-\-no-verify\fR Skip the verification that is normally performed after the formatting. .TP diff --git a/disk-utils/fdformat.c b/disk-utils/fdformat.c index e6ae8e431..dc98de522 100644 --- a/disk-utils/fdformat.c +++ b/disk-utils/fdformat.c @@ -12,82 +12,129 @@ #include <unistd.h> #include "c.h" +#include "strutils.h" #include "closestream.h" #include "nls.h" #include "xalloc.h" +#define SECTOR_SIZE 512 + struct floppy_struct param; -#define SECTOR_SIZE 512 -static void format_disk(int ctrl) +static void format_begin(int ctrl) { - struct format_descr descr; - unsigned int track; + 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, (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); - if (ioctl(ctrl, FDFMTBEG, NULL) < 0) - err(EXIT_FAILURE, "ioctl: FDFMTBEG"); - for (track = 0; track < param.track; track++) { - descr.track = track; - descr.head = 0; - if (ioctl(ctrl, FDFMTTRK, (long) &descr) < 0) - err(EXIT_FAILURE, "ioctl: FDFMTTRK"); - - printf("%3ud\b\b\b", track); - fflush(stdout); - if (param.head == 2) { - descr.head = 1; - if (ioctl(ctrl, FDFMTTRK, (long)&descr) < 0) - err(EXIT_FAILURE, "ioctl: FDFMTTRK"); + + 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); } } - if (ioctl(ctrl, FDFMTEND, NULL) < 0) - err(EXIT_FAILURE, "ioctl: FDFMTEND"); + + format_end(ctrl); + printf(_("done\n")); } -static void verify_disk(char *name) +static void verify_disk(int ctrl, unsigned int track_from, unsigned int track_to, unsigned int repair) { unsigned char *data; - unsigned int cyl; - int fd, cyl_size, count; + struct format_descr current; + int track_size, count; + unsigned int retries_left; - cyl_size = param.sect * param.head * 512; - data = xmalloc(cyl_size); + track_size = param.sect * SECTOR_SIZE; + data = xmalloc(track_size); printf(_("Verifying ... ")); fflush(stdout); - if ((fd = open(name, O_RDONLY)) < 0) - err(EXIT_FAILURE, _("cannot open %s"), name); - for (cyl = 0; cyl < param.track; cyl++) { - int read_bytes; - - printf("%u3d\b\b\b", cyl); - fflush(stdout); - read_bytes = read(fd, data, cyl_size); - if (read_bytes != cyl_size) { - if (read_bytes < 0) - perror(_("Read: ")); - fprintf(stderr, - _("Problem reading cylinder %d," - " expected %d, read %d\n"), - cyl, cyl_size, read_bytes); - free(data); - exit(EXIT_FAILURE); - } - for (count = 0; count < cyl_size; count++) - if (data[count] != FD_FILL_BYTE) { - printf(_("bad data in cyl %d\n" - "Continuing ... "), cyl); - 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")); - if (close(fd) < 0) - err(EXIT_FAILURE, "close"); } static void __attribute__ ((__noreturn__)) usage(FILE * out) @@ -96,9 +143,13 @@ static void __attribute__ ((__noreturn__)) usage(FILE * out) program_invocation_short_name); fprintf(out, _("\nOptions:\n" - " -n, --no-verify disable the verification after the format\n" - " -V, --version output version information and exit\n" - " -h, --help display this help and exit\n\n")); + " -f, --from <N> start at the track N (default 0)\n" + " -t, --to <N> stop at the track N\n" + " -r, --repair <N> try to repair tracks failed during\n" + " the verification (max N retries)\n" + " -n, --no-verify disable the verification after the format\n" + " -V, --version output version information and exit\n" + " -h, --help display this help and exit\n\n")); exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); } @@ -108,22 +159,40 @@ 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); atexit(close_stdout); - while ((ch = getopt_long(argc, argv, "nVh", longopts, NULL)) != -1) + 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; @@ -149,20 +218,33 @@ int main(int argc, char **argv) if (access(argv[0], W_OK) < 0) err(EXIT_FAILURE, _("cannot access file %s"), argv[0]); - ctrl = open(argv[0], O_WRONLY); + ctrl = open(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")); + 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); - format_disk(ctrl); - if (close_fd(ctrl) != 0) - err(EXIT_FAILURE, _("write failed")); + (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(argv[0]); + verify_disk(ctrl, track_from, track_to, repair); + + if (close_fd(ctrl) != 0) + err(EXIT_FAILURE, _("close failed")); + return EXIT_SUCCESS; } |