]> git.ipfire.org Git - thirdparty/util-linux.git/blame - 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
CommitLineData
3160fcf3 1/*
9e95aa12
KZ
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * Copyright (C) 1992 Werner Almesberger
10 *
3160fcf3 11 * fdformat.c - Low-level formats a floppy disk - Werner Almesberger
7eda085c 12 */
6dbe3af9 13#include <errno.h>
8d18d353
SK
14#include <fcntl.h>
15#include <getopt.h>
16#include <linux/fd.h>
17#include <stdio.h>
6dbe3af9 18#include <stdlib.h>
fd6b7a7f 19#include <sys/ioctl.h>
8d18d353
SK
20#include <sys/stat.h>
21#include <unistd.h>
22853e4a 22
b7889ba8 23#include "c.h"
f5320b48 24#include "blkdev.h"
e0402441 25#include "strutils.h"
45ca68ec 26#include "closestream.h"
7eda085c 27#include "nls.h"
a53b31d0 28#include "xalloc.h"
6dbe3af9 29
e0402441
JC
30#define SECTOR_SIZE 512
31
2ba641e5 32static struct floppy_struct param;
6dbe3af9 33
6dbe3af9 34
e0402441 35static void format_begin(int ctrl)
6dbe3af9 36{
e0402441
JC
37 if (ioctl(ctrl, FDFMTBEG, NULL) < 0)
38 err(EXIT_FAILURE, "ioctl: FDFMTBEG");
39}
40
41static void format_end(int ctrl)
42{
43 if (ioctl(ctrl, FDFMTEND, NULL) < 0)
44 err(EXIT_FAILURE, "ioctl: FDFMTEND");
45}
46
47static void format_track_head(int ctrl, struct format_descr *descr)
48{
49 if (ioctl(ctrl, FDFMTTRK, (long) descr) < 0)
50 err(EXIT_FAILURE, "ioctl: FDFMTTRK");
51}
52
53static void seek_track_head(int ctrl, struct format_descr *descr)
54{
c1356257
KZ
55 lseek(ctrl, ((off_t) descr->track * param.head + descr->head)
56 * param.sect * SECTOR_SIZE, SEEK_SET);
e0402441
JC
57}
58
59static void format_disk(int ctrl, unsigned int track_from, unsigned int track_to)
60{
61 struct format_descr current;
8d18d353
SK
62
63 printf(_("Formatting ... "));
6dbe3af9 64 fflush(stdout);
e0402441
JC
65
66 format_begin(ctrl);
67
68 for (current.track = track_from; current.track <= track_to; current.track++) {
69 for (current.head = 0; current.head < param.head; current.head++) {
70 printf("%3u/%u\b\b\b\b\b", current.track, current.head);
71 fflush(stdout);
72 format_track_head(ctrl, &current);
8d18d353 73 }
6dbe3af9 74 }
e0402441
JC
75
76 format_end(ctrl);
77
fc747ee7 78 printf(" \b\b\b\b\b%s", _("done\n"));
6dbe3af9
KZ
79}
80
e0402441 81static void verify_disk(int ctrl, unsigned int track_from, unsigned int track_to, unsigned int repair)
6dbe3af9 82{
8d18d353 83 unsigned char *data;
e0402441
JC
84 struct format_descr current;
85 int track_size, count;
86 unsigned int retries_left;
8d18d353 87
e0402441
JC
88 track_size = param.sect * SECTOR_SIZE;
89 data = xmalloc(track_size);
8d18d353 90 printf(_("Verifying ... "));
6dbe3af9 91 fflush(stdout);
e0402441
JC
92
93 current.track = track_from;
94 current.head = 0;
95 seek_track_head (ctrl, &current);
96
97 for (current.track = track_from; current.track <= track_to; current.track++) {
98 for (current.head = 0; current.head < param.head; current.head++) {
99 int read_bytes;
100
101 printf("%3u\b\b\b", current.track);
102 fflush(stdout);
103
104 retries_left = repair;
105 do {
106 read_bytes = read(ctrl, data, track_size);
107 if (read_bytes != track_size) {
108 if (retries_left) {
109 format_begin(ctrl);
110 format_track_head(ctrl, &current);
111 format_end(ctrl);
112 seek_track_head (ctrl, &current);
113 retries_left--;
114 if (retries_left)
115 continue;
116 }
117 if (read_bytes < 0)
118 perror(_("Read: "));
119 fprintf(stderr,
120 _("Problem reading track/head %u/%u,"
121 " expected %d, read %d\n"),
122 current.track, current.head, track_size, read_bytes);
123 free(data);
124 exit(EXIT_FAILURE);
125 }
126 for (count = 0; count < track_size; count++)
127 if (data[count] != FD_FILL_BYTE) {
128 if (retries_left) {
129 format_begin(ctrl);
130 format_track_head(ctrl, &current);
131 format_end(ctrl);
132 seek_track_head (ctrl, &current);
133 retries_left--;
134 if (retries_left)
135 continue;
136 }
137 printf(_("bad data in track/head %u/%u\n"
138 "Continuing ... "), current.track, current.head);
139 fflush(stdout);
140 break;
141 }
8d18d353 142 break;
e0402441
JC
143 } while (retries_left);
144 }
8d18d353 145 }
e0402441 146
8d18d353
SK
147 free(data);
148 printf(_("done\n"));
6dbe3af9
KZ
149}
150
6e1eda6f 151static void __attribute__((__noreturn__)) usage(void)
6dbe3af9 152{
6e1eda6f 153 FILE *out = stdout;
80b037cc
KZ
154 fputs(USAGE_HEADER, out);
155 fprintf(out, _(" %s [options] <device>\n"),
a8f36480 156 program_invocation_short_name);
6dbe3af9 157
451dbcfa
BS
158 fputs(USAGE_SEPARATOR, out);
159 fputs(_("Do a low-level formatting of a floppy disk.\n"), out);
160
80b037cc
KZ
161 fputs(USAGE_OPTIONS, out);
162 fputs(_(" -f, --from <N> start at the track N (default 0)\n"), out);
163 fputs(_(" -t, --to <N> stop at the track N\n"), out);
164 fputs(_(" -r, --repair <N> try to repair tracks failed during\n"
165 " the verification (max N retries)\n"), out);
166 fputs(_(" -n, --no-verify disable the verification after the format\n"), out);
167
168 fputs(USAGE_SEPARATOR, out);
bad4c729
MY
169 fprintf(out, USAGE_HELP_OPTIONS(19));
170 fprintf(out, USAGE_MAN_TAIL("fdformat(8)"));
6dbe3af9 171
6e1eda6f 172 exit(EXIT_SUCCESS);
a8f36480 173}
6dbe3af9 174
8d18d353 175int main(int argc, char **argv)
6dbe3af9 176{
8d18d353
SK
177 int ch;
178 int ctrl;
8c40f481 179 int verify = 1;
e0402441
JC
180 unsigned int repair = 0;
181 unsigned int track_from = 0;
182 unsigned int track_to = 0;
183 int has_user_defined_track_to = 0;
8d18d353
SK
184 struct stat st;
185
186 static const struct option longopts[] = {
e0402441
JC
187 {"from", required_argument, NULL, 'f'},
188 {"to", required_argument, NULL, 't'},
189 {"repair", required_argument, NULL, 'r'},
8d18d353
SK
190 {"no-verify", no_argument, NULL, 'n'},
191 {"version", no_argument, NULL, 'V'},
192 {"help", no_argument, NULL, 'h'},
193 {NULL, 0, NULL, 0}
194 };
195
196 setlocale(LC_ALL, "");
197 bindtextdomain(PACKAGE, LOCALEDIR);
198 textdomain(PACKAGE);
2c308875 199 close_stdout_atexit();
8d18d353 200
e0402441 201 while ((ch = getopt_long(argc, argv, "f:t:r:nVh", longopts, NULL)) != -1)
8d18d353 202 switch (ch) {
e0402441
JC
203 case 'f':
204 track_from = strtou32_or_err(optarg, _("invalid argument - from"));
205 break;
206 case 't':
207 has_user_defined_track_to = 1;
208 track_to = strtou32_or_err(optarg, _("invalid argument - to"));
209 break;
210 case 'r':
211 repair = strtou32_or_err(optarg, _("invalid argument - repair"));
212 break;
8d18d353
SK
213 case 'n':
214 verify = 0;
215 break;
216 case 'V':
2c308875 217 print_version(EXIT_SUCCESS);
8d18d353 218 case 'h':
6e1eda6f 219 usage();
8d18d353 220 default:
677ec86c 221 errtryhelp(EXIT_FAILURE);
8d18d353
SK
222 }
223
224 argc -= optind;
225 argv += optind;
226
6e1eda6f
RM
227 if (argc < 1) {
228 warnx(_("no device specified"));
229 errtryhelp(EXIT_FAILURE);
230 }
8d18d353 231 if (stat(argv[0], &st) < 0)
fc14ceba 232 err(EXIT_FAILURE, _("stat of %s failed"), argv[0]);
8d18d353 233 if (!S_ISBLK(st.st_mode))
3c560686 234 /* do not test major - perhaps this was a USB floppy */
8d18d353 235 errx(EXIT_FAILURE, _("%s: not a block device"), argv[0]);
f5320b48 236 ctrl = open_blkdev_or_file(&st, argv[0], O_RDWR);
8d18d353 237 if (ctrl < 0)
289dcc90 238 err(EXIT_FAILURE, _("cannot open %s"), argv[0]);
e0402441
JC
239 if (ioctl(ctrl, FDGETPRM, (long) &param) < 0)
240 err(EXIT_FAILURE, _("could not determine current format type"));
8d18d353
SK
241
242 printf(_("%s-sided, %d tracks, %d sec/track. Total capacity %d kB.\n"),
e0402441
JC
243 (param.head == 2) ? _("Double") : _("Single"),
244 param.track, param.sect, param.size >> 1);
245
246 if (!has_user_defined_track_to)
247 track_to = param.track - 1;
248
249 if (track_from >= param.track)
250 err(EXIT_FAILURE, _("user defined start track exceeds the medium specific maximum"));
251 if (track_to >= param.track)
252 err(EXIT_FAILURE, _("user defined end track exceeds the medium specific maximum"));
253 if (track_from > track_to)
254 err(EXIT_FAILURE, _("user defined start track exceeds the user defined end track"));
255
256 format_disk(ctrl, track_from, track_to);
8d18d353
SK
257
258 if (verify)
e0402441
JC
259 verify_disk(ctrl, track_from, track_to, repair);
260
261 if (close_fd(ctrl) != 0)
262 err(EXIT_FAILURE, _("close failed"));
263
8d18d353 264 return EXIT_SUCCESS;
6dbe3af9 265}