fdformat.c revision 79111
1205859Sjoel/*
2162874Snetchild * Copyright (C) 1992-1994,2001 by Joerg Wunsch, Dresden
3159687Snetchild * All rights reserved.
4159687Snetchild *
5159687Snetchild * Redistribution and use in source and binary forms, with or without
6159687Snetchild * modification, are permitted provided that the following conditions
7159687Snetchild * are met:
8159687Snetchild * 1. Redistributions of source code must retain the above copyright
9159687Snetchild *    notice, this list of conditions and the following disclaimer.
10159687Snetchild * 2. Redistributions in binary form must reproduce the above copyright
11159687Snetchild *    notice, this list of conditions and the following disclaimer in the
12159687Snetchild *    documentation and/or other materials provided with the distribution.
13159687Snetchild *
14159687Snetchild * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15159687Snetchild * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16159687Snetchild * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17159687Snetchild * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
18159687Snetchild * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19159687Snetchild * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20159687Snetchild * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21159687Snetchild * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22159687Snetchild * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
23159687Snetchild * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24159687Snetchild * POSSIBILITY OF SUCH DAMAGE.
25159687Snetchild *
26159687Snetchild * $FreeBSD: head/usr.sbin/fdformat/fdformat.c 79111 2001-07-02 21:24:03Z joerg $
27159687Snetchild */
28159687Snetchild
29159687Snetchild/*
30193640Sariff * FreeBSD:
31193640Sariff * format a floppy disk
32193640Sariff *
33193640Sariff * Added FD_GTYPE ioctl, verifying, proportional indicators.
34159687Snetchild * Serge Vakulenko, vak@zebub.msk.su
35159687Snetchild * Sat Dec 18 17:45:47 MSK 1993
36162874Snetchild *
37159687Snetchild * Final adaptation, change format/verify logic, add separate
38227293Sed * format gap/interleave values
39159687Snetchild * Andrew A. Chernov, ache@astral.msk.su
40162874Snetchild * Thu Jan 27 00:47:24 MSK 1994
41162874Snetchild */
42159687Snetchild
43162874Snetchild#include <ctype.h>
44159687Snetchild#include <err.h>
45159687Snetchild#include <errno.h>
46159687Snetchild#include <fcntl.h>
47159687Snetchild#include <paths.h>
48159687Snetchild#include <stdio.h>
49159687Snetchild#include <stdlib.h>
50159687Snetchild#include <strings.h>
51162874Snetchild#include <unistd.h>
52166713Sariff
53159687Snetchild#include <sys/fdcio.h>
54159687Snetchild
55159687Snetchild#include "fdutil.h"
56162874Snetchild
57159687Snetchildstatic void
58159687Snetchildformat_track(int fd, int cyl, int secs, int head, int rate,
59159687Snetchild	     int gaplen, int secsize, int fill,int interleave)
60159687Snetchild{
61159687Snetchild	struct fd_formb f;
62159687Snetchild	register int i,j;
63159687Snetchild	int il[FD_MAX_NSEC + 1];
64159687Snetchild
65159687Snetchild	memset(il,0,sizeof il);
66159687Snetchild	for(j = 0, i = 1; i <= secs; i++) {
67159687Snetchild	    while(il[(j%secs)+1]) j++;
68159687Snetchild	    il[(j%secs)+1] = i;
69159687Snetchild	    j += interleave;
70159687Snetchild	}
71159687Snetchild
72159687Snetchild	f.format_version = FD_FORMAT_VERSION;
73159687Snetchild	f.head = head;
74159687Snetchild	f.cyl = cyl;
75159687Snetchild	f.transfer_rate = rate;
76162874Snetchild
77159687Snetchild	f.fd_formb_secshift = secsize;
78159687Snetchild	f.fd_formb_nsecs = secs;
79159687Snetchild	f.fd_formb_gaplen = gaplen;
80159687Snetchild	f.fd_formb_fillbyte = fill;
81162874Snetchild	for(i = 0; i < secs; i++) {
82159687Snetchild		f.fd_formb_cylno(i) = cyl;
83159687Snetchild		f.fd_formb_headno(i) = head;
84159687Snetchild		f.fd_formb_secno(i) = il[i+1];
85159687Snetchild		f.fd_formb_secsize(i) = secsize;
86159687Snetchild	}
87159687Snetchild	if(ioctl(fd, FD_FORM, (caddr_t)&f) < 0)
88159687Snetchild		err(1, "ioctl(FD_FORM)");
89162874Snetchild}
90162874Snetchild
91162874Snetchildstatic int
92162874Snetchildverify_track(int fd, int track, int tracksize)
93162874Snetchild{
94162874Snetchild	static char *buf = 0;
95170031Sjoel	static int bufsz = 0;
96170031Sjoel	int fdopts = -1, ofdopts, rv = 0;
97170031Sjoel
98170031Sjoel	if (ioctl(fd, FD_GOPTS, &fdopts) < 0)
99170031Sjoel		warn("warning: ioctl(FD_GOPTS)");
100170031Sjoel	else {
101162874Snetchild		ofdopts = fdopts;
102159687Snetchild		fdopts |= FDOPT_NORETRY;
103162874Snetchild		(void)ioctl(fd, FD_SOPTS, &fdopts);
104162874Snetchild	}
105162874Snetchild
106159687Snetchild	if (bufsz < tracksize) {
107162874Snetchild		if (buf)
108159687Snetchild			free (buf);
109159687Snetchild		bufsz = tracksize;
110162874Snetchild		buf = 0;
111159687Snetchild	}
112159687Snetchild	if (! buf)
113162874Snetchild		buf = malloc (bufsz);
114159687Snetchild	if (! buf)
115159687Snetchild		errx(2, "out of memory");
116162874Snetchild	if (lseek (fd, (long) track*tracksize, 0) < 0)
117162874Snetchild		rv = -1;
118162874Snetchild	/* try twice reading it, without using the normal retrier */
119162874Snetchild	else if (read (fd, buf, tracksize) != tracksize
120162874Snetchild		 && read (fd, buf, tracksize) != tracksize)
121162874Snetchild		rv = -1;
122162874Snetchild	if(fdopts != -1)
123162874Snetchild		(void)ioctl(fd, FD_SOPTS, &ofdopts);
124162874Snetchild	return (rv);
125162874Snetchild}
126162874Snetchild
127159687Snetchildstatic const char *
128159687Snetchildmakename(const char *arg, const char *suffix)
129159687Snetchild{
130159687Snetchild	static char namebuff[20];	/* big enough for "/dev/fd0a"... */
131159687Snetchild
132159687Snetchild	memset(namebuff, 0, 20);
133159687Snetchild	if(*arg == '\0') /* ??? */
134159687Snetchild		return arg;
135159687Snetchild	if(*arg == '/')  /* do not convert absolute pathnames */
136159687Snetchild		return arg;
137159687Snetchild	strcpy(namebuff, _PATH_DEV);
138159687Snetchild	strncat(namebuff, arg, 3);
139162874Snetchild	strcat(namebuff, suffix);
140162874Snetchild	return namebuff;
141159687Snetchild}
142162874Snetchild
143159687Snetchildstatic void
144159687Snetchildusage (void)
145162874Snetchild{
146159687Snetchild	fprintf(stderr, "%s\n%s\n",
147162874Snetchild	"usage: fdformat [-y] [-q] [-n | -v] [-f #] [-c #] [-s #] [-h #]",
148159687Snetchild	"                [-r #] [-g #] [-i #] [-S #] [-F #] [-t #] devname");
149159687Snetchild	exit(2);
150159687Snetchild}
151162874Snetchild
152159689Snetchildstatic int
153159687Snetchildyes (void)
154159687Snetchild{
155159687Snetchild	char reply [256], *p;
156159687Snetchild
157162874Snetchild	reply[sizeof(reply)-1] = 0;
158159687Snetchild	for (;;) {
159159687Snetchild		fflush(stdout);
160159687Snetchild		if (! fgets (reply, sizeof(reply)-1, stdin))
161159687Snetchild			return (0);
162159687Snetchild		for (p=reply; *p==' ' || *p=='\t'; ++p)
163159687Snetchild			continue;
164159687Snetchild		if (*p=='y' || *p=='Y')
165159687Snetchild			return (1);
166162874Snetchild		if (*p=='n' || *p=='N' || *p=='\n' || *p=='\r')
167159687Snetchild			return (0);
168159687Snetchild		printf("Answer `yes' or `no': ");
169162874Snetchild	}
170159687Snetchild}
171159687Snetchild
172159687Snetchildint
173162874Snetchildmain(int argc, char **argv)
174159687Snetchild{
175159687Snetchild	int format = -1, cyls = -1, secs = -1, heads = -1, intleave = -1;
176159687Snetchild	int rate = -1, gaplen = -1, secsize = -1, steps = -1;
177159687Snetchild	int fill = 0xf6, quiet = 0, verify = 1, verify_only = 0, confirm = 0;
178159687Snetchild	int fd, c, i, track, error, tracks_per_dot, bytes_per_track, errs;
179159687Snetchild	int fdopts;
180159687Snetchild	const char *devname, *suffix;
181162874Snetchild	struct fd_type fdt;
182159687Snetchild#define MAXPRINTERRS 10
183159687Snetchild	struct fdc_status fdcs[MAXPRINTERRS];
184159687Snetchild
185159687Snetchild	while((c = getopt(argc, argv, "f:c:s:h:r:g:S:F:t:i:qyvn")) != -1)
186159687Snetchild		switch(c) {
187159687Snetchild		case 'f':	/* format in kilobytes */
188159687Snetchild			format = atoi(optarg);
189162874Snetchild			break;
190159687Snetchild
191159687Snetchild		case 'c':	/* # of cyls */
192159687Snetchild			cyls = atoi(optarg);
193159687Snetchild			break;
194159687Snetchild
195159687Snetchild		case 's':	/* # of secs per track */
196159687Snetchild			secs = atoi(optarg);
197162874Snetchild			break;
198159687Snetchild
199159687Snetchild		case 'h':	/* # of heads */
200159689Snetchild			heads = atoi(optarg);
201159687Snetchild			break;
202159687Snetchild
203159687Snetchild		case 'r':	/* transfer rate, kilobyte/sec */
204159687Snetchild			rate = atoi(optarg);
205162874Snetchild			break;
206159687Snetchild
207159687Snetchild		case 'g':	/* length of GAP3 to format with */
208162874Snetchild			gaplen = atoi(optarg);
209159687Snetchild			break;
210159687Snetchild
211162874Snetchild		case 'S':	/* sector size shift factor (1 << S)*128 */
212162874Snetchild			secsize = atoi(optarg);
213159687Snetchild			break;
214162874Snetchild
215159687Snetchild		case 'F':	/* fill byte, C-like notation allowed */
216162874Snetchild			fill = (int)strtol(optarg, (char **)0, 0);
217162874Snetchild			break;
218159687Snetchild
219162874Snetchild		case 't':	/* steps per track */
220159687Snetchild			steps = atoi(optarg);
221162874Snetchild			break;
222162874Snetchild
223162874Snetchild		case 'i':       /* interleave factor */
224162874Snetchild			intleave = atoi(optarg);
225162874Snetchild			break;
226162874Snetchild
227162874Snetchild		case 'q':
228162874Snetchild			quiet = 1;
229162874Snetchild			break;
230162874Snetchild
231162874Snetchild		case 'y':
232162874Snetchild			confirm = 1;
233162874Snetchild			break;
234162874Snetchild
235162874Snetchild		case 'n':
236162874Snetchild			verify = 0;
237162874Snetchild			break;
238162874Snetchild
239162874Snetchild		case 'v':
240162874Snetchild			verify = 1;
241188480Snetchild			verify_only = 1;
242170031Sjoel			break;
243170031Sjoel
244159687Snetchild		case '?': default:
245159687Snetchild			usage();
246159687Snetchild		}
247159687Snetchild
248162874Snetchild	if(optind != argc - 1)
249159687Snetchild		usage();
250159687Snetchild
251162874Snetchild	switch(format) {
252159687Snetchild	default:
253162874Snetchild		errx(2, "bad floppy size: %dK", format);
254159687Snetchild	case -1:   suffix = "";      break;
255162874Snetchild	case 360:  suffix = ".360";  break;
256162874Snetchild	case 640:  suffix = ".640";  break;
257159687Snetchild	case 720:  suffix = ".720";  break;
258162874Snetchild	case 800:  suffix = ".800";  break;
259162874Snetchild	case 820:  suffix = ".820";  break;
260162874Snetchild	case 1200: suffix = ".1200"; break;
261162874Snetchild	case 1232: suffix = ".1232"; break;
262162874Snetchild	case 1440: suffix = ".1440"; break;
263162874Snetchild	case 1480: suffix = ".1480"; break;
264162874Snetchild	case 1720: suffix = ".1720"; break;
265159687Snetchild	}
266159687Snetchild
267159687Snetchild	devname = makename(argv[optind], suffix);
268159687Snetchild
269162874Snetchild	if((fd = open(devname, O_RDWR)) < 0)
270159687Snetchild		err(1, "%s", devname);
271159687Snetchild
272162874Snetchild	if(ioctl(fd, FD_GTYPE, &fdt) < 0)
273159687Snetchild		errx(1, "not a floppy disk: %s", devname);
274159687Snetchild	fdopts = FDOPT_NOERRLOG;
275159687Snetchild	if (ioctl(fd, FD_SOPTS, &fdopts) == -1)
276170031Sjoel		err(1, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)");
277170031Sjoel
278162874Snetchild	switch(rate) {
279162874Snetchild	case -1:  break;
280162874Snetchild	case 250: fdt.trans = FDC_250KBPS; break;
281159687Snetchild	case 300: fdt.trans = FDC_300KBPS; break;
282162874Snetchild	case 500: fdt.trans = FDC_500KBPS; break;
283162874Snetchild	default:
284162874Snetchild		errx(2, "invalid transfer rate: %d", rate);
285162874Snetchild	}
286213779Srpaulo
287213779Srpaulo	if (cyls >= 0)    fdt.tracks = cyls;
288162874Snetchild	if (secs >= 0)    fdt.sectrac = secs;
289162874Snetchild	if (fdt.sectrac > FD_MAX_NSEC)
290162874Snetchild		errx(2, "too many sectors per track, max value is %d", FD_MAX_NSEC);
291162874Snetchild	if (heads >= 0)   fdt.heads = heads;
292162874Snetchild	if (gaplen >= 0)  fdt.f_gap = gaplen;
293159687Snetchild	if (secsize >= 0) fdt.secsize = secsize;
294170031Sjoel	if (steps >= 0)   fdt.steptrac = steps;
295170031Sjoel	if (intleave >= 0) fdt.f_inter = intleave;
296162874Snetchild
297162874Snetchild	bytes_per_track = fdt.sectrac * (1<<fdt.secsize) * 128;
298162874Snetchild
299159687Snetchild	/* XXX  20/40 = 0.5 */
300162874Snetchild	tracks_per_dot = (fdt.tracks * fdt.heads + 20) / 40;
301162874Snetchild
302162874Snetchild	if (verify_only) {
303162874Snetchild		if(!quiet)
304188480Snetchild			printf("Verify %dK floppy `%s'.\n",
305188480Snetchild				fdt.tracks * fdt.heads * bytes_per_track / 1024,
306162874Snetchild				devname);
307162874Snetchild	}
308162874Snetchild	else if(!quiet && !confirm) {
309162874Snetchild		printf("Format %dK floppy `%s'? (y/n): ",
310162874Snetchild			fdt.tracks * fdt.heads * bytes_per_track / 1024,
311162874Snetchild			devname);
312159687Snetchild		if(! yes ()) {
313162874Snetchild			printf("Not confirmed.\n");
314159687Snetchild			return 3;
315162874Snetchild		}
316162874Snetchild	}
317159687Snetchild
318162874Snetchild	/*
319159687Snetchild	 * Formatting.
320162874Snetchild	 */
321159687Snetchild	if(!quiet) {
322162874Snetchild		int i;
323162874Snetchild
324159687Snetchild		printf("Processing ");
325162874Snetchild		for (i = 0; i < (fdt.tracks * fdt.heads) / tracks_per_dot; i++)
326159687Snetchild			putchar('-');
327162874Snetchild		printf("\rProcessing ");
328159687Snetchild		fflush(stdout);
329162874Snetchild	}
330162874Snetchild
331159687Snetchild	error = errs = 0;
332162874Snetchild
333162874Snetchild	for (track = 0; track < fdt.tracks * fdt.heads; track++) {
334162874Snetchild		if (!verify_only) {
335162874Snetchild			format_track(fd, track / fdt.heads, fdt.sectrac,
336162874Snetchild				track % fdt.heads, fdt.trans, fdt.f_gap,
337162874Snetchild				fdt.secsize, fill, fdt.f_inter);
338162874Snetchild			if(!quiet && !((track + 1) % tracks_per_dot)) {
339162874Snetchild				putchar('F');
340162874Snetchild				fflush(stdout);
341162874Snetchild			}
342162874Snetchild		}
343162874Snetchild		if (verify) {
344162874Snetchild			if (verify_track(fd, track, bytes_per_track) < 0) {
345162874Snetchild				error = 1;
346162874Snetchild				if (errs < MAXPRINTERRS && errno == EIO) {
347162874Snetchild					if (ioctl(fd, FD_GSTAT, fdcs + errs) ==
348162874Snetchild					    -1)
349162874Snetchild						errx(1,
350162874Snetchild					"floppy IO error, but no FDC status");
351162874Snetchild					errs++;
352162874Snetchild				}
353162874Snetchild			}
354170031Sjoel			if(!quiet && !((track + 1) % tracks_per_dot)) {
355170031Sjoel				if (!verify_only)
356170031Sjoel					putchar('\b');
357170031Sjoel				if (error) {
358170031Sjoel					putchar('E');
359170031Sjoel					error = 0;
360170031Sjoel				}
361170031Sjoel				else
362159687Snetchild					putchar('V');
363159687Snetchild				fflush(stdout);
364159687Snetchild			}
365162874Snetchild		}
366162874Snetchild	}
367	if(!quiet)
368		printf(" done.\n");
369
370	if (!quiet && errs) {
371		fflush(stdout);
372		fprintf(stderr, "Errors encountered:\nCyl Head Sect   Error\n");
373		for (i = 0; i < errs && i < MAXPRINTERRS; i++) {
374			fprintf(stderr, " %2d   %2d   %2d   ",
375				fdcs[i].status[3], fdcs[i].status[4],
376				fdcs[i].status[5]);
377			printstatus(fdcs + i, 1);
378			putc('\n', stderr);
379		}
380		if (errs >= MAXPRINTERRS)
381			fprintf(stderr, "(Further errors not printed.)\n");
382	}
383
384	return errs != 0;
385}
386