314 lines
8.2 KiB
C
314 lines
8.2 KiB
C
/* $NetBSD: fdformat.c,v 1.18 2021/11/27 22:16:41 rillig Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by John Kohl.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/*
|
|
* fdformat: format a floppy diskette, using interface provided in
|
|
* <sys/fdio.h>
|
|
*/
|
|
#include <sys/cdefs.h>
|
|
|
|
#ifndef lint
|
|
__RCSID("$NetBSD: fdformat.c,v 1.18 2021/11/27 22:16:41 rillig Exp $");
|
|
#endif
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/fdio.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include "pathnames.h"
|
|
|
|
static const char *fdb_array[2] = {_PATH_FLOPPYTAB, 0};
|
|
|
|
#define MASK_NBPS 0x0001
|
|
#define MASK_NCYL 0x0002
|
|
#define MASK_NSPT 0x0004
|
|
#define MASK_NTRK 0x0008
|
|
#define MASK_STEPSPERCYL 0x0010
|
|
#define MASK_GAPLEN 0x0020
|
|
#define MASK_FILLBYTE 0x0040
|
|
#define MASK_XFER_RATE 0x0080
|
|
#define MASK_INTERLEAVE 0x0100
|
|
|
|
#define ALLPARMS (MASK_NBPS|MASK_NCYL|MASK_NSPT|MASK_NTRK|MASK_STEPSPERCYL|MASK_GAPLEN|MASK_FILLBYTE|MASK_XFER_RATE|MASK_INTERLEAVE)
|
|
|
|
static int confirm(int);
|
|
static void usage(void) __dead;
|
|
static int verify_track(int, int, int, struct fdformat_parms *, char *);
|
|
|
|
static int
|
|
confirm(int def)
|
|
{
|
|
int ch;
|
|
|
|
(void)printf(" Yes/no [%c]?", def ? 'y' : 'n');
|
|
ch = getchar();
|
|
switch (ch) {
|
|
case 'y':
|
|
case 'Y':
|
|
return 1;
|
|
case '\n':
|
|
return def;
|
|
case EOF:
|
|
case 'n':
|
|
case 'N':
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int
|
|
verify_track(int fd, int cyl, int trk, struct fdformat_parms *parms, char *buf)
|
|
{
|
|
size_t tracksize;
|
|
off_t offset;
|
|
|
|
tracksize = parms->nbps * parms->nspt; /* bytes per track */
|
|
offset = tracksize * (cyl * parms->ntrk + trk); /* track offset */
|
|
|
|
if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
|
|
(void)printf("- SEEK ERROR\n");
|
|
return 1;
|
|
}
|
|
if ((size_t)read(fd, buf, tracksize) != tracksize) {
|
|
(void)printf("- VERIFY ERROR\n");
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
usage(void)
|
|
{
|
|
(void)fprintf(stderr,
|
|
"Usage: %s [-f device] [-t type] [-n] [-B nbps] [-S nspt]\n"
|
|
"\t[-T ntrk] [-C ncyl] [-P stepspercyl] [-G gaplen]\n"
|
|
"\t[-F fillbyte] [-X xfer_rate] [-I interleave]\n", getprogname());
|
|
exit(1);
|
|
}
|
|
|
|
#define numarg(which, maskn, op) \
|
|
do { \
|
|
tmplong = strtol(optarg, &tmpcharp, 0); \
|
|
if (*tmpcharp != '\0' || tmplong op 0) \
|
|
errx(1, \
|
|
"Invalid numerical argument `%s' for " \
|
|
# which, optarg); \
|
|
if (errno == ERANGE && (tmplong == LONG_MIN || \
|
|
tmplong == LONG_MAX)) \
|
|
err(1, \
|
|
"Bad numerical argument `%s' for " \
|
|
# which, optarg); \
|
|
parms.which = tmplong; \
|
|
parmmask |= MASK_##maskn; \
|
|
} while (0)
|
|
|
|
#define getparm(structname, maskname) \
|
|
do { \
|
|
if (cgetnum(fdbuf, # structname, &tmplong) == -1) \
|
|
errx(1, "Parameter " # structname \
|
|
" missing for type `%s'", optarg); \
|
|
parms.structname = tmplong; \
|
|
parmmask |= MASK_ ## maskname; \
|
|
} while (0)
|
|
|
|
|
|
#define copyparm(which, mask) \
|
|
if ((parmmask & MASK_##mask) == 0) \
|
|
parms.which = fetchparms.which
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
char *fdbuf = NULL, *trackbuf = NULL;
|
|
int errcnt = 0;
|
|
int verify = 1;
|
|
int ch;
|
|
long tmplong;
|
|
int tmpint;
|
|
char *tmpcharp;
|
|
int parmmask = 0;
|
|
struct fdformat_parms parms, fetchparms;
|
|
struct fdformat_cmd cmd;
|
|
const char *filename = _PATH_FLOPPY_DEV;
|
|
int fd;
|
|
int trk, cyl;
|
|
|
|
while ((ch = getopt(argc, argv, "f:t:nB:C:S:T:P:G:F:X:I:")) != -1)
|
|
switch (ch) {
|
|
case 't': /* disk type */
|
|
switch (cgetent(&fdbuf, fdb_array, optarg)) {
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
case -3:
|
|
errx(1, "tc= loop or missing entry entry in "
|
|
_PATH_FLOPPYTAB " for type %s", optarg);
|
|
break;
|
|
case -1:
|
|
errx(1, "Unknown floppy disk type %s", optarg);
|
|
break;
|
|
default:
|
|
err(1, "Problem accessing " _PATH_FLOPPYTAB);
|
|
break;
|
|
}
|
|
|
|
getparm(nbps, NBPS);
|
|
getparm(ncyl, NCYL);
|
|
getparm(nspt, NSPT);
|
|
getparm(ntrk, NTRK);
|
|
getparm(stepspercyl, STEPSPERCYL);
|
|
getparm(gaplen, GAPLEN);
|
|
getparm(fillbyte, FILLBYTE);
|
|
getparm(xfer_rate, XFER_RATE);
|
|
getparm(interleave, INTERLEAVE);
|
|
break;
|
|
case 'f': /* device name */
|
|
filename = optarg;
|
|
break;
|
|
case 'n': /* no verify */
|
|
verify = 0;
|
|
break;
|
|
case 'B':
|
|
numarg(nbps, NBPS, <=);
|
|
break;
|
|
case 'C':
|
|
numarg(ncyl, NCYL, <=);
|
|
break;
|
|
case 'S':
|
|
numarg(nspt, NSPT, <=);
|
|
break;
|
|
case 'T':
|
|
numarg(ntrk, NTRK, <=);
|
|
break;
|
|
case 'P':
|
|
numarg(stepspercyl, STEPSPERCYL, <=);
|
|
break;
|
|
case 'G':
|
|
numarg(gaplen, GAPLEN, <=);
|
|
break;
|
|
case 'F':
|
|
numarg(fillbyte, FILLBYTE, <);
|
|
break;
|
|
case 'X':
|
|
numarg(xfer_rate, XFER_RATE, <=);
|
|
break;
|
|
case 'I':
|
|
numarg(interleave, INTERLEAVE, <=);
|
|
break;
|
|
case '?':
|
|
default:
|
|
usage();
|
|
}
|
|
|
|
if (optind < argc)
|
|
usage();
|
|
|
|
fd = open(filename, O_RDWR);
|
|
if (fd == -1)
|
|
err(1, "Cannot open %s", filename);
|
|
if (ioctl(fd, FDIOCGETFORMAT, &fetchparms) == -1) {
|
|
if (errno == ENOTTY)
|
|
err(1, "Device `%s' does not support floppy formatting",
|
|
filename);
|
|
else
|
|
err(1, "Cannot fetch current floppy"
|
|
" formatting parameters");
|
|
}
|
|
|
|
copyparm(nbps, NBPS);
|
|
copyparm(ncyl, NCYL);
|
|
copyparm(nspt, NSPT);
|
|
copyparm(ntrk, NTRK);
|
|
copyparm(stepspercyl, STEPSPERCYL);
|
|
copyparm(gaplen, GAPLEN);
|
|
copyparm(fillbyte, FILLBYTE);
|
|
copyparm(xfer_rate, XFER_RATE);
|
|
copyparm(interleave, INTERLEAVE);
|
|
|
|
parms.fdformat_version = FDFORMAT_VERSION;
|
|
|
|
tmpint = FDOPT_NORETRY|FDOPT_SILENT;
|
|
if (ioctl(fd, FDIOCSETOPTS, &tmpint) == -1 ||
|
|
ioctl(fd, FDIOCSETFORMAT, &parms) == -1) {
|
|
errx(1, "Cannot set requested formatting parameters:"
|
|
" %d cylinders, %d tracks, %d sectors of %d bytes",
|
|
parms.ncyl, parms.ntrk, parms.nspt, parms.nbps);
|
|
}
|
|
|
|
(void)printf("Ready to format %s with %d cylinders, %d tracks,"
|
|
" %d sectors of %d bytes\n(%d KB)",
|
|
filename, parms.ncyl, parms.ntrk, parms.nspt, parms.nbps,
|
|
parms.ncyl * parms.ntrk * parms.nspt * parms.nbps / 1024);
|
|
if (!confirm(1))
|
|
errx(1,"Formatting abandoned -- not confirmed.");
|
|
|
|
if (verify) {
|
|
trackbuf = malloc(parms.nbps * parms.nspt);
|
|
if (trackbuf == NULL)
|
|
warn("Cannot allocate verification buffer");
|
|
}
|
|
|
|
cmd.formatcmd_version = FDFORMAT_VERSION;
|
|
for (cyl = 0; (unsigned int)cyl < parms.ncyl; cyl++) {
|
|
cmd.cylinder = cyl;
|
|
for (trk = 0; (unsigned int)trk < parms.ntrk; trk++) {
|
|
cmd.head = trk;
|
|
(void)printf("\rFormatting track %i / head %i ", cyl, trk);
|
|
(void)fflush(stdout);
|
|
if (ioctl(fd, FDIOCFORMAT_TRACK, &cmd) == 0) {
|
|
if (verify)
|
|
errcnt += verify_track(fd, cyl, trk,
|
|
&parms, trackbuf);
|
|
} else if (errno == EINVAL) {
|
|
(void)putchar('\n');
|
|
errx(1, "Formatting botch at <%d,%d>",
|
|
cyl, trk);
|
|
} else if (errno == EIO) {
|
|
(void)printf("- IO ERROR\n");
|
|
errcnt++;
|
|
}
|
|
}
|
|
}
|
|
(void)printf("\rFormatting %i tracks total complete.\n",
|
|
parms.ncyl * parms.ntrk);
|
|
if (errcnt)
|
|
errx(1, "%d track formatting error%s",
|
|
errcnt, errcnt == 1 ? "" : "s");
|
|
return 0;
|
|
}
|