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