]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/fdformat.c
misc: add static keyword to where needed [smatch scan]
[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
8d18d353 68 printf(_("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
a8f36480 141static void __attribute__ ((__noreturn__)) usage(FILE * out)
6dbe3af9 142{
80b037cc
KZ
143 fputs(USAGE_HEADER, out);
144 fprintf(out, _(" %s [options] <device>\n"),
a8f36480 145 program_invocation_short_name);
6dbe3af9 146
451dbcfa
BS
147 fputs(USAGE_SEPARATOR, out);
148 fputs(_("Do a low-level formatting of a floppy disk.\n"), out);
149
80b037cc
KZ
150 fputs(USAGE_OPTIONS, out);
151 fputs(_(" -f, --from <N> start at the track N (default 0)\n"), out);
152 fputs(_(" -t, --to <N> stop at the track N\n"), out);
153 fputs(_(" -r, --repair <N> try to repair tracks failed during\n"
154 " the verification (max N retries)\n"), out);
155 fputs(_(" -n, --no-verify disable the verification after the format\n"), out);
156
157 fputs(USAGE_SEPARATOR, out);
158 fputs(USAGE_HELP, out);
159 fputs(USAGE_VERSION, out);
160 fprintf(out, USAGE_MAN_TAIL("fdformat(8)"));
6dbe3af9 161
a8f36480
SK
162 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
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);
45ca68ec 189 atexit(close_stdout);
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':
e421313d 207 printf(UTIL_LINUX_VERSION);
8d18d353
SK
208 exit(EXIT_SUCCESS);
209 case 'h':
210 usage(stdout);
211 default:
677ec86c 212 errtryhelp(EXIT_FAILURE);
8d18d353
SK
213 }
214
215 argc -= optind;
216 argv += optind;
217
218 if (argc < 1)
219 usage(stderr);
220 if (stat(argv[0], &st) < 0)
fc14ceba 221 err(EXIT_FAILURE, _("stat of %s failed"), argv[0]);
8d18d353
SK
222 if (!S_ISBLK(st.st_mode))
223 /* do not test major - perhaps this was an USB floppy */
224 errx(EXIT_FAILURE, _("%s: not a block device"), argv[0]);
f5320b48 225 ctrl = open_blkdev_or_file(&st, argv[0], O_RDWR);
8d18d353 226 if (ctrl < 0)
289dcc90 227 err(EXIT_FAILURE, _("cannot open %s"), argv[0]);
e0402441
JC
228 if (ioctl(ctrl, FDGETPRM, (long) &param) < 0)
229 err(EXIT_FAILURE, _("could not determine current format type"));
8d18d353
SK
230
231 printf(_("%s-sided, %d tracks, %d sec/track. Total capacity %d kB.\n"),
e0402441
JC
232 (param.head == 2) ? _("Double") : _("Single"),
233 param.track, param.sect, param.size >> 1);
234
235 if (!has_user_defined_track_to)
236 track_to = param.track - 1;
237
238 if (track_from >= param.track)
239 err(EXIT_FAILURE, _("user defined start track exceeds the medium specific maximum"));
240 if (track_to >= param.track)
241 err(EXIT_FAILURE, _("user defined end track exceeds the medium specific maximum"));
242 if (track_from > track_to)
243 err(EXIT_FAILURE, _("user defined start track exceeds the user defined end track"));
244
245 format_disk(ctrl, track_from, track_to);
8d18d353
SK
246
247 if (verify)
e0402441
JC
248 verify_disk(ctrl, track_from, track_to, repair);
249
250 if (close_fd(ctrl) != 0)
251 err(EXIT_FAILURE, _("close failed"));
252
8d18d353 253 return EXIT_SUCCESS;
6dbe3af9 254}