]> git.ipfire.org Git - thirdparty/util-linux.git/blob - disk-utils/fdformat.c
Merge branch 'meson-more-build-options' of https://github.com/jwillikers/util-linux
[thirdparty/util-linux.git] / disk-utils / fdformat.c
1 /*
2 * fdformat.c - Low-level formats a floppy disk - Werner Almesberger
3 */
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <getopt.h>
7 #include <linux/fd.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sys/ioctl.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
13
14 #include "c.h"
15 #include "blkdev.h"
16 #include "strutils.h"
17 #include "closestream.h"
18 #include "nls.h"
19 #include "xalloc.h"
20
21 #define SECTOR_SIZE 512
22
23 static struct floppy_struct param;
24
25
26 static void format_begin(int ctrl)
27 {
28 if (ioctl(ctrl, FDFMTBEG, NULL) < 0)
29 err(EXIT_FAILURE, "ioctl: FDFMTBEG");
30 }
31
32 static void format_end(int ctrl)
33 {
34 if (ioctl(ctrl, FDFMTEND, NULL) < 0)
35 err(EXIT_FAILURE, "ioctl: FDFMTEND");
36 }
37
38 static void format_track_head(int ctrl, struct format_descr *descr)
39 {
40 if (ioctl(ctrl, FDFMTTRK, (long) descr) < 0)
41 err(EXIT_FAILURE, "ioctl: FDFMTTRK");
42 }
43
44 static void seek_track_head(int ctrl, struct format_descr *descr)
45 {
46 lseek(ctrl, (descr->track * param.head + descr->head) * param.sect * SECTOR_SIZE, SEEK_SET);
47 }
48
49 static void format_disk(int ctrl, unsigned int track_from, unsigned int track_to)
50 {
51 struct format_descr current;
52
53 printf(_("Formatting ... "));
54 fflush(stdout);
55
56 format_begin(ctrl);
57
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);
61 fflush(stdout);
62 format_track_head(ctrl, &current);
63 }
64 }
65
66 format_end(ctrl);
67
68 printf(" \b\b\b\b\b%s", _("done\n"));
69 }
70
71 static void verify_disk(int ctrl, unsigned int track_from, unsigned int track_to, unsigned int repair)
72 {
73 unsigned char *data;
74 struct format_descr current;
75 int track_size, count;
76 unsigned int retries_left;
77
78 track_size = param.sect * SECTOR_SIZE;
79 data = xmalloc(track_size);
80 printf(_("Verifying ... "));
81 fflush(stdout);
82
83 current.track = track_from;
84 current.head = 0;
85 seek_track_head (ctrl, &current);
86
87 for (current.track = track_from; current.track <= track_to; current.track++) {
88 for (current.head = 0; current.head < param.head; current.head++) {
89 int read_bytes;
90
91 printf("%3u\b\b\b", current.track);
92 fflush(stdout);
93
94 retries_left = repair;
95 do {
96 read_bytes = read(ctrl, data, track_size);
97 if (read_bytes != track_size) {
98 if (retries_left) {
99 format_begin(ctrl);
100 format_track_head(ctrl, &current);
101 format_end(ctrl);
102 seek_track_head (ctrl, &current);
103 retries_left--;
104 if (retries_left)
105 continue;
106 }
107 if (read_bytes < 0)
108 perror(_("Read: "));
109 fprintf(stderr,
110 _("Problem reading track/head %u/%u,"
111 " expected %d, read %d\n"),
112 current.track, current.head, track_size, read_bytes);
113 free(data);
114 exit(EXIT_FAILURE);
115 }
116 for (count = 0; count < track_size; count++)
117 if (data[count] != FD_FILL_BYTE) {
118 if (retries_left) {
119 format_begin(ctrl);
120 format_track_head(ctrl, &current);
121 format_end(ctrl);
122 seek_track_head (ctrl, &current);
123 retries_left--;
124 if (retries_left)
125 continue;
126 }
127 printf(_("bad data in track/head %u/%u\n"
128 "Continuing ... "), current.track, current.head);
129 fflush(stdout);
130 break;
131 }
132 break;
133 } while (retries_left);
134 }
135 }
136
137 free(data);
138 printf(_("done\n"));
139 }
140
141 static void __attribute__((__noreturn__)) usage(void)
142 {
143 FILE *out = stdout;
144 fputs(USAGE_HEADER, out);
145 fprintf(out, _(" %s [options] <device>\n"),
146 program_invocation_short_name);
147
148 fputs(USAGE_SEPARATOR, out);
149 fputs(_("Do a low-level formatting of a floppy disk.\n"), out);
150
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);
157
158 fputs(USAGE_SEPARATOR, out);
159 printf(USAGE_HELP_OPTIONS(19));
160 printf(USAGE_MAN_TAIL("fdformat(8)"));
161
162 exit(EXIT_SUCCESS);
163 }
164
165 int main(int argc, char **argv)
166 {
167 int ch;
168 int ctrl;
169 int verify = 1;
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;
174 struct stat st;
175
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'},
183 {NULL, 0, NULL, 0}
184 };
185
186 setlocale(LC_ALL, "");
187 bindtextdomain(PACKAGE, LOCALEDIR);
188 textdomain(PACKAGE);
189 close_stdout_atexit();
190
191 while ((ch = getopt_long(argc, argv, "f:t:r:nVh", longopts, NULL)) != -1)
192 switch (ch) {
193 case 'f':
194 track_from = strtou32_or_err(optarg, _("invalid argument - from"));
195 break;
196 case 't':
197 has_user_defined_track_to = 1;
198 track_to = strtou32_or_err(optarg, _("invalid argument - to"));
199 break;
200 case 'r':
201 repair = strtou32_or_err(optarg, _("invalid argument - repair"));
202 break;
203 case 'n':
204 verify = 0;
205 break;
206 case 'V':
207 print_version(EXIT_SUCCESS);
208 case 'h':
209 usage();
210 default:
211 errtryhelp(EXIT_FAILURE);
212 }
213
214 argc -= optind;
215 argv += optind;
216
217 if (argc < 1) {
218 warnx(_("no device specified"));
219 errtryhelp(EXIT_FAILURE);
220 }
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);
227 if (ctrl < 0)
228 err(EXIT_FAILURE, _("cannot open %s"), argv[0]);
229 if (ioctl(ctrl, FDGETPRM, (long) &param) < 0)
230 err(EXIT_FAILURE, _("could not determine current format type"));
231
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);
235
236 if (!has_user_defined_track_to)
237 track_to = param.track - 1;
238
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"));
245
246 format_disk(ctrl, track_from, track_to);
247
248 if (verify)
249 verify_disk(ctrl, track_from, track_to, repair);
250
251 if (close_fd(ctrl) != 0)
252 err(EXIT_FAILURE, _("close failed"));
253
254 return EXIT_SUCCESS;
255 }