1 /*        $NetBSD: fdformat.c,v 1.18 2021/11/27 22:16:41 rillig Exp $ */
2 
3 /*-
4  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by John Kohl.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * fdformat: format a floppy diskette, using interface provided in
34  * <sys/fdio.h>
35  */
36 #include <sys/cdefs.h>
37 
38 #ifndef lint
39 __RCSID("$NetBSD: fdformat.c,v 1.18 2021/11/27 22:16:41 rillig Exp $");
40 #endif
41 
42 #include <sys/types.h>
43 #include <sys/fdio.h>
44 #include <sys/ioctl.h>
45 
46 #include <err.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <limits.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include "pathnames.h"
54 
55 static const char *fdb_array[2] = {_PATH_FLOPPYTAB, 0};
56 
57 #define MASK_NBPS             0x0001
58 #define MASK_NCYL             0x0002
59 #define MASK_NSPT             0x0004
60 #define MASK_NTRK             0x0008
61 #define MASK_STEPSPERCYL      0x0010
62 #define MASK_GAPLEN           0x0020
63 #define MASK_FILLBYTE                   0x0040
64 #define MASK_XFER_RATE                  0x0080
65 #define MASK_INTERLEAVE                 0x0100
66 
67 #define ALLPARMS (MASK_NBPS|MASK_NCYL|MASK_NSPT|MASK_NTRK|MASK_STEPSPERCYL|MASK_GAPLEN|MASK_FILLBYTE|MASK_XFER_RATE|MASK_INTERLEAVE)
68 
69 static int          confirm(int);
70 static void         usage(void) __dead;
71 static int          verify_track(int, int, int, struct fdformat_parms *, char *);
72 
73 static int
confirm(int def)74 confirm(int def)
75 {
76           int ch;
77 
78           (void)printf(" Yes/no [%c]?", def ? 'y' : 'n');
79           ch = getchar();
80           switch (ch) {
81           case 'y':
82           case 'Y':
83                     return 1;
84           case '\n':
85                     return def;
86           case EOF:
87           case 'n':
88           case 'N':
89           default:
90                     return 0;
91           }
92 }
93 
94 static int
verify_track(int fd,int cyl,int trk,struct fdformat_parms * parms,char * buf)95 verify_track(int fd, int cyl, int trk, struct fdformat_parms *parms, char *buf)
96 {
97           size_t tracksize;
98           off_t offset;
99 
100           tracksize = parms->nbps * parms->nspt; /* bytes per track */
101           offset = tracksize * (cyl * parms->ntrk + trk); /* track offset */
102 
103           if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
104                     (void)printf("- SEEK ERROR\n");
105                     return 1;
106           }
107           if ((size_t)read(fd, buf, tracksize) != tracksize) {
108                     (void)printf("- VERIFY ERROR\n");
109                     return 1;
110           }
111           return 0;
112 }
113 
114 static void
usage(void)115 usage(void)
116 {
117           (void)fprintf(stderr,
118               "Usage: %s [-f device] [-t type] [-n] [-B nbps] [-S nspt]\n"
119               "\t[-T ntrk] [-C ncyl] [-P stepspercyl] [-G gaplen]\n"
120               "\t[-F fillbyte] [-X xfer_rate] [-I interleave]\n", getprogname());
121           exit(1);
122 }
123 
124 #define numarg(which, maskn, op)                                      \
125           do {                                                                  \
126                     tmplong = strtol(optarg, &tmpcharp, 0);           \
127                     if (*tmpcharp != '\0' || tmplong op 0)            \
128                         errx(1,                                                 \
129                               "Invalid numerical argument `%s' for "  \
130                               # which, optarg);                       \
131                     if (errno == ERANGE && (tmplong == LONG_MIN ||    \
132                         tmplong == LONG_MAX))                         \
133                         err(1,                                                  \
134                               "Bad numerical argument `%s' for "      \
135                               # which, optarg);                       \
136                     parms.which = tmplong;                                      \
137                     parmmask |= MASK_##maskn;                         \
138           } while (0)
139 
140 #define getparm(structname, maskname)                                 \
141           do {                                                                  \
142                     if (cgetnum(fdbuf, # structname, &tmplong) == -1) \
143                               errx(1, "Parameter " # structname       \
144                                   " missing for type `%s'", optarg);  \
145                     parms.structname = tmplong;                       \
146                     parmmask |= MASK_ ## maskname;                              \
147           } while (0)
148 
149 
150 #define copyparm(which, mask)                                                   \
151           if ((parmmask & MASK_##mask) == 0)                          \
152                     parms.which = fetchparms.which
153 
154 int
main(int argc,char * argv[])155 main(int argc, char *argv[])
156 {
157           char *fdbuf = NULL, *trackbuf = NULL;
158           int errcnt = 0;
159           int verify = 1;
160           int ch;
161           long tmplong;
162           int tmpint;
163           char *tmpcharp;
164           int parmmask = 0;
165           struct fdformat_parms parms, fetchparms;
166           struct fdformat_cmd cmd;
167           const char *filename = _PATH_FLOPPY_DEV;
168           int fd;
169           int trk, cyl;
170 
171           while ((ch = getopt(argc, argv, "f:t:nB:C:S:T:P:G:F:X:I:")) != -1)
172                     switch (ch) {
173                     case 't':           /* disk type */
174                               switch (cgetent(&fdbuf, fdb_array, optarg)) {
175                               case 0:
176                                         break;
177                               case 1:
178                               case -3:
179                                         errx(1, "tc= loop or missing entry entry in "
180                                              _PATH_FLOPPYTAB " for type %s", optarg);
181                                         break;
182                               case -1:
183                                         errx(1, "Unknown floppy disk type %s", optarg);
184                                         break;
185                               default:
186                                         err(1, "Problem accessing " _PATH_FLOPPYTAB);
187                                         break;
188                               }
189 
190                               getparm(nbps, NBPS);
191                               getparm(ncyl, NCYL);
192                               getparm(nspt, NSPT);
193                               getparm(ntrk, NTRK);
194                               getparm(stepspercyl, STEPSPERCYL);
195                               getparm(gaplen, GAPLEN);
196                               getparm(fillbyte, FILLBYTE);
197                               getparm(xfer_rate, XFER_RATE);
198                               getparm(interleave, INTERLEAVE);
199                               break;
200                     case 'f':           /* device name */
201                               filename = optarg;
202                               break;
203                     case 'n':           /* no verify */
204                               verify = 0;
205                               break;
206                     case 'B':
207                               numarg(nbps, NBPS, <=);
208                               break;
209                     case 'C':
210                               numarg(ncyl, NCYL, <=);
211                               break;
212                     case 'S':
213                               numarg(nspt, NSPT, <=);
214                               break;
215                     case 'T':
216                               numarg(ntrk, NTRK, <=);
217                               break;
218                     case 'P':
219                               numarg(stepspercyl, STEPSPERCYL, <=);
220                               break;
221                     case 'G':
222                               numarg(gaplen, GAPLEN, <=);
223                               break;
224                     case 'F':
225                               numarg(fillbyte, FILLBYTE, <);
226                               break;
227                     case 'X':
228                               numarg(xfer_rate, XFER_RATE, <=);
229                               break;
230                     case 'I':
231                               numarg(interleave, INTERLEAVE, <=);
232                               break;
233                     case '?':
234                     default:
235                               usage();
236                     }
237 
238           if (optind < argc)
239                     usage();
240 
241           fd = open(filename, O_RDWR);
242           if (fd == -1)
243                     err(1, "Cannot open %s", filename);
244           if (ioctl(fd, FDIOCGETFORMAT, &fetchparms) == -1) {
245                     if (errno == ENOTTY)
246                               err(1, "Device `%s' does not support floppy formatting",
247                                   filename);
248                     else
249                               err(1, "Cannot fetch current floppy"
250                                   " formatting parameters");
251           }
252 
253           copyparm(nbps, NBPS);
254           copyparm(ncyl, NCYL);
255           copyparm(nspt, NSPT);
256           copyparm(ntrk, NTRK);
257           copyparm(stepspercyl, STEPSPERCYL);
258           copyparm(gaplen, GAPLEN);
259           copyparm(fillbyte, FILLBYTE);
260           copyparm(xfer_rate, XFER_RATE);
261           copyparm(interleave, INTERLEAVE);
262 
263           parms.fdformat_version = FDFORMAT_VERSION;
264 
265           tmpint = FDOPT_NORETRY|FDOPT_SILENT;
266           if (ioctl(fd, FDIOCSETOPTS, &tmpint) == -1 ||
267               ioctl(fd, FDIOCSETFORMAT, &parms) == -1) {
268                     errx(1, "Cannot set requested formatting parameters:"
269                         " %d cylinders, %d tracks, %d sectors of %d bytes",
270                         parms.ncyl, parms.ntrk, parms.nspt, parms.nbps);
271           }
272 
273           (void)printf("Ready to format %s with %d cylinders, %d tracks,"
274               " %d sectors of %d bytes\n(%d KB)",
275               filename, parms.ncyl, parms.ntrk, parms.nspt, parms.nbps,
276               parms.ncyl * parms.ntrk * parms.nspt * parms.nbps / 1024);
277           if (!confirm(1))
278                     errx(1,"Formatting abandoned -- not confirmed.");
279 
280           if (verify) {
281                     trackbuf = malloc(parms.nbps * parms.nspt);
282                     if (trackbuf == NULL)
283                               warn("Cannot allocate verification buffer");
284           }
285 
286           cmd.formatcmd_version = FDFORMAT_VERSION;
287           for (cyl = 0; (unsigned int)cyl < parms.ncyl; cyl++) {
288                     cmd.cylinder = cyl;
289                     for (trk = 0; (unsigned int)trk < parms.ntrk; trk++) {
290                               cmd.head = trk;
291                               (void)printf("\rFormatting track %i / head %i ", cyl, trk);
292                               (void)fflush(stdout);
293                               if (ioctl(fd, FDIOCFORMAT_TRACK, &cmd) == 0) {
294                                         if (verify)
295                                                   errcnt += verify_track(fd, cyl, trk,
296                                                       &parms, trackbuf);
297                               } else if (errno == EINVAL) {
298                                         (void)putchar('\n');
299                                         errx(1, "Formatting botch at <%d,%d>",
300                                              cyl, trk);
301                               } else if (errno == EIO) {
302                                         (void)printf("- IO ERROR\n");
303                                         errcnt++;
304                               }
305                     }
306           }
307           (void)printf("\rFormatting %i tracks total complete.\n",
308                     parms.ncyl * parms.ntrk);
309           if (errcnt)
310                     errx(1, "%d track formatting error%s",
311                         errcnt, errcnt == 1 ? "" : "s");
312           return 0;
313 }
314