]> git.ipfire.org Git - thirdparty/util-linux.git/blob - disk-utils/fdformat.c
cal: Update man page
[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, ((off_t) descr->track * param.head + descr->head)
47 * param.sect * SECTOR_SIZE, SEEK_SET);
48 }
49
50 static void format_disk(int ctrl, unsigned int track_from, unsigned int track_to)
51 {
52 struct format_descr current;
53
54 printf(_("Formatting ... "));
55 fflush(stdout);
56
57 format_begin(ctrl);
58
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);
62 fflush(stdout);
63 format_track_head(ctrl, &current);
64 }
65 }
66
67 format_end(ctrl);
68
69 printf(" \b\b\b\b\b%s", _("done\n"));
70 }
71
72 static void verify_disk(int ctrl, unsigned int track_from, unsigned int track_to, unsigned int repair)
73 {
74 unsigned char *data;
75 struct format_descr current;
76 int track_size, count;
77 unsigned int retries_left;
78
79 track_size = param.sect * SECTOR_SIZE;
80 data = xmalloc(track_size);
81 printf(_("Verifying ... "));
82 fflush(stdout);
83
84 current.track = track_from;
85 current.head = 0;
86 seek_track_head (ctrl, &current);
87
88 for (current.track = track_from; current.track <= track_to; current.track++) {
89 for (current.head = 0; current.head < param.head; current.head++) {
90 int read_bytes;
91
92 printf("%3u\b\b\b", current.track);
93 fflush(stdout);
94
95 retries_left = repair;
96 do {
97 read_bytes = read(ctrl, data, track_size);
98 if (read_bytes != track_size) {
99 if (retries_left) {
100 format_begin(ctrl);
101 format_track_head(ctrl, &current);
102 format_end(ctrl);
103 seek_track_head (ctrl, &current);
104 retries_left--;
105 if (retries_left)
106 continue;
107 }
108 if (read_bytes < 0)
109 perror(_("Read: "));
110 fprintf(stderr,
111 _("Problem reading track/head %u/%u,"
112 " expected %d, read %d\n"),
113 current.track, current.head, track_size, read_bytes);
114 free(data);
115 exit(EXIT_FAILURE);
116 }
117 for (count = 0; count < track_size; count++)
118 if (data[count] != FD_FILL_BYTE) {
119 if (retries_left) {
120 format_begin(ctrl);
121 format_track_head(ctrl, &current);
122 format_end(ctrl);
123 seek_track_head (ctrl, &current);
124 retries_left--;
125 if (retries_left)
126 continue;
127 }
128 printf(_("bad data in track/head %u/%u\n"
129 "Continuing ... "), current.track, current.head);
130 fflush(stdout);
131 break;
132 }
133 break;
134 } while (retries_left);
135 }
136 }
137
138 free(data);
139 printf(_("done\n"));
140 }
141
142 static void __attribute__((__noreturn__)) usage(void)
143 {
144 FILE *out = stdout;
145 fputs(USAGE_HEADER, out);
146 fprintf(out, _(" %s [options] <device>\n"),
147 program_invocation_short_name);
148
149 fputs(USAGE_SEPARATOR, out);
150 fputs(_("Do a low-level formatting of a floppy disk.\n"), out);
151
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);
158
159 fputs(USAGE_SEPARATOR, out);
160 printf(USAGE_HELP_OPTIONS(19));
161 printf(USAGE_MAN_TAIL("fdformat(8)"));
162
163 exit(EXIT_SUCCESS);
164 }
165
166 int main(int argc, char **argv)
167 {
168 int ch;
169 int ctrl;
170 int verify = 1;
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;
175 struct stat st;
176
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'},
184 {NULL, 0, NULL, 0}
185 };
186
187 setlocale(LC_ALL, "");
188 bindtextdomain(PACKAGE, LOCALEDIR);
189 textdomain(PACKAGE);
190 close_stdout_atexit();
191
192 while ((ch = getopt_long(argc, argv, "f:t:r:nVh", longopts, NULL)) != -1)
193 switch (ch) {
194 case 'f':
195 track_from = strtou32_or_err(optarg, _("invalid argument - from"));
196 break;
197 case 't':
198 has_user_defined_track_to = 1;
199 track_to = strtou32_or_err(optarg, _("invalid argument - to"));
200 break;
201 case 'r':
202 repair = strtou32_or_err(optarg, _("invalid argument - repair"));
203 break;
204 case 'n':
205 verify = 0;
206 break;
207 case 'V':
208 print_version(EXIT_SUCCESS);
209 case 'h':
210 usage();
211 default:
212 errtryhelp(EXIT_FAILURE);
213 }
214
215 argc -= optind;
216 argv += optind;
217
218 if (argc < 1) {
219 warnx(_("no device specified"));
220 errtryhelp(EXIT_FAILURE);
221 }
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);
228 if (ctrl < 0)
229 err(EXIT_FAILURE, _("cannot open %s"), argv[0]);
230 if (ioctl(ctrl, FDGETPRM, (long) &param) < 0)
231 err(EXIT_FAILURE, _("could not determine current format type"));
232
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);
236
237 if (!has_user_defined_track_to)
238 track_to = param.track - 1;
239
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"));
246
247 format_disk(ctrl, track_from, track_to);
248
249 if (verify)
250 verify_disk(ctrl, track_from, track_to, repair);
251
252 if (close_fd(ctrl) != 0)
253 err(EXIT_FAILURE, _("close failed"));
254
255 return EXIT_SUCCESS;
256 }