fdformat.c revision 87992
11022Sache/*
278858Sjoerg * Copyright (C) 1992-1994,2001 by Joerg Wunsch, Dresden
31022Sache * All rights reserved.
41022Sache *
51022Sache * Redistribution and use in source and binary forms, with or without
61022Sache * modification, are permitted provided that the following conditions
71022Sache * are met:
81022Sache * 1. Redistributions of source code must retain the above copyright
91022Sache *    notice, this list of conditions and the following disclaimer.
101022Sache * 2. Redistributions in binary form must reproduce the above copyright
111022Sache *    notice, this list of conditions and the following disclaimer in the
121022Sache *    documentation and/or other materials provided with the distribution.
131022Sache *
141533Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
151533Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
161533Sjoerg * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
171533Sjoerg * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
181533Sjoerg * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
191533Sjoerg * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
201533Sjoerg * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211533Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
221533Sjoerg * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
231533Sjoerg * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
241533Sjoerg * POSSIBILITY OF SUCH DAMAGE.
2555541Skato *
2655541Skato * $FreeBSD: head/usr.sbin/fdformat/fdformat.c 87992 2001-12-15 19:09:04Z joerg $
271022Sache */
281022Sache
2987992Sjoerg#include <sys/types.h>
3087992Sjoerg#include <sys/fdcio.h>
3187992Sjoerg#include <sys/stat.h>
321022Sache
3329531Scharnier#include <ctype.h>
3429531Scharnier#include <err.h>
3579111Sjoerg#include <errno.h>
3629531Scharnier#include <fcntl.h>
3769793Sobrien#include <paths.h>
381022Sache#include <stdio.h>
391022Sache#include <stdlib.h>
4029531Scharnier#include <strings.h>
4187992Sjoerg#include <sysexits.h>
421022Sache#include <unistd.h>
431022Sache
4479111Sjoerg#include "fdutil.h"
4579111Sjoerg
461022Sachestatic void
471022Sacheformat_track(int fd, int cyl, int secs, int head, int rate,
4887992Sjoerg	     int gaplen, int secsize, int fill, int interleave,
4987992Sjoerg	     int offset)
501022Sache{
511022Sache	struct fd_formb f;
5287992Sjoerg	int i, j, il[FD_MAX_NSEC + 1];
531022Sache
5487992Sjoerg	memset(il, 0, sizeof il);
5587992Sjoerg	for(j = 0, i = 1 + offset; i <= secs + offset; i++) {
5687992Sjoerg	    while(il[(j % secs) + 1])
5787992Sjoerg		    j++;
5887992Sjoerg	    il[(j % secs) + 1] = i;
591137Sache	    j += interleave;
601137Sache	}
611137Sache
621022Sache	f.format_version = FD_FORMAT_VERSION;
631022Sache	f.head = head;
641022Sache	f.cyl = cyl;
651022Sache	f.transfer_rate = rate;
661022Sache
671022Sache	f.fd_formb_secshift = secsize;
681022Sache	f.fd_formb_nsecs = secs;
691022Sache	f.fd_formb_gaplen = gaplen;
701022Sache	f.fd_formb_fillbyte = fill;
711022Sache	for(i = 0; i < secs; i++) {
721022Sache		f.fd_formb_cylno(i) = cyl;
731022Sache		f.fd_formb_headno(i) = head;
741137Sache		f.fd_formb_secno(i) = il[i+1];
751022Sache		f.fd_formb_secsize(i) = secsize;
761022Sache	}
7729531Scharnier	if(ioctl(fd, FD_FORM, (caddr_t)&f) < 0)
7887992Sjoerg		err(EX_OSERR, "ioctl(FD_FORM)");
791022Sache}
801022Sache
811022Sachestatic int
821022Sacheverify_track(int fd, int track, int tracksize)
831022Sache{
8487992Sjoerg	static char *buf;
8587992Sjoerg	static int bufsz;
861533Sjoerg	int fdopts = -1, ofdopts, rv = 0;
871022Sache
881533Sjoerg	if (ioctl(fd, FD_GOPTS, &fdopts) < 0)
8929531Scharnier		warn("warning: ioctl(FD_GOPTS)");
901533Sjoerg	else {
911533Sjoerg		ofdopts = fdopts;
921533Sjoerg		fdopts |= FDOPT_NORETRY;
931533Sjoerg		(void)ioctl(fd, FD_SOPTS, &fdopts);
941533Sjoerg	}
958857Srgrimes
9687992Sjoerg	if (bufsz < tracksize)
9787992Sjoerg		buf = realloc(buf, bufsz = tracksize);
9887992Sjoerg	if (buf == 0)
9987992Sjoerg		errx(EX_UNAVAILABLE, "out of memory");
10087992Sjoerg	if (lseek (fd, (long) track * tracksize, 0) < 0)
1011533Sjoerg		rv = -1;
1021533Sjoerg	/* try twice reading it, without using the normal retrier */
1031533Sjoerg	else if (read (fd, buf, tracksize) != tracksize
1041533Sjoerg		 && read (fd, buf, tracksize) != tracksize)
1051533Sjoerg		rv = -1;
10687992Sjoerg	if (fdopts != -1)
1071533Sjoerg		(void)ioctl(fd, FD_SOPTS, &ofdopts);
1081533Sjoerg	return (rv);
1091022Sache}
1101022Sache
1111022Sachestatic void
1121533Sjoergusage (void)
1131022Sache{
11487992Sjoerg	errx(EX_USAGE,
11587992Sjoerg	     "usage: fdformat [-F fill] [-f fmt] [-s fmtstr] [-nqvy] device");
1161022Sache}
1171022Sache
1181022Sachestatic int
1191533Sjoergyes (void)
1201022Sache{
12187992Sjoerg	char reply[256], *p;
1221022Sache
12387992Sjoerg	reply[sizeof(reply) - 1] = 0;
1241022Sache	for (;;) {
1251022Sache		fflush(stdout);
12687992Sjoerg		if (!fgets (reply, sizeof(reply) - 1, stdin))
1271022Sache			return (0);
1281022Sache		for (p=reply; *p==' ' || *p=='\t'; ++p)
1291022Sache			continue;
1301022Sache		if (*p=='y' || *p=='Y')
1311022Sache			return (1);
1321022Sache		if (*p=='n' || *p=='N' || *p=='\n' || *p=='\r')
1331022Sache			return (0);
1341022Sache		printf("Answer `yes' or `no': ");
1351022Sache	}
1361022Sache}
1371022Sache
1381022Sacheint
1391022Sachemain(int argc, char **argv)
1401022Sache{
14187992Sjoerg	enum fd_drivetype type;
14287992Sjoerg	struct fd_type fdt, newft, *fdtp;
14387992Sjoerg	struct stat sb;
14479111Sjoerg#define MAXPRINTERRS 10
14579111Sjoerg	struct fdc_status fdcs[MAXPRINTERRS];
14687992Sjoerg	int format, fill, quiet, verify, verify_only, confirm;
14787992Sjoerg	int fd, c, i, track, error, tracks_per_dot, bytes_per_track, errs;
14887992Sjoerg	int fdopts, flags;
14987992Sjoerg	char *fmtstring, *device;
15087992Sjoerg	const char *name, *descr;
1511022Sache
15287992Sjoerg	format = quiet = verify_only = confirm = 0;
15387992Sjoerg	verify = 1;
15487992Sjoerg	fill = 0xf6;
15587992Sjoerg	fmtstring = 0;
15687992Sjoerg
15787992Sjoerg	while((c = getopt(argc, argv, "F:f:nqs:vy")) != -1)
1581022Sache		switch(c) {
15987992Sjoerg		case 'F':	/* fill byte */
16087992Sjoerg			if (getnum(optarg, &fill)) {
16187992Sjoerg				fprintf(stderr,
16287992Sjoerg			"Bad argument %s to -F option; must be numeric\n",
16387992Sjoerg					optarg);
16487992Sjoerg				usage();
16587992Sjoerg			}
1661022Sache			break;
1671022Sache
16887992Sjoerg		case 'f':	/* format in kilobytes */
16987992Sjoerg			if (getnum(optarg, &format)) {
17087992Sjoerg				fprintf(stderr,
17187992Sjoerg			"Bad argument %s to -f option; must be numeric\n",
17287992Sjoerg					optarg);
17387992Sjoerg				usage();
17487992Sjoerg			}
1751022Sache			break;
1761022Sache
17787992Sjoerg		case 'n':	/* don't verify */
17887992Sjoerg			verify = 0;
1791022Sache			break;
1801022Sache
18187992Sjoerg		case 'q':	/* quiet */
18287992Sjoerg			quiet = 1;
1831022Sache			break;
1841022Sache
18587992Sjoerg		case 's':	/* format string with detailed options */
18687992Sjoerg			fmtstring = optarg;
1871022Sache			break;
1881022Sache
18987992Sjoerg		case 'v':	/* verify only */
19087992Sjoerg			verify = 1;
19187992Sjoerg			verify_only = 1;
1921022Sache			break;
1931022Sache
19487992Sjoerg		case 'y':	/* confirm */
19561154Sphk			confirm = 1;
19661154Sphk			break;
19761154Sphk
19887992Sjoerg		default:
1991022Sache			usage();
2001022Sache		}
2011022Sache
2021022Sache	if(optind != argc - 1)
2031022Sache		usage();
2041022Sache
20587992Sjoerg	if (stat(argv[optind], &sb) == -1 && errno == ENOENT) {
20687992Sjoerg		/* try prepending _PATH_DEV */
20787992Sjoerg		device = malloc(strlen(argv[optind] + sizeof _PATH_DEV + 1));
20887992Sjoerg		if (device == 0)
20987992Sjoerg			errx(EX_UNAVAILABLE, "out of memory");
21087992Sjoerg		strcpy(device, _PATH_DEV);
21187992Sjoerg		strcat(device, argv[optind]);
21287992Sjoerg		if (stat(device, &sb) == -1) {
21387992Sjoerg			free(device);
21487992Sjoerg			device = argv[optind]; /* let it fail below */
21587992Sjoerg		}
21687992Sjoerg	} else {
21787992Sjoerg		device = argv[optind];
2181022Sache	}
2191022Sache
22087992Sjoerg	if ((fd = open(device, O_RDWR | O_NONBLOCK)) < 0)
22187992Sjoerg		err(EX_OSERR, "open(%s)", device);
2221022Sache
22387992Sjoerg	/*
22487992Sjoerg	 * Device initialization.
22587992Sjoerg	 *
22687992Sjoerg	 * First, get the device type descriptor.  This tells us about
22787992Sjoerg	 * the media geometry data we need to format a medium.  It also
22887992Sjoerg	 * lets us know quickly whether the device name actually points
22987992Sjoerg	 * to a floppy disk drive.
23087992Sjoerg	 *
23187992Sjoerg	 * Then, obtain any drive options.  We're mainly interested to
23287992Sjoerg	 * see whether we're currently working on a device with media
23387992Sjoerg	 * density autoselection (FDOPT_AUTOSEL).  Then, we add the
23487992Sjoerg	 * device option to tell the kernel not to log media errors,
23587992Sjoerg	 * since we can handle them ourselves.  If the device does
23687992Sjoerg	 * media density autoselection, we then need to set the device
23787992Sjoerg	 * type appropriately, since by opening with O_NONBLOCK we
23887992Sjoerg	 * told the driver to bypass media autoselection (otherwise we
23987992Sjoerg	 * wouldn't stand a chance to format an unformatted or damaged
24087992Sjoerg	 * medium).  We do not attempt to set the media type on any
24187992Sjoerg	 * other devices since this is a privileged operation.  For the
24287992Sjoerg	 * same reason, specifying -f and -s options is only possible
24387992Sjoerg	 * for autoselecting devices.
24487992Sjoerg	 *
24587992Sjoerg	 * Finally, we are ready to turn off O_NONBLOCK, and start to
24687992Sjoerg	 * actually format something.
24787992Sjoerg	 */
24829531Scharnier	if(ioctl(fd, FD_GTYPE, &fdt) < 0)
24987992Sjoerg		errx(EX_OSERR, "not a floppy disk: %s", device);
25087992Sjoerg	if (ioctl(fd, FD_GDTYPE, &type) == -1)
25187992Sjoerg		err(EX_OSERR, "ioctl(FD_GDTYPE)");
25287992Sjoerg	if (ioctl(fd, FD_GOPTS, &fdopts) == -1)
25387992Sjoerg		err(EX_OSERR, "ioctl(FD_GOPTS)");
25487992Sjoerg	fdopts |= FDOPT_NOERRLOG;
25578858Sjoerg	if (ioctl(fd, FD_SOPTS, &fdopts) == -1)
25687992Sjoerg		err(EX_OSERR, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)");
25787992Sjoerg	if (format) {
25887992Sjoerg		getname(type, &name, &descr);
25987992Sjoerg		fdtp = get_fmt(format, type);
26087992Sjoerg		if (fdtp == 0)
26187992Sjoerg			errx(EX_USAGE,
26287992Sjoerg			    "unknown format %d KB for drive type %s",
26387992Sjoerg			     format, name);
26487992Sjoerg		fdt = *fdtp;
2651022Sache	}
26687992Sjoerg	if (fmtstring) {
26787992Sjoerg		parse_fmt(fmtstring, type, fdt, &newft);
26887992Sjoerg		fdt = newft;
26987992Sjoerg	}
27087992Sjoerg	if (fdopts & FDOPT_AUTOSEL) {
27187992Sjoerg		if (ioctl(fd, FD_STYPE, &fdt) < 0)
27287992Sjoerg			err(EX_OSERR, "ioctl(FD_STYPE)");
27387992Sjoerg	} else if (fmtstring || format) {
27487992Sjoerg		errx(EX_USAGE,
27587992Sjoerg	     "-f fmt or -s fmtstr is only allowed for autoselecting devices");
27687992Sjoerg	}
27787992Sjoerg	if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
27887992Sjoerg		err(EX_OSERR, "fcntl(F_GETFL)");
27987992Sjoerg	flags &= ~O_NONBLOCK;
28087992Sjoerg	if (fcntl(fd, F_SETFL, flags) == -1)
28187992Sjoerg		err(EX_OSERR, "fcntl(F_SETFL)");
2821022Sache
28387992Sjoerg	bytes_per_track = fdt.sectrac * (128 << fdt.secsize);
2841022Sache
28555541Skato	/* XXX  20/40 = 0.5 */
28655541Skato	tracks_per_dot = (fdt.tracks * fdt.heads + 20) / 40;
28755541Skato
2881022Sache	if (verify_only) {
2891022Sache		if(!quiet)
2901022Sache			printf("Verify %dK floppy `%s'.\n",
2911022Sache				fdt.tracks * fdt.heads * bytes_per_track / 1024,
29279161Sjoerg				device);
2931022Sache	}
29461154Sphk	else if(!quiet && !confirm) {
2951022Sache		printf("Format %dK floppy `%s'? (y/n): ",
2961022Sache			fdt.tracks * fdt.heads * bytes_per_track / 1024,
29779161Sjoerg			device);
29887992Sjoerg		if(!yes()) {
2991022Sache			printf("Not confirmed.\n");
30087992Sjoerg			return (EX_UNAVAILABLE);
3011022Sache		}
3021022Sache	}
3031022Sache
3041022Sache	/*
3051022Sache	 * Formatting.
3061022Sache	 */
3071022Sache	if(!quiet) {
3081022Sache		printf("Processing ");
30955541Skato		for (i = 0; i < (fdt.tracks * fdt.heads) / tracks_per_dot; i++)
31055541Skato			putchar('-');
31155541Skato		printf("\rProcessing ");
3121022Sache		fflush(stdout);
3131022Sache	}
3141022Sache
3151022Sache	error = errs = 0;
3161022Sache
3171022Sache	for (track = 0; track < fdt.tracks * fdt.heads; track++) {
3181022Sache		if (!verify_only) {
3191183Srgrimes			format_track(fd, track / fdt.heads, fdt.sectrac,
3201183Srgrimes				track % fdt.heads, fdt.trans, fdt.f_gap,
32187992Sjoerg				fdt.secsize, fill, fdt.f_inter,
32287992Sjoerg				track % fdt.heads? fdt.offset_side2: 0);
3231022Sache			if(!quiet && !((track + 1) % tracks_per_dot)) {
3241022Sache				putchar('F');
3251022Sache				fflush(stdout);
3261022Sache			}
3271022Sache		}
3281022Sache		if (verify) {
32979111Sjoerg			if (verify_track(fd, track, bytes_per_track) < 0) {
33079111Sjoerg				error = 1;
33179111Sjoerg				if (errs < MAXPRINTERRS && errno == EIO) {
33279111Sjoerg					if (ioctl(fd, FD_GSTAT, fdcs + errs) ==
33379111Sjoerg					    -1)
33487992Sjoerg						errx(EX_IOERR,
33579111Sjoerg					"floppy IO error, but no FDC status");
33679111Sjoerg					errs++;
33779111Sjoerg				}
33879111Sjoerg			}
3391022Sache			if(!quiet && !((track + 1) % tracks_per_dot)) {
3401022Sache				if (!verify_only)
3411022Sache					putchar('\b');
3421022Sache				if (error) {
3431022Sache					putchar('E');
3441022Sache					error = 0;
3451022Sache				}
3461022Sache				else
3471022Sache					putchar('V');
3481022Sache				fflush(stdout);
3491022Sache			}
3501022Sache		}
3511022Sache	}
3521022Sache	if(!quiet)
3531022Sache		printf(" done.\n");
3541022Sache
35579111Sjoerg	if (!quiet && errs) {
35679111Sjoerg		fflush(stdout);
35779111Sjoerg		fprintf(stderr, "Errors encountered:\nCyl Head Sect   Error\n");
35879111Sjoerg		for (i = 0; i < errs && i < MAXPRINTERRS; i++) {
35979111Sjoerg			fprintf(stderr, " %2d   %2d   %2d   ",
36079111Sjoerg				fdcs[i].status[3], fdcs[i].status[4],
36179111Sjoerg				fdcs[i].status[5]);
36279111Sjoerg			printstatus(fdcs + i, 1);
36379111Sjoerg			putc('\n', stderr);
36479111Sjoerg		}
36579111Sjoerg		if (errs >= MAXPRINTERRS)
36679111Sjoerg			fprintf(stderr, "(Further errors not printed.)\n");
36779111Sjoerg	}
36879111Sjoerg
36979111Sjoerg	return errs != 0;
3701022Sache}
371