]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/fdformat.c
misc: consolidate version printing and close_stdout()
[thirdparty/util-linux.git] / disk-utils / fdformat.c
CommitLineData
3160fcf3
KZ
1/*
2 * fdformat.c - Low-level formats a floppy disk - Werner Almesberger
7eda085c 3 */
6dbe3af9 4#include <errno.h>
8d18d353
SK
5#include <fcntl.h>
6#include <getopt.h>
7#include <linux/fd.h>
8#include <stdio.h>
6dbe3af9 9#include <stdlib.h>
fd6b7a7f 10#include <sys/ioctl.h>
8d18d353
SK
11#include <sys/stat.h>
12#include <unistd.h>
22853e4a 13
b7889ba8 14#include "c.h"
f5320b48 15#include "blkdev.h"
e0402441 16#include "strutils.h"
45ca68ec 17#include "closestream.h"
7eda085c 18#include "nls.h"
a53b31d0 19#include "xalloc.h"
6dbe3af9 20
e0402441
JC
21#define SECTOR_SIZE 512
22
2ba641e5 23static struct floppy_struct param;
6dbe3af9 24
6dbe3af9 25
e0402441 26static void format_begin(int ctrl)
6dbe3af9 27{
e0402441
JC
28 if (ioctl(ctrl, FDFMTBEG, NULL) < 0)
29 err(EXIT_FAILURE, "ioctl: FDFMTBEG");
30}
31
32static void format_end(int ctrl)
33{
34 if (ioctl(ctrl, FDFMTEND, NULL) < 0)
35 err(EXIT_FAILURE, "ioctl: FDFMTEND");
36}
37
38static 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
44static 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
49static void format_disk(int ctrl, unsigned int track_from, unsigned int track_to)
50{
51 struct format_descr current;
8d18d353
SK
52
53 printf(_("Formatting ... "));
6dbe3af9 54 fflush(stdout);
e0402441
JC
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);
8d18d353 63 }
6dbe3af9 64 }
e0402441
JC
65
66 format_end(ctrl);
67
fc747ee7 68 printf(" \b\b\b\b\b%s", _("done\n"));
6dbe3af9
KZ
69}
70
e0402441 71static void verify_disk(int ctrl, unsigned int track_from, unsigned int track_to, unsigned int repair)
6dbe3af9 72{
8d18d353 73 unsigned char *data;
e0402441
JC
74 struct format_descr current;
75 int track_size, count;
76 unsigned int retries_left;
8d18d353 77
e0402441
JC
78 track_size = param.sect * SECTOR_SIZE;
79 data = xmalloc(track_size);
8d18d353 80 printf(_("Verifying ... "));
6dbe3af9 81 fflush(stdout);
e0402441
JC
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 }
8d18d353 132 break;
e0402441
JC
133 } while (retries_left);
134 }
8d18d353 135 }
e0402441 136
8d18d353
SK
137 free(data);
138 printf(_("done\n"));
6dbe3af9
KZ
139}
140
6e1eda6f 141static void __attribute__((__noreturn__)) usage(void)
6dbe3af9 142{
6e1eda6f 143 FILE *out = stdout;
80b037cc
KZ
144 fputs(USAGE_HEADER, out);
145 fprintf(out, _(" %s [options] <device>\n"),
a8f36480 146 program_invocation_short_name);
6dbe3af9 147
451dbcfa
BS
148 fputs(USAGE_SEPARATOR, out);
149 fputs(_("Do a low-level formatting of a floppy disk.\n"), out);
150
80b037cc
KZ
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);
f45f3ec3
RM
159 printf(USAGE_HELP_OPTIONS(19));
160 printf(USAGE_MAN_TAIL("fdformat(8)"));
6dbe3af9 161
6e1eda6f 162 exit(EXIT_SUCCESS);
a8f36480 163}
6dbe3af9 164
8d18d353 165int main(int argc, char **argv)
6dbe3af9 166{
8d18d353
SK
167 int ch;
168 int ctrl;
8c40f481 169 int verify = 1;
e0402441
JC
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;
8d18d353
SK
174 struct stat st;
175
176 static const struct option longopts[] = {
e0402441
JC
177 {"from", required_argument, NULL, 'f'},
178 {"to", required_argument, NULL, 't'},
179 {"repair", required_argument, NULL, 'r'},
8d18d353
SK
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);
2c308875 189 close_stdout_atexit();
8d18d353 190
e0402441 191 while ((ch = getopt_long(argc, argv, "f:t:r:nVh", longopts, NULL)) != -1)
8d18d353 192 switch (ch) {
e0402441
JC
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;
8d18d353
SK
203 case 'n':
204 verify = 0;
205 break;
206 case 'V':
2c308875 207 print_version(EXIT_SUCCESS);
8d18d353 208 case 'h':
6e1eda6f 209 usage();
8d18d353 210 default:
677ec86c 211 errtryhelp(EXIT_FAILURE);
8d18d353
SK
212 }
213
214 argc -= optind;
215 argv += optind;
216
6e1eda6f
RM
217 if (argc < 1) {
218 warnx(_("no device specified"));
219 errtryhelp(EXIT_FAILURE);
220 }
8d18d353 221 if (stat(argv[0], &st) < 0)
fc14ceba 222 err(EXIT_FAILURE, _("stat of %s failed"), argv[0]);
8d18d353
SK
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]);
f5320b48 226 ctrl = open_blkdev_or_file(&st, argv[0], O_RDWR);
8d18d353 227 if (ctrl < 0)
289dcc90 228 err(EXIT_FAILURE, _("cannot open %s"), argv[0]);
e0402441
JC
229 if (ioctl(ctrl, FDGETPRM, (long) &param) < 0)
230 err(EXIT_FAILURE, _("could not determine current format type"));
8d18d353
SK
231
232 printf(_("%s-sided, %d tracks, %d sec/track. Total capacity %d kB.\n"),
e0402441
JC
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);
8d18d353
SK
247
248 if (verify)
e0402441
JC
249 verify_disk(ctrl, track_from, track_to, repair);
250
251 if (close_fd(ctrl) != 0)
252 err(EXIT_FAILURE, _("close failed"));
253
8d18d353 254 return EXIT_SUCCESS;
6dbe3af9 255}