]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/fdformat/fdformat.c
Optionally bind ktls threads to NUMA domains
[FreeBSD/FreeBSD.git] / usr.sbin / fdformat / fdformat.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (C) 1992-1994,2001 by Joerg Wunsch, Dresden
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30
31 #include <sys/types.h>
32 #include <sys/fdcio.h>
33 #include <sys/stat.h>
34
35 #include <ctype.h>
36 #include <err.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <paths.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <strings.h>
44 #include <sysexits.h>
45 #include <unistd.h>
46
47 #include "fdutil.h"
48
49 static void
50 format_track(int fd, int cyl, int secs, int head, int rate,
51              int gaplen, int secsize, int fill, int interleave,
52              int offset)
53 {
54         struct fd_formb f;
55         int i, j, il[FD_MAX_NSEC + 1];
56
57         memset(il, 0, sizeof il);
58         for(j = 0, i = 1 + offset; i <= secs + offset; i++) {
59             while(il[(j % secs) + 1])
60                     j++;
61             il[(j % secs) + 1] = i;
62             j += interleave;
63         }
64
65         f.format_version = FD_FORMAT_VERSION;
66         f.head = head;
67         f.cyl = cyl;
68         f.transfer_rate = rate;
69
70         f.fd_formb_secshift = secsize;
71         f.fd_formb_nsecs = secs;
72         f.fd_formb_gaplen = gaplen;
73         f.fd_formb_fillbyte = fill;
74         for(i = 0; i < secs; i++) {
75                 f.fd_formb_cylno(i) = cyl;
76                 f.fd_formb_headno(i) = head;
77                 f.fd_formb_secno(i) = il[i+1];
78                 f.fd_formb_secsize(i) = secsize;
79         }
80         (void)ioctl(fd, FD_FORM, (caddr_t)&f);
81 }
82
83 static int
84 verify_track(int fd, int track, int tracksize)
85 {
86         static char *buf;
87         static int bufsz;
88         int fdopts = -1, ofdopts, rv = 0;
89
90         if (ioctl(fd, FD_GOPTS, &fdopts) < 0)
91                 warn("warning: ioctl(FD_GOPTS)");
92         else {
93                 ofdopts = fdopts;
94                 fdopts |= FDOPT_NORETRY;
95                 (void)ioctl(fd, FD_SOPTS, &fdopts);
96         }
97
98         if (bufsz < tracksize)
99                 buf = realloc(buf, bufsz = tracksize);
100         if (buf == NULL)
101                 errx(EX_UNAVAILABLE, "out of memory");
102         if (lseek (fd, (long) track * tracksize, 0) < 0)
103                 rv = -1;
104         /* try twice reading it, without using the normal retrier */
105         else if (read (fd, buf, tracksize) != tracksize
106                  && read (fd, buf, tracksize) != tracksize)
107                 rv = -1;
108         if (fdopts != -1)
109                 (void)ioctl(fd, FD_SOPTS, &ofdopts);
110         return (rv);
111 }
112
113 static void
114 usage (void)
115 {
116         errx(EX_USAGE,
117              "usage: fdformat [-F fill] [-f fmt] [-s fmtstr] [-nqvy] device");
118 }
119
120 static int
121 yes (void)
122 {
123         char reply[256], *p;
124
125         reply[sizeof(reply) - 1] = 0;
126         for (;;) {
127                 fflush(stdout);
128                 if (!fgets (reply, sizeof(reply) - 1, stdin))
129                         return (0);
130                 for (p=reply; *p==' ' || *p=='\t'; ++p)
131                         continue;
132                 if (*p=='y' || *p=='Y')
133                         return (1);
134                 if (*p=='n' || *p=='N' || *p=='\n' || *p=='\r')
135                         return (0);
136                 printf("Answer `yes' or `no': ");
137         }
138 }
139
140 int
141 main(int argc, char **argv)
142 {
143         enum fd_drivetype type;
144         struct fd_type fdt, newft, *fdtp;
145         struct stat sb;
146 #define MAXPRINTERRS 10
147         struct fdc_status fdcs[MAXPRINTERRS];
148         int format, fill, quiet, verify, verify_only, confirm;
149         int fd, c, i, track, error, tracks_per_dot, bytes_per_track, errs;
150         int flags;
151         char *fmtstring, *device;
152         const char *name, *descr;
153
154         format = quiet = verify_only = confirm = 0;
155         verify = 1;
156         fill = 0xf6;
157         fmtstring = 0;
158
159         while((c = getopt(argc, argv, "F:f:nqs:vy")) != -1)
160                 switch(c) {
161                 case 'F':       /* fill byte */
162                         if (getnum(optarg, &fill)) {
163                                 fprintf(stderr,
164                         "Bad argument %s to -F option; must be numeric\n",
165                                         optarg);
166                                 usage();
167                         }
168                         break;
169
170                 case 'f':       /* format in kilobytes */
171                         if (getnum(optarg, &format)) {
172                                 fprintf(stderr,
173                         "Bad argument %s to -f option; must be numeric\n",
174                                         optarg);
175                                 usage();
176                         }
177                         break;
178
179                 case 'n':       /* don't verify */
180                         verify = 0;
181                         break;
182
183                 case 'q':       /* quiet */
184                         quiet = 1;
185                         break;
186
187                 case 's':       /* format string with detailed options */
188                         fmtstring = optarg;
189                         break;
190
191                 case 'v':       /* verify only */
192                         verify = 1;
193                         verify_only = 1;
194                         break;
195
196                 case 'y':       /* confirm */
197                         confirm = 1;
198                         break;
199
200                 default:
201                         usage();
202                 }
203
204         if(optind != argc - 1)
205                 usage();
206
207         if (stat(argv[optind], &sb) == -1 && errno == ENOENT) {
208                 /* try prepending _PATH_DEV */
209                 device = malloc(strlen(argv[optind]) + sizeof(_PATH_DEV) + 1);
210                 if (device == NULL)
211                         errx(EX_UNAVAILABLE, "out of memory");
212                 strcpy(device, _PATH_DEV);
213                 strcat(device, argv[optind]);
214                 if (stat(device, &sb) == -1) {
215                         free(device);
216                         device = argv[optind]; /* let it fail below */
217                 }
218         } else {
219                 device = argv[optind];
220         }
221
222         if ((fd = open(device, O_RDWR | O_NONBLOCK)) < 0)
223                 err(EX_OSERR, "open(%s)", device);
224
225         /*
226          * Device initialization.
227          *
228          * First, get the device type descriptor.  This tells us about
229          * the media geometry data we need to format a medium.  It also
230          * lets us know quickly whether the device name actually points
231          * to a floppy disk drive.
232          *
233          * Then, obtain any drive options.  We're mainly interested to
234          * see whether we're currently working on a device with media
235          * density autoselection (FDOPT_AUTOSEL).  Then, we add the
236          * device option to tell the kernel not to log media errors,
237          * since we can handle them ourselves.  If the device does
238          * media density autoselection, we then need to set the device
239          * type appropriately, since by opening with O_NONBLOCK we
240          * told the driver to bypass media autoselection (otherwise we
241          * wouldn't stand a chance to format an unformatted or damaged
242          * medium).  We do not attempt to set the media type on any
243          * other devices since this is a privileged operation.  For the
244          * same reason, specifying -f and -s options is only possible
245          * for autoselecting devices.
246          *
247          * Finally, we are ready to turn off O_NONBLOCK, and start to
248          * actually format something.
249          */
250         if(ioctl(fd, FD_GTYPE, &fdt) < 0)
251                 errx(EX_OSERR, "not a floppy disk: %s", device);
252         if (ioctl(fd, FD_GDTYPE, &type) == -1)
253                 err(EX_OSERR, "ioctl(FD_GDTYPE)");
254         if (format) {
255                 getname(type, &name, &descr);
256                 fdtp = get_fmt(format, type);
257                 if (fdtp == NULL)
258                         errx(EX_USAGE,
259                             "unknown format %d KB for drive type %s",
260                              format, name);
261                 fdt = *fdtp;
262         }
263         if (fmtstring) {
264                 parse_fmt(fmtstring, type, fdt, &newft);
265                 fdt = newft;
266         }
267         if (ioctl(fd, FD_STYPE, &fdt) < 0)
268                 err(EX_OSERR, "ioctl(FD_STYPE)");
269         if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
270                 err(EX_OSERR, "fcntl(F_GETFL)");
271         flags &= ~O_NONBLOCK;
272         if (fcntl(fd, F_SETFL, flags) == -1)
273                 err(EX_OSERR, "fcntl(F_SETFL)");
274
275         bytes_per_track = fdt.sectrac * (128 << fdt.secsize);
276
277         /* XXX  20/40 = 0.5 */
278         tracks_per_dot = (fdt.tracks * fdt.heads + 20) / 40;
279
280         if (verify_only) {
281                 if(!quiet)
282                         printf("Verify %dK floppy `%s'.\n",
283                                 fdt.tracks * fdt.heads * bytes_per_track / 1024,
284                                 device);
285         }
286         else if(!quiet && !confirm) {
287                 printf("Format %dK floppy `%s'? (y/n): ",
288                         fdt.tracks * fdt.heads * bytes_per_track / 1024,
289                         device);
290                 if(!yes()) {
291                         printf("Not confirmed.\n");
292                         return (EX_UNAVAILABLE);
293                 }
294         }
295
296         /*
297          * Formatting.
298          */
299         if(!quiet) {
300                 printf("Processing ");
301                 for (i = 0; i < (fdt.tracks * fdt.heads) / tracks_per_dot; i++)
302                         putchar('-');
303                 printf("\rProcessing ");
304                 fflush(stdout);
305         }
306
307         error = errs = 0;
308
309         for (track = 0; track < fdt.tracks * fdt.heads; track++) {
310                 if (!verify_only) {
311                         format_track(fd, track / fdt.heads, fdt.sectrac,
312                                 track % fdt.heads, fdt.trans, fdt.f_gap,
313                                 fdt.secsize, fill, fdt.f_inter,
314                                 track % fdt.heads? fdt.offset_side2: 0);
315                         if(!quiet && !((track + 1) % tracks_per_dot)) {
316                                 putchar('F');
317                                 fflush(stdout);
318                         }
319                 }
320                 if (verify) {
321                         if (verify_track(fd, track, bytes_per_track) < 0) {
322                                 error = 1;
323                                 if (errs < MAXPRINTERRS && errno == EIO) {
324                                         if (ioctl(fd, FD_GSTAT, fdcs + errs) ==
325                                             -1)
326                                                 errx(EX_IOERR,
327                                         "floppy IO error, but no FDC status");
328                                         errs++;
329                                 }
330                         }
331                         if(!quiet && !((track + 1) % tracks_per_dot)) {
332                                 if (!verify_only)
333                                         putchar('\b');
334                                 if (error) {
335                                         putchar('E');
336                                         error = 0;
337                                 }
338                                 else
339                                         putchar('V');
340                                 fflush(stdout);
341                         }
342                 }
343         }
344         if(!quiet)
345                 printf(" done.\n");
346
347         if (!quiet && errs) {
348                 fflush(stdout);
349                 fprintf(stderr, "Errors encountered:\nCyl Head Sect   Error\n");
350                 for (i = 0; i < errs && i < MAXPRINTERRS; i++) {
351                         fprintf(stderr, " %2d   %2d   %2d   ",
352                                 fdcs[i].status[3], fdcs[i].status[4],
353                                 fdcs[i].status[5]);
354                         printstatus(fdcs + i, 1);
355                         putc('\n', stderr);
356                 }
357                 if (errs >= MAXPRINTERRS)
358                         fprintf(stderr, "(Further errors not printed.)\n");
359         }
360
361         return errs != 0;
362 }