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
, ((off_t
) descr
->track
* param
.head
+ descr
->head
)
47 * param
.sect
* SECTOR_SIZE
, SEEK_SET
);
50 static void format_disk(int ctrl
, unsigned int track_from
, unsigned int track_to
)
52 struct format_descr current
;
54 printf(_("Formatting ... "));
59 for (current
.track
= track_from
; current
.track
<= track_to
; current
.track
++) {
60 for (current
.head
= 0; current
.head
< param
.head
; current
.head
++) {
61 printf("%3u/%u\b\b\b\b\b", current
.track
, current
.head
);
63 format_track_head(ctrl
, ¤t
);
69 printf(" \b\b\b\b\b%s", _("done\n"));
72 static void verify_disk(int ctrl
, unsigned int track_from
, unsigned int track_to
, unsigned int repair
)
75 struct format_descr current
;
76 int track_size
, count
;
77 unsigned int retries_left
;
79 track_size
= param
.sect
* SECTOR_SIZE
;
80 data
= xmalloc(track_size
);
81 printf(_("Verifying ... "));
84 current
.track
= track_from
;
86 seek_track_head (ctrl
, ¤t
);
88 for (current
.track
= track_from
; current
.track
<= track_to
; current
.track
++) {
89 for (current
.head
= 0; current
.head
< param
.head
; current
.head
++) {
92 printf("%3u\b\b\b", current
.track
);
95 retries_left
= repair
;
97 read_bytes
= read(ctrl
, data
, track_size
);
98 if (read_bytes
!= track_size
) {
101 format_track_head(ctrl
, ¤t
);
103 seek_track_head (ctrl
, ¤t
);
111 _("Problem reading track/head %u/%u,"
112 " expected %d, read %d\n"),
113 current
.track
, current
.head
, track_size
, read_bytes
);
117 for (count
= 0; count
< track_size
; count
++)
118 if (data
[count
] != FD_FILL_BYTE
) {
121 format_track_head(ctrl
, ¤t
);
123 seek_track_head (ctrl
, ¤t
);
128 printf(_("bad data in track/head %u/%u\n"
129 "Continuing ... "), current
.track
, current
.head
);
134 } while (retries_left
);
142 static void __attribute__((__noreturn__
)) usage(void)
145 fputs(USAGE_HEADER
, out
);
146 fprintf(out
, _(" %s [options] <device>\n"),
147 program_invocation_short_name
);
149 fputs(USAGE_SEPARATOR
, out
);
150 fputs(_("Do a low-level formatting of a floppy disk.\n"), out
);
152 fputs(USAGE_OPTIONS
, out
);
153 fputs(_(" -f, --from <N> start at the track N (default 0)\n"), out
);
154 fputs(_(" -t, --to <N> stop at the track N\n"), out
);
155 fputs(_(" -r, --repair <N> try to repair tracks failed during\n"
156 " the verification (max N retries)\n"), out
);
157 fputs(_(" -n, --no-verify disable the verification after the format\n"), out
);
159 fputs(USAGE_SEPARATOR
, out
);
160 printf(USAGE_HELP_OPTIONS(19));
161 printf(USAGE_MAN_TAIL("fdformat(8)"));
166 int main(int argc
, char **argv
)
171 unsigned int repair
= 0;
172 unsigned int track_from
= 0;
173 unsigned int track_to
= 0;
174 int has_user_defined_track_to
= 0;
177 static const struct option longopts
[] = {
178 {"from", required_argument
, NULL
, 'f'},
179 {"to", required_argument
, NULL
, 't'},
180 {"repair", required_argument
, NULL
, 'r'},
181 {"no-verify", no_argument
, NULL
, 'n'},
182 {"version", no_argument
, NULL
, 'V'},
183 {"help", no_argument
, NULL
, 'h'},
187 setlocale(LC_ALL
, "");
188 bindtextdomain(PACKAGE
, LOCALEDIR
);
190 close_stdout_atexit();
192 while ((ch
= getopt_long(argc
, argv
, "f:t:r:nVh", longopts
, NULL
)) != -1)
195 track_from
= strtou32_or_err(optarg
, _("invalid argument - from"));
198 has_user_defined_track_to
= 1;
199 track_to
= strtou32_or_err(optarg
, _("invalid argument - to"));
202 repair
= strtou32_or_err(optarg
, _("invalid argument - repair"));
208 print_version(EXIT_SUCCESS
);
212 errtryhelp(EXIT_FAILURE
);
219 warnx(_("no device specified"));
220 errtryhelp(EXIT_FAILURE
);
222 if (stat(argv
[0], &st
) < 0)
223 err(EXIT_FAILURE
, _("stat of %s failed"), argv
[0]);
224 if (!S_ISBLK(st
.st_mode
))
225 /* do not test major - perhaps this was an USB floppy */
226 errx(EXIT_FAILURE
, _("%s: not a block device"), argv
[0]);
227 ctrl
= open_blkdev_or_file(&st
, argv
[0], O_RDWR
);
229 err(EXIT_FAILURE
, _("cannot open %s"), argv
[0]);
230 if (ioctl(ctrl
, FDGETPRM
, (long) ¶m
) < 0)
231 err(EXIT_FAILURE
, _("could not determine current format type"));
233 printf(_("%s-sided, %d tracks, %d sec/track. Total capacity %d kB.\n"),
234 (param
.head
== 2) ? _("Double") : _("Single"),
235 param
.track
, param
.sect
, param
.size
>> 1);
237 if (!has_user_defined_track_to
)
238 track_to
= param
.track
- 1;
240 if (track_from
>= param
.track
)
241 err(EXIT_FAILURE
, _("user defined start track exceeds the medium specific maximum"));
242 if (track_to
>= param
.track
)
243 err(EXIT_FAILURE
, _("user defined end track exceeds the medium specific maximum"));
244 if (track_from
> track_to
)
245 err(EXIT_FAILURE
, _("user defined start track exceeds the user defined end track"));
247 format_disk(ctrl
, track_from
, track_to
);
250 verify_disk(ctrl
, track_from
, track_to
, repair
);
252 if (close_fd(ctrl
) != 0)
253 err(EXIT_FAILURE
, _("close failed"));