]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/fdformat.c
wipefs: add --lock and LOCK_BLOCK_DEVICE
[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{
c1356257
KZ
46 lseek(ctrl, ((off_t) descr->track * param.head + descr->head)
47 * param.sect * SECTOR_SIZE, SEEK_SET);
e0402441
JC
48}
49
50static void format_disk(int ctrl, unsigned int track_from, unsigned int track_to)
51{
52 struct format_descr current;
8d18d353
SK
53
54 printf(_("Formatting ... "));
6dbe3af9 55 fflush(stdout);
e0402441
JC
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);
8d18d353 64 }
6dbe3af9 65 }
e0402441
JC
66
67 format_end(ctrl);
68
fc747ee7 69 printf(" \b\b\b\b\b%s", _("done\n"));
6dbe3af9
KZ
70}
71
e0402441 72static void verify_disk(int ctrl, unsigned int track_from, unsigned int track_to, unsigned int repair)
6dbe3af9 73{
8d18d353 74 unsigned char *data;
e0402441
JC
75 struct format_descr current;
76 int track_size, count;
77 unsigned int retries_left;
8d18d353 78
e0402441
JC
79 track_size = param.sect * SECTOR_SIZE;
80 data = xmalloc(track_size);
8d18d353 81 printf(_("Verifying ... "));
6dbe3af9 82 fflush(stdout);
e0402441
JC
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 }
8d18d353 133 break;
e0402441
JC
134 } while (retries_left);
135 }
8d18d353 136 }
e0402441 137
8d18d353
SK
138 free(data);
139 printf(_("done\n"));
6dbe3af9
KZ
140}
141
6e1eda6f 142static void __attribute__((__noreturn__)) usage(void)
6dbe3af9 143{
6e1eda6f 144 FILE *out = stdout;
80b037cc
KZ
145 fputs(USAGE_HEADER, out);
146 fprintf(out, _(" %s [options] <device>\n"),
a8f36480 147 program_invocation_short_name);
6dbe3af9 148
451dbcfa
BS
149 fputs(USAGE_SEPARATOR, out);
150 fputs(_("Do a low-level formatting of a floppy disk.\n"), out);
151
80b037cc
KZ
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);
f45f3ec3
RM
160 printf(USAGE_HELP_OPTIONS(19));
161 printf(USAGE_MAN_TAIL("fdformat(8)"));
6dbe3af9 162
6e1eda6f 163 exit(EXIT_SUCCESS);
a8f36480 164}
6dbe3af9 165
8d18d353 166int main(int argc, char **argv)
6dbe3af9 167{
8d18d353
SK
168 int ch;
169 int ctrl;
8c40f481 170 int verify = 1;
e0402441
JC
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;
8d18d353
SK
175 struct stat st;
176
177 static const struct option longopts[] = {
e0402441
JC
178 {"from", required_argument, NULL, 'f'},
179 {"to", required_argument, NULL, 't'},
180 {"repair", required_argument, NULL, 'r'},
8d18d353
SK
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);
2c308875 190 close_stdout_atexit();
8d18d353 191
e0402441 192 while ((ch = getopt_long(argc, argv, "f:t:r:nVh", longopts, NULL)) != -1)
8d18d353 193 switch (ch) {
e0402441
JC
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;
8d18d353
SK
204 case 'n':
205 verify = 0;
206 break;
207 case 'V':
2c308875 208 print_version(EXIT_SUCCESS);
8d18d353 209 case 'h':
6e1eda6f 210 usage();
8d18d353 211 default:
677ec86c 212 errtryhelp(EXIT_FAILURE);
8d18d353
SK
213 }
214
215 argc -= optind;
216 argv += optind;
217
6e1eda6f
RM
218 if (argc < 1) {
219 warnx(_("no device specified"));
220 errtryhelp(EXIT_FAILURE);
221 }
8d18d353 222 if (stat(argv[0], &st) < 0)
fc14ceba 223 err(EXIT_FAILURE, _("stat of %s failed"), argv[0]);
8d18d353
SK
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]);
f5320b48 227 ctrl = open_blkdev_or_file(&st, argv[0], O_RDWR);
8d18d353 228 if (ctrl < 0)
289dcc90 229 err(EXIT_FAILURE, _("cannot open %s"), argv[0]);
e0402441
JC
230 if (ioctl(ctrl, FDGETPRM, (long) &param) < 0)
231 err(EXIT_FAILURE, _("could not determine current format type"));
8d18d353
SK
232
233 printf(_("%s-sided, %d tracks, %d sec/track. Total capacity %d kB.\n"),
e0402441
JC
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);
8d18d353
SK
248
249 if (verify)
e0402441
JC
250 verify_disk(ctrl, track_from, track_to, repair);
251
252 if (close_fd(ctrl) != 0)
253 err(EXIT_FAILURE, _("close failed"));
254
8d18d353 255 return EXIT_SUCCESS;
6dbe3af9 256}