Commit | Line | Data |
---|---|---|
745cabe1 | 1 | /* |
1bd4610c | 2 | * Copyright (C) 1992-1994 by Joerg Wunsch, Dresden |
745cabe1 AC |
3 | * All rights reserved. |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * | |
1bd4610c JW |
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR |
15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
17 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, | |
18 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
20 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
22 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
23 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
24 | * POSSIBILITY OF SUCH DAMAGE. | |
745cabe1 AC |
25 | */ |
26 | ||
27 | /* | |
28 | * FreeBSD: | |
29 | * format a floppy disk | |
30 | * | |
31 | * Added FD_GTYPE ioctl, verifying, proportional indicators. | |
32 | * Serge Vakulenko, vak@zebub.msk.su | |
33 | * Sat Dec 18 17:45:47 MSK 1993 | |
34 | * | |
35 | * Final adaptation, change format/verify logic, add separate | |
36 | * format gap/interleave values | |
37 | * Andrew A. Chernov, ache@astral.msk.su | |
38 | * Thu Jan 27 00:47:24 MSK 1994 | |
39 | */ | |
40 | ||
41 | #include <stdio.h> | |
42 | #include <stdlib.h> | |
43 | #include <unistd.h> | |
44 | #include <fcntl.h> | |
45 | #include <strings.h> | |
46 | #include <ctype.h> | |
47 | ||
48 | #include <errno.h> | |
49 | #include <machine/ioctl_fd.h> | |
50 | #include <../i386/isa/fdreg.h> /* XXX should be in <machine> dir */ | |
51 | ||
52 | static void | |
53 | format_track(int fd, int cyl, int secs, int head, int rate, | |
7531a868 | 54 | int gaplen, int secsize, int fill,int interleave) |
745cabe1 AC |
55 | { |
56 | struct fd_formb f; | |
7531a868 | 57 | register int i,j; |
ea3541cb | 58 | int il[FD_MAX_NSEC + 1]; |
7531a868 AC |
59 | |
60 | memset(il,0,sizeof il); | |
61 | for(j = 0, i = 1; i <= secs; i++) { | |
62 | while(il[(j%secs)+1]) j++; | |
63 | il[(j%secs)+1] = i; | |
64 | j += interleave; | |
65 | } | |
745cabe1 AC |
66 | |
67 | f.format_version = FD_FORMAT_VERSION; | |
68 | f.head = head; | |
69 | f.cyl = cyl; | |
70 | f.transfer_rate = rate; | |
71 | ||
72 | f.fd_formb_secshift = secsize; | |
73 | f.fd_formb_nsecs = secs; | |
74 | f.fd_formb_gaplen = gaplen; | |
75 | f.fd_formb_fillbyte = fill; | |
76 | for(i = 0; i < secs; i++) { | |
77 | f.fd_formb_cylno(i) = cyl; | |
78 | f.fd_formb_headno(i) = head; | |
7531a868 | 79 | f.fd_formb_secno(i) = il[i+1]; |
745cabe1 AC |
80 | f.fd_formb_secsize(i) = secsize; |
81 | } | |
82 | if(ioctl(fd, FD_FORM, (caddr_t)&f) < 0) { | |
83 | perror("\nfdformat: ioctl(FD_FORM)"); | |
84 | exit(1); | |
85 | } | |
86 | } | |
87 | ||
88 | static int | |
89 | verify_track(int fd, int track, int tracksize) | |
90 | { | |
91 | static char *buf = 0; | |
92 | static int bufsz = 0; | |
1bd4610c JW |
93 | int fdopts = -1, ofdopts, rv = 0; |
94 | ||
95 | if (ioctl(fd, FD_GOPTS, &fdopts) < 0) | |
96 | perror("warning: ioctl(FD_GOPTS)"); | |
97 | else { | |
98 | ofdopts = fdopts; | |
99 | fdopts |= FDOPT_NORETRY; | |
100 | (void)ioctl(fd, FD_SOPTS, &fdopts); | |
101 | } | |
102 | ||
745cabe1 AC |
103 | if (bufsz < tracksize) { |
104 | if (buf) | |
105 | free (buf); | |
106 | bufsz = tracksize; | |
107 | buf = 0; | |
108 | } | |
109 | if (! buf) | |
110 | buf = malloc (bufsz); | |
111 | if (! buf) { | |
112 | fprintf (stderr, "\nfdformat: out of memory\n"); | |
113 | exit (2); | |
114 | } | |
115 | if (lseek (fd, (long) track*tracksize, 0) < 0) | |
1bd4610c JW |
116 | rv = -1; |
117 | /* try twice reading it, without using the normal retrier */ | |
118 | else if (read (fd, buf, tracksize) != tracksize | |
119 | && read (fd, buf, tracksize) != tracksize) | |
120 | rv = -1; | |
121 | if(fdopts != -1) | |
122 | (void)ioctl(fd, FD_SOPTS, &ofdopts); | |
123 | return (rv); | |
745cabe1 AC |
124 | } |
125 | ||
126 | static const char * | |
127 | makename(const char *arg, const char *suffix) | |
128 | { | |
129 | static char namebuff[20]; /* big enough for "/dev/rfd0a"... */ | |
130 | ||
131 | memset(namebuff, 0, 20); | |
132 | if(*arg == '\0') /* ??? */ | |
133 | return arg; | |
134 | if(*arg == '/') /* do not convert absolute pathnames */ | |
135 | return arg; | |
136 | strcpy(namebuff, "/dev/r"); | |
137 | strncat(namebuff, arg, 3); | |
138 | strcat(namebuff, suffix); | |
139 | return namebuff; | |
140 | } | |
141 | ||
142 | static void | |
1bd4610c | 143 | usage (void) |
745cabe1 AC |
144 | { |
145 | printf("Usage:\n\tfdformat [-q] [-n | -v] [-f #] [-c #] [-s #] [-h #]\n"); | |
146 | printf("\t\t [-r #] [-g #] [-i #] [-S #] [-F #] [-t #] devname\n"); | |
147 | printf("Options:\n"); | |
148 | printf("\t-q\tsupress any normal output, don't ask for confirmation\n"); | |
149 | printf("\t-n\tdon't verify floppy after formatting\n"); | |
150 | printf("\t-v\tdon't format, verify only\n"); | |
151 | printf("\t-f #\tspecify desired floppy capacity, in kilobytes;\n"); | |
152 | printf("\t\tvalid choices are 360, 720, 800, 820, 1200, 1440, 1480, 1720\n"); | |
153 | printf("\tdevname\tthe full name of floppy device or in short form fd0, fd1\n"); | |
154 | printf("Obscure options:\n"); | |
155 | printf("\t-c #\tspecify number of cylinders, 40 or 80\n"); | |
156 | printf("\t-s #\tspecify number of sectors per track, 9, 10, 15 or 18\n"); | |
157 | printf("\t-h #\tspecify number of floppy heads, 1 or 2\n"); | |
158 | printf("\t-r #\tspecify data rate, 250, 300 or 500 kbps\n"); | |
159 | printf("\t-g #\tspecify gap length\n"); | |
160 | printf("\t-i #\tspecify interleave factor\n"); | |
161 | printf("\t-S #\tspecify sector size, 0=128, 1=256, 2=512 bytes\n"); | |
162 | printf("\t-F #\tspecify fill byte\n"); | |
163 | printf("\t-t #\tnumber of steps per track\n"); | |
164 | exit(2); | |
165 | } | |
166 | ||
167 | static int | |
1bd4610c | 168 | yes (void) |
745cabe1 AC |
169 | { |
170 | char reply [256], *p; | |
171 | ||
172 | reply[sizeof(reply)-1] = 0; | |
173 | for (;;) { | |
174 | fflush(stdout); | |
175 | if (! fgets (reply, sizeof(reply)-1, stdin)) | |
176 | return (0); | |
177 | for (p=reply; *p==' ' || *p=='\t'; ++p) | |
178 | continue; | |
179 | if (*p=='y' || *p=='Y') | |
180 | return (1); | |
181 | if (*p=='n' || *p=='N' || *p=='\n' || *p=='\r') | |
182 | return (0); | |
183 | printf("Answer `yes' or `no': "); | |
184 | } | |
185 | } | |
186 | ||
187 | int | |
188 | main(int argc, char **argv) | |
189 | { | |
190 | int format = -1, cyls = -1, secs = -1, heads = -1, intleave = -1; | |
191 | int rate = -1, gaplen = -1, secsize = -1, steps = -1; | |
192 | int fill = 0xf6, quiet = 0, verify = 1, verify_only = 0; | |
193 | int fd, c, track, error, tracks_per_dot, bytes_per_track, errs; | |
194 | const char *devname, *suffix; | |
195 | struct fd_type fdt; | |
196 | ||
197 | while((c = getopt(argc, argv, "f:c:s:h:r:g:S:F:t:i:qvn")) != -1) | |
198 | switch(c) { | |
199 | case 'f': /* format in kilobytes */ | |
200 | format = atoi(optarg); | |
201 | break; | |
202 | ||
203 | case 'c': /* # of cyls */ | |
204 | cyls = atoi(optarg); | |
205 | break; | |
206 | ||
207 | case 's': /* # of secs per track */ | |
208 | secs = atoi(optarg); | |
209 | break; | |
210 | ||
211 | case 'h': /* # of heads */ | |
212 | heads = atoi(optarg); | |
213 | break; | |
214 | ||
215 | case 'r': /* transfer rate, kilobyte/sec */ | |
216 | rate = atoi(optarg); | |
217 | break; | |
218 | ||
219 | case 'g': /* length of GAP3 to format with */ | |
220 | gaplen = atoi(optarg); | |
221 | break; | |
222 | ||
223 | case 'S': /* sector size shift factor (1 << S)*128 */ | |
224 | secsize = atoi(optarg); | |
225 | break; | |
226 | ||
227 | case 'F': /* fill byte, C-like notation allowed */ | |
228 | fill = (int)strtol(optarg, (char **)0, 0); | |
229 | break; | |
230 | ||
231 | case 't': /* steps per track */ | |
232 | steps = atoi(optarg); | |
233 | break; | |
234 | ||
235 | case 'i': /* interleave factor */ | |
236 | intleave = atoi(optarg); | |
237 | break; | |
238 | ||
239 | case 'q': | |
240 | quiet = 1; | |
241 | break; | |
242 | ||
243 | case 'n': | |
244 | verify = 0; | |
245 | break; | |
246 | ||
247 | case 'v': | |
248 | verify = 1; | |
249 | verify_only = 1; | |
250 | break; | |
251 | ||
252 | case '?': default: | |
253 | usage(); | |
254 | } | |
255 | ||
256 | if(optind != argc - 1) | |
257 | usage(); | |
258 | ||
259 | switch(format) { | |
260 | default: | |
261 | fprintf(stderr, "fdformat: bad floppy size: %dK\n", format); | |
262 | exit(2); | |
263 | case -1: suffix = ""; break; | |
264 | case 360: suffix = ".360"; break; | |
265 | case 720: suffix = ".720"; break; | |
266 | case 800: suffix = ".800"; break; | |
267 | case 820: suffix = ".820"; break; | |
268 | case 1200: suffix = ".1200"; break; | |
269 | case 1440: suffix = ".1440"; break; | |
270 | case 1480: suffix = ".1480"; break; | |
271 | case 1720: suffix = ".1720"; break; | |
272 | } | |
273 | ||
274 | devname = makename(argv[optind], suffix); | |
275 | ||
276 | if((fd = open(devname, O_RDWR)) < 0) { | |
277 | perror(devname); | |
278 | exit(1); | |
279 | } | |
280 | ||
281 | if(ioctl(fd, FD_GTYPE, &fdt) < 0) { | |
282 | fprintf(stderr, "fdformat: not a floppy disk: %s\n", devname); | |
283 | exit(1); | |
284 | } | |
285 | ||
286 | switch(rate) { | |
287 | case -1: break; | |
288 | case 250: fdt.trans = FDC_250KBPS; break; | |
289 | case 300: fdt.trans = FDC_300KBPS; break; | |
290 | case 500: fdt.trans = FDC_500KBPS; break; | |
291 | default: | |
292 | fprintf(stderr, "fdformat: invalid transfer rate: %d\n", rate); | |
293 | exit(2); | |
294 | } | |
295 | ||
296 | if (cyls >= 0) fdt.tracks = cyls; | |
297 | if (secs >= 0) fdt.sectrac = secs; | |
7531a868 AC |
298 | if (fdt.sectrac > FD_MAX_NSEC) { |
299 | fprintf(stderr, "fdformat: too many sectors per track, max value is %d\n", FD_MAX_NSEC); | |
300 | exit(2); | |
301 | } | |
745cabe1 AC |
302 | if (heads >= 0) fdt.heads = heads; |
303 | if (gaplen >= 0) fdt.f_gap = gaplen; | |
304 | if (secsize >= 0) fdt.secsize = secsize; | |
305 | if (steps >= 0) fdt.steptrac = steps; | |
306 | if (intleave >= 0) fdt.f_inter = intleave; | |
745cabe1 AC |
307 | |
308 | bytes_per_track = fdt.sectrac * (1<<fdt.secsize) * 128; | |
309 | tracks_per_dot = fdt.tracks * fdt.heads / 40; | |
310 | ||
311 | if (verify_only) { | |
312 | if(!quiet) | |
313 | printf("Verify %dK floppy `%s'.\n", | |
314 | fdt.tracks * fdt.heads * bytes_per_track / 1024, | |
315 | devname); | |
316 | } | |
317 | else if(!quiet) { | |
318 | printf("Format %dK floppy `%s'? (y/n): ", | |
319 | fdt.tracks * fdt.heads * bytes_per_track / 1024, | |
320 | devname); | |
321 | if(! yes ()) { | |
322 | printf("Not confirmed.\n"); | |
323 | return 0; | |
324 | } | |
325 | } | |
326 | ||
327 | /* | |
328 | * Formatting. | |
329 | */ | |
330 | if(!quiet) { | |
331 | printf("Processing ----------------------------------------\r"); | |
332 | printf("Processing "); | |
333 | fflush(stdout); | |
334 | } | |
335 | ||
336 | error = errs = 0; | |
337 | ||
338 | for (track = 0; track < fdt.tracks * fdt.heads; track++) { | |
339 | if (!verify_only) { | |
6cdf8df9 RG |
340 | format_track(fd, track / fdt.heads, fdt.sectrac, |
341 | track % fdt.heads, fdt.trans, fdt.f_gap, | |
342 | fdt.secsize, fill, fdt.f_inter); | |
745cabe1 AC |
343 | if(!quiet && !((track + 1) % tracks_per_dot)) { |
344 | putchar('F'); | |
345 | fflush(stdout); | |
346 | } | |
347 | } | |
348 | if (verify) { | |
349 | if (verify_track(fd, track, bytes_per_track) < 0) | |
350 | error = errs = 1; | |
351 | if(!quiet && !((track + 1) % tracks_per_dot)) { | |
352 | if (!verify_only) | |
353 | putchar('\b'); | |
354 | if (error) { | |
355 | putchar('E'); | |
356 | error = 0; | |
357 | } | |
358 | else | |
359 | putchar('V'); | |
360 | fflush(stdout); | |
361 | } | |
362 | } | |
363 | } | |
364 | if(!quiet) | |
365 | printf(" done.\n"); | |
366 | ||
367 | return errs; | |
368 | } | |
1bd4610c JW |
369 | /* |
370 | * Local Variables: | |
371 | * c-indent-level: 8 | |
372 | * c-continued-statement-offset: 8 | |
373 | * c-continued-brace-offset: 0 | |
374 | * c-brace-offset: -8 | |
375 | * c-brace-imaginary-offset: 0 | |
376 | * c-argdecl-indent: 8 | |
377 | * c-label-offset: -8 | |
378 | * c++-hanging-braces: 1 | |
379 | * c++-access-specifier-offset: -8 | |
380 | * c++-empty-arglist-indent: 8 | |
381 | * c++-friend-offset: 0 | |
382 | * End: | |
383 | */ |