fdformat.c revision 134081
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 134081 2004-08-20 15:14:25Z phk $
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>
4093590Smike#include <string.h>
4129531Scharnier#include <strings.h>
4287992Sjoerg#include <sysexits.h>
431022Sache#include <unistd.h>
441022Sache
4579111Sjoerg#include "fdutil.h"
4679111Sjoerg
471022Sachestatic void
481022Sacheformat_track(int fd, int cyl, int secs, int head, int rate,
4987992Sjoerg	     int gaplen, int secsize, int fill, int interleave,
5087992Sjoerg	     int offset)
511022Sache{
521022Sache	struct fd_formb f;
5387992Sjoerg	int i, j, il[FD_MAX_NSEC + 1];
541022Sache
5587992Sjoerg	memset(il, 0, sizeof il);
5687992Sjoerg	for(j = 0, i = 1 + offset; i <= secs + offset; i++) {
5787992Sjoerg	    while(il[(j % secs) + 1])
5887992Sjoerg		    j++;
5987992Sjoerg	    il[(j % secs) + 1] = i;
601137Sache	    j += interleave;
611137Sache	}
621137Sache
631022Sache	f.format_version = FD_FORMAT_VERSION;
641022Sache	f.head = head;
651022Sache	f.cyl = cyl;
661022Sache	f.transfer_rate = rate;
671022Sache
681022Sache	f.fd_formb_secshift = secsize;
691022Sache	f.fd_formb_nsecs = secs;
701022Sache	f.fd_formb_gaplen = gaplen;
711022Sache	f.fd_formb_fillbyte = fill;
721022Sache	for(i = 0; i < secs; i++) {
731022Sache		f.fd_formb_cylno(i) = cyl;
741022Sache		f.fd_formb_headno(i) = head;
751137Sache		f.fd_formb_secno(i) = il[i+1];
761022Sache		f.fd_formb_secsize(i) = secsize;
771022Sache	}
7829531Scharnier	if(ioctl(fd, FD_FORM, (caddr_t)&f) < 0)
7987992Sjoerg		err(EX_OSERR, "ioctl(FD_FORM)");
801022Sache}
811022Sache
821022Sachestatic int
831022Sacheverify_track(int fd, int track, int tracksize)
841022Sache{
8587992Sjoerg	static char *buf;
8687992Sjoerg	static int bufsz;
871533Sjoerg	int fdopts = -1, ofdopts, rv = 0;
881022Sache
891533Sjoerg	if (ioctl(fd, FD_GOPTS, &fdopts) < 0)
9029531Scharnier		warn("warning: ioctl(FD_GOPTS)");
911533Sjoerg	else {
921533Sjoerg		ofdopts = fdopts;
931533Sjoerg		fdopts |= FDOPT_NORETRY;
941533Sjoerg		(void)ioctl(fd, FD_SOPTS, &fdopts);
951533Sjoerg	}
968857Srgrimes
9787992Sjoerg	if (bufsz < tracksize)
9887992Sjoerg		buf = realloc(buf, bufsz = tracksize);
9987992Sjoerg	if (buf == 0)
10087992Sjoerg		errx(EX_UNAVAILABLE, "out of memory");
10187992Sjoerg	if (lseek (fd, (long) track * tracksize, 0) < 0)
1021533Sjoerg		rv = -1;
1031533Sjoerg	/* try twice reading it, without using the normal retrier */
1041533Sjoerg	else if (read (fd, buf, tracksize) != tracksize
1051533Sjoerg		 && read (fd, buf, tracksize) != tracksize)
1061533Sjoerg		rv = -1;
10787992Sjoerg	if (fdopts != -1)
1081533Sjoerg		(void)ioctl(fd, FD_SOPTS, &ofdopts);
1091533Sjoerg	return (rv);
1101022Sache}
1111022Sache
1121022Sachestatic void
1131533Sjoergusage (void)
1141022Sache{
11587992Sjoerg	errx(EX_USAGE,
11687992Sjoerg	     "usage: fdformat [-F fill] [-f fmt] [-s fmtstr] [-nqvy] device");
1171022Sache}
1181022Sache
1191022Sachestatic int
1201533Sjoergyes (void)
1211022Sache{
12287992Sjoerg	char reply[256], *p;
1231022Sache
12487992Sjoerg	reply[sizeof(reply) - 1] = 0;
1251022Sache	for (;;) {
1261022Sache		fflush(stdout);
12787992Sjoerg		if (!fgets (reply, sizeof(reply) - 1, stdin))
1281022Sache			return (0);
1291022Sache		for (p=reply; *p==' ' || *p=='\t'; ++p)
1301022Sache			continue;
1311022Sache		if (*p=='y' || *p=='Y')
1321022Sache			return (1);
1331022Sache		if (*p=='n' || *p=='N' || *p=='\n' || *p=='\r')
1341022Sache			return (0);
1351022Sache		printf("Answer `yes' or `no': ");
1361022Sache	}
1371022Sache}
1381022Sache
1391022Sacheint
1401022Sachemain(int argc, char **argv)
1411022Sache{
14287992Sjoerg	enum fd_drivetype type;
14387992Sjoerg	struct fd_type fdt, newft, *fdtp;
14487992Sjoerg	struct stat sb;
14579111Sjoerg#define MAXPRINTERRS 10
14679111Sjoerg	struct fdc_status fdcs[MAXPRINTERRS];
14787992Sjoerg	int format, fill, quiet, verify, verify_only, confirm;
14887992Sjoerg	int fd, c, i, track, error, tracks_per_dot, bytes_per_track, errs;
14987992Sjoerg	int fdopts, flags;
15087992Sjoerg	char *fmtstring, *device;
15187992Sjoerg	const char *name, *descr;
1521022Sache
15387992Sjoerg	format = quiet = verify_only = confirm = 0;
15487992Sjoerg	verify = 1;
15587992Sjoerg	fill = 0xf6;
15687992Sjoerg	fmtstring = 0;
15787992Sjoerg
15887992Sjoerg	while((c = getopt(argc, argv, "F:f:nqs:vy")) != -1)
1591022Sache		switch(c) {
16087992Sjoerg		case 'F':	/* fill byte */
16187992Sjoerg			if (getnum(optarg, &fill)) {
16287992Sjoerg				fprintf(stderr,
16387992Sjoerg			"Bad argument %s to -F option; must be numeric\n",
16487992Sjoerg					optarg);
16587992Sjoerg				usage();
16687992Sjoerg			}
1671022Sache			break;
1681022Sache
16987992Sjoerg		case 'f':	/* format in kilobytes */
17087992Sjoerg			if (getnum(optarg, &format)) {
17187992Sjoerg				fprintf(stderr,
17287992Sjoerg			"Bad argument %s to -f option; must be numeric\n",
17387992Sjoerg					optarg);
17487992Sjoerg				usage();
17587992Sjoerg			}
1761022Sache			break;
1771022Sache
17887992Sjoerg		case 'n':	/* don't verify */
17987992Sjoerg			verify = 0;
1801022Sache			break;
1811022Sache
18287992Sjoerg		case 'q':	/* quiet */
18387992Sjoerg			quiet = 1;
1841022Sache			break;
1851022Sache
18687992Sjoerg		case 's':	/* format string with detailed options */
18787992Sjoerg			fmtstring = optarg;
1881022Sache			break;
1891022Sache
19087992Sjoerg		case 'v':	/* verify only */
19187992Sjoerg			verify = 1;
19287992Sjoerg			verify_only = 1;
1931022Sache			break;
1941022Sache
19587992Sjoerg		case 'y':	/* confirm */
19661154Sphk			confirm = 1;
19761154Sphk			break;
19861154Sphk
19987992Sjoerg		default:
2001022Sache			usage();
2011022Sache		}
2021022Sache
2031022Sache	if(optind != argc - 1)
2041022Sache		usage();
2051022Sache
20687992Sjoerg	if (stat(argv[optind], &sb) == -1 && errno == ENOENT) {
20787992Sjoerg		/* try prepending _PATH_DEV */
208124200Sanholt		device = malloc(strlen(argv[optind]) + sizeof(_PATH_DEV) + 1);
20987992Sjoerg		if (device == 0)
21087992Sjoerg			errx(EX_UNAVAILABLE, "out of memory");
21187992Sjoerg		strcpy(device, _PATH_DEV);
21287992Sjoerg		strcat(device, argv[optind]);
21387992Sjoerg		if (stat(device, &sb) == -1) {
21487992Sjoerg			free(device);
21587992Sjoerg			device = argv[optind]; /* let it fail below */
21687992Sjoerg		}
21787992Sjoerg	} else {
21887992Sjoerg		device = argv[optind];
2191022Sache	}
2201022Sache
22187992Sjoerg	if ((fd = open(device, O_RDWR | O_NONBLOCK)) < 0)
22287992Sjoerg		err(EX_OSERR, "open(%s)", device);
2231022Sache
22487992Sjoerg	/*
22587992Sjoerg	 * Device initialization.
22687992Sjoerg	 *
22787992Sjoerg	 * First, get the device type descriptor.  This tells us about
22887992Sjoerg	 * the media geometry data we need to format a medium.  It also
22987992Sjoerg	 * lets us know quickly whether the device name actually points
23087992Sjoerg	 * to a floppy disk drive.
23187992Sjoerg	 *
23287992Sjoerg	 * Then, obtain any drive options.  We're mainly interested to
23387992Sjoerg	 * see whether we're currently working on a device with media
23487992Sjoerg	 * density autoselection (FDOPT_AUTOSEL).  Then, we add the
23587992Sjoerg	 * device option to tell the kernel not to log media errors,
23687992Sjoerg	 * since we can handle them ourselves.  If the device does
23787992Sjoerg	 * media density autoselection, we then need to set the device
23887992Sjoerg	 * type appropriately, since by opening with O_NONBLOCK we
23987992Sjoerg	 * told the driver to bypass media autoselection (otherwise we
24087992Sjoerg	 * wouldn't stand a chance to format an unformatted or damaged
24187992Sjoerg	 * medium).  We do not attempt to set the media type on any
24287992Sjoerg	 * other devices since this is a privileged operation.  For the
24387992Sjoerg	 * same reason, specifying -f and -s options is only possible
24487992Sjoerg	 * for autoselecting devices.
24587992Sjoerg	 *
24687992Sjoerg	 * Finally, we are ready to turn off O_NONBLOCK, and start to
24787992Sjoerg	 * actually format something.
24887992Sjoerg	 */
24929531Scharnier	if(ioctl(fd, FD_GTYPE, &fdt) < 0)
25087992Sjoerg		errx(EX_OSERR, "not a floppy disk: %s", device);
25187992Sjoerg	if (ioctl(fd, FD_GDTYPE, &type) == -1)
25287992Sjoerg		err(EX_OSERR, "ioctl(FD_GDTYPE)");
25387992Sjoerg	if (ioctl(fd, FD_GOPTS, &fdopts) == -1)
25487992Sjoerg		err(EX_OSERR, "ioctl(FD_GOPTS)");
25587992Sjoerg	fdopts |= FDOPT_NOERRLOG;
25678858Sjoerg	if (ioctl(fd, FD_SOPTS, &fdopts) == -1)
25787992Sjoerg		err(EX_OSERR, "ioctl(FD_SOPTS, FDOPT_NOERRLOG)");
25887992Sjoerg	if (format) {
25987992Sjoerg		getname(type, &name, &descr);
26087992Sjoerg		fdtp = get_fmt(format, type);
26187992Sjoerg		if (fdtp == 0)
26287992Sjoerg			errx(EX_USAGE,
26387992Sjoerg			    "unknown format %d KB for drive type %s",
26487992Sjoerg			     format, name);
26587992Sjoerg		fdt = *fdtp;
2661022Sache	}
26787992Sjoerg	if (fmtstring) {
26887992Sjoerg		parse_fmt(fmtstring, type, fdt, &newft);
26987992Sjoerg		fdt = newft;
27087992Sjoerg	}
271134081Sphk	if (ioctl(fd, FD_STYPE, &fdt) < 0)
272134081Sphk		err(EX_OSERR, "ioctl(FD_STYPE)");
27387992Sjoerg	if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
27487992Sjoerg		err(EX_OSERR, "fcntl(F_GETFL)");
27587992Sjoerg	flags &= ~O_NONBLOCK;
27687992Sjoerg	if (fcntl(fd, F_SETFL, flags) == -1)
27787992Sjoerg		err(EX_OSERR, "fcntl(F_SETFL)");
2781022Sache
27987992Sjoerg	bytes_per_track = fdt.sectrac * (128 << fdt.secsize);
2801022Sache
28155541Skato	/* XXX  20/40 = 0.5 */
28255541Skato	tracks_per_dot = (fdt.tracks * fdt.heads + 20) / 40;
28355541Skato
2841022Sache	if (verify_only) {
2851022Sache		if(!quiet)
2861022Sache			printf("Verify %dK floppy `%s'.\n",
2871022Sache				fdt.tracks * fdt.heads * bytes_per_track / 1024,
28879161Sjoerg				device);
2891022Sache	}
29061154Sphk	else if(!quiet && !confirm) {
2911022Sache		printf("Format %dK floppy `%s'? (y/n): ",
2921022Sache			fdt.tracks * fdt.heads * bytes_per_track / 1024,
29379161Sjoerg			device);
29487992Sjoerg		if(!yes()) {
2951022Sache			printf("Not confirmed.\n");
29687992Sjoerg			return (EX_UNAVAILABLE);
2971022Sache		}
2981022Sache	}
2991022Sache
3001022Sache	/*
3011022Sache	 * Formatting.
3021022Sache	 */
3031022Sache	if(!quiet) {
3041022Sache		printf("Processing ");
30555541Skato		for (i = 0; i < (fdt.tracks * fdt.heads) / tracks_per_dot; i++)
30655541Skato			putchar('-');
30755541Skato		printf("\rProcessing ");
3081022Sache		fflush(stdout);
3091022Sache	}
3101022Sache
3111022Sache	error = errs = 0;
3121022Sache
3131022Sache	for (track = 0; track < fdt.tracks * fdt.heads; track++) {
3141022Sache		if (!verify_only) {
3151183Srgrimes			format_track(fd, track / fdt.heads, fdt.sectrac,
3161183Srgrimes				track % fdt.heads, fdt.trans, fdt.f_gap,
31787992Sjoerg				fdt.secsize, fill, fdt.f_inter,
31887992Sjoerg				track % fdt.heads? fdt.offset_side2: 0);
3191022Sache			if(!quiet && !((track + 1) % tracks_per_dot)) {
3201022Sache				putchar('F');
3211022Sache				fflush(stdout);
3221022Sache			}
3231022Sache		}
3241022Sache		if (verify) {
32579111Sjoerg			if (verify_track(fd, track, bytes_per_track) < 0) {
32679111Sjoerg				error = 1;
32779111Sjoerg				if (errs < MAXPRINTERRS && errno == EIO) {
32879111Sjoerg					if (ioctl(fd, FD_GSTAT, fdcs + errs) ==
32979111Sjoerg					    -1)
33087992Sjoerg						errx(EX_IOERR,
33179111Sjoerg					"floppy IO error, but no FDC status");
33279111Sjoerg					errs++;
33379111Sjoerg				}
33479111Sjoerg			}
3351022Sache			if(!quiet && !((track + 1) % tracks_per_dot)) {
3361022Sache				if (!verify_only)
3371022Sache					putchar('\b');
3381022Sache				if (error) {
3391022Sache					putchar('E');
3401022Sache					error = 0;
3411022Sache				}
3421022Sache				else
3431022Sache					putchar('V');
3441022Sache				fflush(stdout);
3451022Sache			}
3461022Sache		}
3471022Sache	}
3481022Sache	if(!quiet)
3491022Sache		printf(" done.\n");
3501022Sache
35179111Sjoerg	if (!quiet && errs) {
35279111Sjoerg		fflush(stdout);
35379111Sjoerg		fprintf(stderr, "Errors encountered:\nCyl Head Sect   Error\n");
35479111Sjoerg		for (i = 0; i < errs && i < MAXPRINTERRS; i++) {
35579111Sjoerg			fprintf(stderr, " %2d   %2d   %2d   ",
35679111Sjoerg				fdcs[i].status[3], fdcs[i].status[4],
35779111Sjoerg				fdcs[i].status[5]);
35879111Sjoerg			printstatus(fdcs + i, 1);
35979111Sjoerg			putc('\n', stderr);
36079111Sjoerg		}
36179111Sjoerg		if (errs >= MAXPRINTERRS)
36279111Sjoerg			fprintf(stderr, "(Further errors not printed.)\n");
36379111Sjoerg	}
36479111Sjoerg
36579111Sjoerg	return errs != 0;
3661022Sache}
367