2 * fdformat.c - Low-level formats a floppy disk - Werner Almesberger
10 #include <sys/ioctl.h>
17 #include "closestream.h"
21 #define SECTOR_SIZE 512
23 static struct floppy_struct param
;
26 static void format_begin(int ctrl
)
28 if (ioctl(ctrl
, FDFMTBEG
, NULL
) < 0)
29 err(EXIT_FAILURE
, "ioctl: FDFMTBEG");
32 static void format_end(int ctrl
)
34 if (ioctl(ctrl
, FDFMTEND
, NULL
) < 0)
35 err(EXIT_FAILURE
, "ioctl: FDFMTEND");
38 static void format_track_head(int ctrl
, struct format_descr
*descr
)
40 if (ioctl(ctrl
, FDFMTTRK
, (long) descr
) < 0)
41 err(EXIT_FAILURE
, "ioctl: FDFMTTRK");
44 static void seek_track_head(int ctrl
, struct format_descr
*descr
)
46 lseek(ctrl
, (descr
->track
* param
.head
+ descr
->head
) * param
.sect
* SECTOR_SIZE
, SEEK_SET
);
49 static void format_disk(int ctrl
, unsigned int track_from
, unsigned int track_to
)
51 struct format_descr current
;
53 printf(_("Formatting ... "));
58 for (current
.track
= track_from
; current
.track
<= track_to
; current
.track
++) {
59 for (current
.head
= 0; current
.head
< param
.head
; current
.head
++) {
60 printf("%3u/%u\b\b\b\b\b", current
.track
, current
.head
);
62 format_track_head(ctrl
, ¤t
);
68 printf(" \b\b\b\b\b%s", _("done\n"));
71 static void verify_disk(int ctrl
, unsigned int track_from
, unsigned int track_to
, unsigned int repair
)
74 struct format_descr current
;
75 int track_size
, count
;
76 unsigned int retries_left
;
78 track_size
= param
.sect
* SECTOR_SIZE
;
79 data
= xmalloc(track_size
);
80 printf(_("Verifying ... "));
83 current
.track
= track_from
;
85 seek_track_head (ctrl
, ¤t
);
87 for (current
.track
= track_from
; current
.track
<= track_to
; current
.track
++) {
88 for (current
.head
= 0; current
.head
< param
.head
; current
.head
++) {
91 printf("%3u\b\b\b", current
.track
);
94 retries_left
= repair
;
96 read_bytes
= read(ctrl
, data
, track_size
);
97 if (read_bytes
!= track_size
) {
100 format_track_head(ctrl
, ¤t
);
102 seek_track_head (ctrl
, ¤t
);
110 _("Problem reading track/head %u/%u,"
111 " expected %d, read %d\n"),
112 current
.track
, current
.head
, track_size
, read_bytes
);
116 for (count
= 0; count
< track_size
; count
++)
117 if (data
[count
] != FD_FILL_BYTE
) {
120 format_track_head(ctrl
, ¤t
);
122 seek_track_head (ctrl
, ¤t
);
127 printf(_("bad data in track/head %u/%u\n"
128 "Continuing ... "), current
.track
, current
.head
);
133 } while (retries_left
);
141 static void __attribute__((__noreturn__
)) usage(void)
144 fputs(USAGE_HEADER
, out
);
145 fprintf(out
, _(" %s [options] <device>\n"),
146 program_invocation_short_name
);
148 fputs(USAGE_SEPARATOR
, out
);
149 fputs(_("Do a low-level formatting of a floppy disk.\n"), out
);
151 fputs(USAGE_OPTIONS
, out
);
152 fputs(_(" -f, --from <N> start at the track N (default 0)\n"), out
);
153 fputs(_(" -t, --to <N> stop at the track N\n"), out
);
154 fputs(_(" -r, --repair <N> try to repair tracks failed during\n"
155 " the verification (max N retries)\n"), out
);
156 fputs(_(" -n, --no-verify disable the verification after the format\n"), out
);
158 fputs(USAGE_SEPARATOR
, out
);
159 printf(USAGE_HELP_OPTIONS(19));
160 printf(USAGE_MAN_TAIL("fdformat(8)"));
165 int main(int argc
, char **argv
)
170 unsigned int repair
= 0;
171 unsigned int track_from
= 0;
172 unsigned int track_to
= 0;
173 int has_user_defined_track_to
= 0;
176 static const struct option longopts
[] = {
177 {"from", required_argument
, NULL
, 'f'},
178 {"to", required_argument
, NULL
, 't'},
179 {"repair", required_argument
, NULL
, 'r'},
180 {"no-verify", no_argument
, NULL
, 'n'},
181 {"version", no_argument
, NULL
, 'V'},
182 {"help", no_argument
, NULL
, 'h'},
186 setlocale(LC_ALL
, "");
187 bindtextdomain(PACKAGE
, LOCALEDIR
);
189 close_stdout_atexit();
191 while ((ch
= getopt_long(argc
, argv
, "f:t:r:nVh", longopts
, NULL
)) != -1)
194 track_from
= strtou32_or_err(optarg
, _("invalid argument - from"));
197 has_user_defined_track_to
= 1;
198 track_to
= strtou32_or_err(optarg
, _("invalid argument - to"));
201 repair
= strtou32_or_err(optarg
, _("invalid argument - repair"));
207 print_version(EXIT_SUCCESS
);
211 errtryhelp(EXIT_FAILURE
);
218 warnx(_("no device specified"));
219 errtryhelp(EXIT_FAILURE
);
221 if (stat(argv
[0], &st
) < 0)
222 err(EXIT_FAILURE
, _("stat of %s failed"), argv
[0]);
223 if (!S_ISBLK(st
.st_mode
))
224 /* do not test major - perhaps this was an USB floppy */
225 errx(EXIT_FAILURE
, _("%s: not a block device"), argv
[0]);
226 ctrl
= open_blkdev_or_file(&st
, argv
[0], O_RDWR
);
228 err(EXIT_FAILURE
, _("cannot open %s"), argv
[0]);
229 if (ioctl(ctrl
, FDGETPRM
, (long) ¶m
) < 0)
230 err(EXIT_FAILURE
, _("could not determine current format type"));
232 printf(_("%s-sided, %d tracks, %d sec/track. Total capacity %d kB.\n"),
233 (param
.head
== 2) ? _("Double") : _("Single"),
234 param
.track
, param
.sect
, param
.size
>> 1);
236 if (!has_user_defined_track_to
)
237 track_to
= param
.track
- 1;
239 if (track_from
>= param
.track
)
240 err(EXIT_FAILURE
, _("user defined start track exceeds the medium specific maximum"));
241 if (track_to
>= param
.track
)
242 err(EXIT_FAILURE
, _("user defined end track exceeds the medium specific maximum"));
243 if (track_from
> track_to
)
244 err(EXIT_FAILURE
, _("user defined start track exceeds the user defined end track"));
246 format_disk(ctrl
, track_from
, track_to
);
249 verify_disk(ctrl
, track_from
, track_to
, repair
);
251 if (close_fd(ctrl
) != 0)
252 err(EXIT_FAILURE
, _("close failed"));