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: releng/10.3/usr.sbin/fdformat/fdformat.c 218910 2011-02-21 09:56:08Z brucec $
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	}
78218910Sbrucec	(void)ioctl(fd, FD_FORM, (caddr_t)&f);
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;
148194892Sjoerg	int 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 */
207124200Sanholt		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 (format) {
25387992Sjoerg		getname(type, &name, &descr);
25487992Sjoerg		fdtp = get_fmt(format, type);
25587992Sjoerg		if (fdtp == 0)
25687992Sjoerg			errx(EX_USAGE,
25787992Sjoerg			    "unknown format %d KB for drive type %s",
25887992Sjoerg			     format, name);
25987992Sjoerg		fdt = *fdtp;
2601022Sache	}
26187992Sjoerg	if (fmtstring) {
26287992Sjoerg		parse_fmt(fmtstring, type, fdt, &newft);
26387992Sjoerg		fdt = newft;
26487992Sjoerg	}
265134081Sphk	if (ioctl(fd, FD_STYPE, &fdt) < 0)
266134081Sphk		err(EX_OSERR, "ioctl(FD_STYPE)");
26787992Sjoerg	if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
26887992Sjoerg		err(EX_OSERR, "fcntl(F_GETFL)");
26987992Sjoerg	flags &= ~O_NONBLOCK;
27087992Sjoerg	if (fcntl(fd, F_SETFL, flags) == -1)
27187992Sjoerg		err(EX_OSERR, "fcntl(F_SETFL)");
2721022Sache
27387992Sjoerg	bytes_per_track = fdt.sectrac * (128 << fdt.secsize);
2741022Sache
27555541Skato	/* XXX  20/40 = 0.5 */
27655541Skato	tracks_per_dot = (fdt.tracks * fdt.heads + 20) / 40;
27755541Skato
2781022Sache	if (verify_only) {
2791022Sache		if(!quiet)
2801022Sache			printf("Verify %dK floppy `%s'.\n",
2811022Sache				fdt.tracks * fdt.heads * bytes_per_track / 1024,
28279161Sjoerg				device);
2831022Sache	}
28461154Sphk	else if(!quiet && !confirm) {
2851022Sache		printf("Format %dK floppy `%s'? (y/n): ",
2861022Sache			fdt.tracks * fdt.heads * bytes_per_track / 1024,
28779161Sjoerg			device);
28887992Sjoerg		if(!yes()) {
2891022Sache			printf("Not confirmed.\n");
29087992Sjoerg			return (EX_UNAVAILABLE);
2911022Sache		}
2921022Sache	}
2931022Sache
2941022Sache	/*
2951022Sache	 * Formatting.
2961022Sache	 */
2971022Sache	if(!quiet) {
2981022Sache		printf("Processing ");
29955541Skato		for (i = 0; i < (fdt.tracks * fdt.heads) / tracks_per_dot; i++)
30055541Skato			putchar('-');
30155541Skato		printf("\rProcessing ");
3021022Sache		fflush(stdout);
3031022Sache	}
3041022Sache
3051022Sache	error = errs = 0;
3061022Sache
3071022Sache	for (track = 0; track < fdt.tracks * fdt.heads; track++) {
3081022Sache		if (!verify_only) {
3091183Srgrimes			format_track(fd, track / fdt.heads, fdt.sectrac,
3101183Srgrimes				track % fdt.heads, fdt.trans, fdt.f_gap,
31187992Sjoerg				fdt.secsize, fill, fdt.f_inter,
31287992Sjoerg				track % fdt.heads? fdt.offset_side2: 0);
3131022Sache			if(!quiet && !((track + 1) % tracks_per_dot)) {
3141022Sache				putchar('F');
3151022Sache				fflush(stdout);
3161022Sache			}
3171022Sache		}
3181022Sache		if (verify) {
31979111Sjoerg			if (verify_track(fd, track, bytes_per_track) < 0) {
32079111Sjoerg				error = 1;
32179111Sjoerg				if (errs < MAXPRINTERRS && errno == EIO) {
32279111Sjoerg					if (ioctl(fd, FD_GSTAT, fdcs + errs) ==
32379111Sjoerg					    -1)
32487992Sjoerg						errx(EX_IOERR,
32579111Sjoerg					"floppy IO error, but no FDC status");
32679111Sjoerg					errs++;
32779111Sjoerg				}
32879111Sjoerg			}
3291022Sache			if(!quiet && !((track + 1) % tracks_per_dot)) {
3301022Sache				if (!verify_only)
3311022Sache					putchar('\b');
3321022Sache				if (error) {
3331022Sache					putchar('E');
3341022Sache					error = 0;
3351022Sache				}
3361022Sache				else
3371022Sache					putchar('V');
3381022Sache				fflush(stdout);
3391022Sache			}
3401022Sache		}
3411022Sache	}
3421022Sache	if(!quiet)
3431022Sache		printf(" done.\n");
3441022Sache
34579111Sjoerg	if (!quiet && errs) {
34679111Sjoerg		fflush(stdout);
34779111Sjoerg		fprintf(stderr, "Errors encountered:\nCyl Head Sect   Error\n");
34879111Sjoerg		for (i = 0; i < errs && i < MAXPRINTERRS; i++) {
34979111Sjoerg			fprintf(stderr, " %2d   %2d   %2d   ",
35079111Sjoerg				fdcs[i].status[3], fdcs[i].status[4],
35179111Sjoerg				fdcs[i].status[5]);
35279111Sjoerg			printstatus(fdcs + i, 1);
35379111Sjoerg			putc('\n', stderr);
35479111Sjoerg		}
35579111Sjoerg		if (errs >= MAXPRINTERRS)
35679111Sjoerg			fprintf(stderr, "(Further errors not printed.)\n");
35779111Sjoerg	}
35879111Sjoerg
35979111Sjoerg	return errs != 0;
3601022Sache}
361