diff options
Diffstat (limited to 'usr.sbin/fdread')
| -rw-r--r-- | usr.sbin/fdread/Makefile | 5 | ||||
| -rw-r--r-- | usr.sbin/fdread/Makefile.depend | 15 | ||||
| -rw-r--r-- | usr.sbin/fdread/fdread.1 | 231 | ||||
| -rw-r--r-- | usr.sbin/fdread/fdread.c | 334 | ||||
| -rw-r--r-- | usr.sbin/fdread/fdutil.c | 484 | ||||
| -rw-r--r-- | usr.sbin/fdread/fdutil.h | 37 | 
6 files changed, 1106 insertions, 0 deletions
| diff --git a/usr.sbin/fdread/Makefile b/usr.sbin/fdread/Makefile new file mode 100644 index 000000000000..c7cfce78cef5 --- /dev/null +++ b/usr.sbin/fdread/Makefile @@ -0,0 +1,5 @@ +PACKAGE= fd +PROG=	fdread +SRCS=	fdread.c fdutil.c + +.include <bsd.prog.mk> diff --git a/usr.sbin/fdread/Makefile.depend b/usr.sbin/fdread/Makefile.depend new file mode 100644 index 000000000000..6ef78fac5cbf --- /dev/null +++ b/usr.sbin/fdread/Makefile.depend @@ -0,0 +1,15 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ +	include \ +	include/xlocale \ +	lib/${CSU_DIR} \ +	lib/libc \ +	lib/libcompiler_rt \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/usr.sbin/fdread/fdread.1 b/usr.sbin/fdread/fdread.1 new file mode 100644 index 000000000000..c0036906bee6 --- /dev/null +++ b/usr.sbin/fdread/fdread.1 @@ -0,0 +1,231 @@ +.\" +.\" Copyright (c) 2001 Joerg Wunsch +.\" +.\" All rights reserved. +.\" +.\" 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 DEVELOPERS ``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 DEVELOPERS 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. +.\" +.\" +.Dd May 14, 2001 +.Dt FDREAD 1 +.Os +.Sh NAME +.Nm fdread +.Nd read floppy disks +.Sh SYNOPSIS +.Nm +.Op Fl qr +.Op Fl d Ar device +.Op Fl f Ar fillbyte +.Op Fl o Ar file +.Nm +.Op Fl d Ar device +.Fl I Ar numsects +.Op Fl t Ar trackno +.Sh DESCRIPTION +The +.Nm +utility reads floppy disks. +Effective read blocking based on the track +size is performed, and floppy-specific error recovery of otherwise +bad blocks can be enabled. +.Pp +The +.Nm +utility +will always read an entire floppy medium, and write its contents to +the respective output file. +Unlike other tools like +.Xr dd 1 , +.Nm +automatically uses a read block size that is more efficient than +reading single blocks (usually one track of data at a time), but +falls back to reading single floppy sectors in case of an input/output +error occurred, in order to obtain as much valid data as possible. +While +.Nm +is working, kernel error reporting for floppy errors is turned off, so +the console and/or syslog are not flooded with kernel error messages. +.Pp +The +.Nm +utility accepts the following options: +.Bl -tag -width indent +.It Fl q +Turn on quiet mode. +By default, the medium parameters of the device +are being written to standard error output, progress will be indicated +by the approximate number of kilobytes read so far, and errors will be +printed out in detail, including the information about the location of +recovered data in the output. +In quiet mode, none of these messages +will be generated. +.It Fl r +Enable error recovery. +By default, +.Nm +stops after the first unrecovered read error, much like +.Xr dd 1 +does. +In recovery mode, however, one of two recovery actions will be +taken: +.Bl -bullet +.It +If the error was a CRC error in the data field, the +kernel is told to ignore the error, and data are transferred to the +output file anyway. +.Bf -emphasis +Note that this will cause the erroneous data +to be included in the output file! +.Ef +Still, this is the best recovery action that can be taken at all. +.It +All other errors are really fatal (usually, the FDC did not find the +sector ID fields), thus a dummy block with fill +bytes will be included in the output file. +.El +.Pp +Unless operating in quiet mode, the action taken and the location of +the error in the output file will be displayed. +.It Fl d Ar device +Specify the input floppy device, defaulting to +.Pa /dev/fd0 . +The parameter +.Ar device +must be a valid floppy disk device. +.It Fl f Ar fillbyte +Value of the fill byte used for dummy blocks in the output file in +recovery mode. +Defaults to +.Ql 0xf0 . +(Mnemonic: +.Dq foo . ) +The value can be specified using the usual C language notation of +the number base. +.It Fl o Ar file +Specify the output file to be +.Ar file . +By default, the data will be written to standard output. +.It Fl I Ar numsects +Read +.Ar numsects +sector ID fields, and write out their contents to standard output. +Each sector ID field contains recorded values for the cylinder number +.Pq Ql C , +the head number +.Pq Ql H , +the record number (sector number starting with 1) +.Pq Ql R , +and the +.Em sector shift value +(0 = 128 bytes, 1 = 256 bytes, 2 = 512 bytes, 3 = 1024 bytes) +.Pq Ql N . +The +.Fl I +option is mutually exclusive with all other options except +.Fl d Ar device +and +.Fl t Ar trackno . +.It Fl t Ar trackno +Specify the track number (cylinder number * number of heads + head +number) to read the sector ID fields from; only allowed together with +the +.Fl I Ar numsects +option. +.El +.Sh FILES +.Bl -tag -width /dev/fd0 +.It Pa /dev/fd0 +Default device to read from. +.El +.Sh EXIT STATUS +The +.Nm +utility sets the exit value according to +.Xr sysexits 3 . +In recovery mode, the exit value will be set to +.Dv EX_IOERR +if any error occurred during processing (even in quiet mode). +.Sh DIAGNOSTICS +Unless running in quiet mode, upon encountering an error, the status +of the floppy disc controller (FDC) will be printed out, both in +hexadecimal form, followed by a textual description that translates +those values into a human-readable form for the most common error +cases that can happen in a PC environment. +.Pp +The FDC error status includes the three FDC status registers +.Ql ST0 , +.Ql ST1 , +and +.Ql ST2 , +as well as the location of the error (physical cylinder, head, and sector +number, plus the +.Dq sector shift value , +respectively). +See the manual for the NE765 or compatible for details +about the status register contents. +.Pp +The FDC's status is then examined to determine whether the error is +deemed to be recoverable. +If error recovery was requested, the +location of the bad block in the output file is indicated by its +(hexadecimal) bounds. +Also, a summary line indicating the total number +of transfer errors will be printed before exiting. +.Sh SEE ALSO +.Xr dd 1 , +.Xr fdwrite 1 , +.Xr sysexits 3 , +.Xr fdc 4 , +.Xr fdcontrol 8 +.Sh HISTORY +The +.Nm +utility was written mainly to provide a means of recovering at least some of +the data on bad media, and to obviate the need to invoke +.Xr dd 1 +with too many hard to memorize options that might be useful to handle +a floppy. +.Pp +The command appeared in +.Fx 5.0 . +.Sh AUTHORS +Program and man page by +.An J\(:org Wunsch . +.Sh BUGS +Concurrent traffic on the second floppy drive located at the same FDC +will make error recovery attempts pointless, since the FDC status +obtained after a read error occurred cannot be guaranteed to actually +belong to the erroneous transfer. +Thus using option +.Fl r +is only reliable if +.Ar device +is the only active drive on that controller. +.Pp +No attempt beyond the floppy error retry mechanism of +.Xr fdc 4 +is made in order to see whether bad sectors could still be read +without errors by trying multiple times. +.Pp +Bits that are (no longer) available on the floppy medium cannot be +guessed by +.Nm . diff --git a/usr.sbin/fdread/fdread.c b/usr.sbin/fdread/fdread.c new file mode 100644 index 000000000000..ee8548699783 --- /dev/null +++ b/usr.sbin/fdread/fdread.c @@ -0,0 +1,334 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2001 Joerg Wunsch + * + * All rights reserved. + * + * 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 DEVELOPERS ``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 DEVELOPERS 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. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/fdcio.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> + +#include <dev/ic/nec765.h> + +#include "fdutil.h" + +static int	quiet, recover; +static unsigned char fillbyte = 0xf0;	/* "foo" */ + +static int	doread(int fd, FILE *of, const char *_devname); +static int	doreadid(int fd, unsigned int numids, unsigned int trackno); +static void	usage(void); + +static void +usage(void) +{ + +	errx(EX_USAGE, +	     "usage: fdread [-qr] [-d device] [-f fillbyte]\n" +	     "       fdread [-d device] -I numids [-t trackno]"); +} + + +int +main(int argc, char **argv) +{ +	int c, errs = 0; +	unsigned int numids = 0, trackno = 0; +	const char *fname = 0, *_devname = "/dev/fd0"; +	char *cp; +	FILE *of = stdout; +	int fd; +	unsigned long ul; + +	while ((c = getopt(argc, argv, "d:f:I:o:qrt:")) != -1) +		switch (c) { +		case 'd': +			_devname = optarg; +			break; + +		case 'f': +			ul = strtoul(optarg, &cp, 0); +			if (*cp != '\0') { +				fprintf(stderr, +			"Bad argument %s to -f option; must be numeric\n", +					optarg); +				usage(); +			} +			if (ul > 0xff) +				warnx( +			"Warning: fillbyte %#lx too large, truncating\n", +				      ul); +			fillbyte = ul & 0xff; +			break; + +		case 'I': +			ul = strtoul(optarg, &cp, 0); +			if (*cp != '\0') { +				fprintf(stderr, +			"Bad argument %s to -I option; must be numeric\n", +					optarg); +				usage(); +			} +			numids = ul; +			break; + +		case 'o': +			fname = optarg; +			break; + +		case 'q': +			quiet++; +			break; + +		case 'r': +			recover++; +			break; + +		case 't': +			ul = strtoul(optarg, &cp, 0); +			if (*cp != '\0') { +				fprintf(stderr, +			"Bad argument %s to -t option; must be numeric\n", +					optarg); +				usage(); +			} +			trackno = ul; +			break; + +		default: +			errs++; +		} +	argc -= optind; +	argv += optind; + +	if (argc != 0 || errs) +		usage(); +	/* check for mutually exclusive options */ +	if (numids) { +		if (fname || quiet || recover) +			usage(); +	} else { +		if (trackno) +			usage(); +	} + +	if (fname) { +		if ((of = fopen(fname, "w")) == NULL) +			err(EX_OSERR, "cannot create output file %s", fname); +	} + +	if ((fd = open(_devname, O_RDONLY)) == -1) +		err(EX_OSERR, "cannot open device %s", _devname); + +	return (numids? doreadid(fd, numids, trackno): doread(fd, of, _devname)); +} + +static int +doread(int fd, FILE *of, const char *_devname) +{ +	char *trackbuf; +	int rv, fdopts, recoverable, nerrs = 0; +	unsigned int nbytes, tracksize, mediasize, secsize, n; +	struct fdc_status fdcs; +	struct fd_type fdt; + +	if (ioctl(fd, FD_GTYPE, &fdt) == -1) +		err(EX_OSERR, "ioctl(FD_GTYPE) failed -- not a floppy?"); + +	secsize = 128 << fdt.secsize; +	tracksize = fdt.sectrac * secsize; +	mediasize = tracksize * fdt.tracks * fdt.heads; +	if ((trackbuf = malloc(tracksize)) == NULL) +		errx(EX_TEMPFAIL, "out of memory"); + +	if (!quiet) +		fprintf(stderr, "Reading %d * %d * %d * %d medium at %s\n", +			fdt.tracks, fdt.heads, fdt.sectrac, secsize, _devname); + +	for (nbytes = 0; nbytes < mediasize;) { +		if (lseek(fd, nbytes, SEEK_SET) != nbytes) +			err(EX_OSERR, "cannot lseek()"); +		rv = read(fd, trackbuf, tracksize); +		if (rv == 0) { +			/* EOF? */ +			warnx("premature EOF after %u bytes", nbytes); +			free(trackbuf); +			return (EX_OK); +		} +		if ((unsigned)rv == tracksize) { +			nbytes += rv; +			if (!quiet) +				fprintf(stderr, "%5d KB\r", nbytes / 1024); +			fwrite(trackbuf, sizeof(unsigned char), rv, of); +			fflush(of); +			continue; +		} +		if (rv == -1) { +			/* fall back reading one sector at a time */ +			for (n = 0; n < tracksize; n += secsize) { +				if (lseek(fd, nbytes, SEEK_SET) != nbytes) +					err(EX_OSERR, "cannot lseek()"); +				rv = read(fd, trackbuf, secsize); +				if ((unsigned) rv == secsize) { +					nbytes += rv; +					if (!quiet) +						fprintf(stderr, "%5d KB\r", +							nbytes / 1024); +					fwrite(trackbuf, sizeof(unsigned char), +					       rv, of); +					fflush(of); +					continue; +				} +				if (rv == -1) { +					if (errno != EIO) { +						if (!quiet) +							putc('\n', stderr); +						perror("non-IO error"); +						free(trackbuf); +						return (EX_OSERR); +					} +					if (ioctl(fd, FD_GSTAT, &fdcs) == -1) +						errx(EX_IOERR, +				     "floppy IO error, but no FDC status"); +					nerrs++; +					recoverable = fdcs.status[2] & +						NE7_ST2_DD; +					if (!quiet) { +						printstatus(&fdcs, 0); +						fputs(" (", stderr); +						if (!recoverable) +							fputs("not ", stderr); +						fputs("recoverable)", stderr); +					} +					if (!recover) { +						if (!quiet) +							putc('\n', stderr); +						free(trackbuf); +						return (EX_IOERR); +					} +					memset(trackbuf, fillbyte, secsize); +					if (recoverable) { +						fdopts |= FDOPT_NOERROR; +						if (ioctl(fd, FD_SOPTS, +							  &fdopts) == -1) +							err(EX_OSERR, +				    "ioctl(fd, FD_SOPTS, FDOPT_NOERROR)"); +						rv = read(fd, trackbuf, +							  secsize); +						if ((unsigned)rv != secsize) +							err(EX_IOERR, +				    "read() with FDOPT_NOERROR still fails"); +						fdopts &= ~FDOPT_NOERROR; +						(void)ioctl(fd, FD_SOPTS, +							    &fdopts); +					} +					if (!quiet) { +						if (recoverable) +							fprintf(stderr, +								": recovered"); +						else +							fprintf(stderr, +								": dummy"); +						fprintf(stderr, +							" data @ %#x ... %#x\n", +							nbytes, +							nbytes + secsize - 1); +					} +					nbytes += secsize; +					fwrite(trackbuf, sizeof(unsigned char), +					       secsize, of); +					fflush(of); +					continue; +				} +				errx(EX_OSERR, "unexpected read() result: %d", +				     rv); +			} +		} +		if ((unsigned)rv < tracksize) { +			/* should not happen */ +			nbytes += rv; +			if (!quiet) +				fprintf(stderr, "\nshort after %5d KB\r", +					nbytes / 1024); +			fwrite(trackbuf, sizeof(unsigned char), rv, of); +			fflush(of); +			continue; +		} +	} +	free(trackbuf); +	if (!quiet) { +		putc('\n', stderr); +		if (nerrs) +			fprintf(stderr, "%d error%s\n", +				nerrs, nerrs > 1? "s": ""); +	} + +	return (nerrs? EX_IOERR: EX_OK); +} + +static int +doreadid(int fd, unsigned int numids, unsigned int trackno) +{ +	int rv = 0; +	unsigned int i; +	struct fdc_readid info; +	struct fdc_status fdcs; +	struct fd_type fdt; + +	if (ioctl(fd, FD_GTYPE, &fdt) == -1) +		err(EX_OSERR, "ioctl(FD_GTYPE) failed -- not a floppy?"); + +	for (i = 0; i < numids; i++) { +		info.cyl = trackno / fdt.heads; +		info.head = fdt.heads > 1? trackno % fdt.heads: 0; +		if (ioctl(fd, FD_READID, &info) == 0) { +			printf("C = %d, H = %d, R = %d, N = %d\n", +			       info.cyl, info.head, info.sec, info.secshift); +		} else { +			if (errno != EIO) { +				perror("non-IO error"); +				return (EX_OSERR); +			} +			if (ioctl(fd, FD_GSTAT, &fdcs) == -1) +				errx(EX_IOERR, +				     "floppy IO error, but no FDC status"); +			printstatus(&fdcs, 0); +			putc('\n', stderr); +			rv = EX_IOERR; +		} +	} + +	return (rv); +} diff --git a/usr.sbin/fdread/fdutil.c b/usr.sbin/fdread/fdutil.c new file mode 100644 index 000000000000..eb5e7a642f2f --- /dev/null +++ b/usr.sbin/fdread/fdutil.c @@ -0,0 +1,484 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2001 Joerg Wunsch + * + * All rights reserved. + * + * 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 DEVELOPERS ``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 DEVELOPERS 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. + */ + +#include <dev/ic/nec765.h> + +#include <sys/fdcio.h> + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> + +#include "fdutil.h" + +/* + * Decode the FDC status pointed to by `fdcsp', and print a textual + * translation to stderr.  If `terse' is false, the numerical FDC + * register status is printed, too. + */ +void +printstatus(struct fdc_status *fdcsp, int terse) +{ +	char msgbuf[100]; + +	if (!terse) +		fprintf(stderr, +		"\nFDC status ST0=%#x ST1=%#x ST2=%#x C=%u H=%u R=%u N=%u:\n", +			fdcsp->status[0] & 0xff, +			fdcsp->status[1] & 0xff, +			fdcsp->status[2] & 0xff, +			fdcsp->status[3] & 0xff, +			fdcsp->status[4] & 0xff, +			fdcsp->status[5] & 0xff, +			fdcsp->status[6] & 0xff); + +	if ((fdcsp->status[0] & NE7_ST0_IC_RC) == 0) { +		sprintf(msgbuf, "timeout"); +	} else if ((fdcsp->status[0] & NE7_ST0_IC_RC) != NE7_ST0_IC_AT) { +		sprintf(msgbuf, "unexcpted interrupt code %#x", +			fdcsp->status[0] & NE7_ST0_IC_RC); +	} else { +		strcpy(msgbuf, "unexpected error code in ST1/ST2"); + +		if (fdcsp->status[1] & NE7_ST1_EN) +			strcpy(msgbuf, "end of cylinder (wrong format)"); +		else if (fdcsp->status[1] & NE7_ST1_DE) { +			if (fdcsp->status[2] & NE7_ST2_DD) +				strcpy(msgbuf, "CRC error in data field"); +			else +				strcpy(msgbuf, "CRC error in ID field"); +		} else if (fdcsp->status[1] & NE7_ST1_MA) { +			if (fdcsp->status[2] & NE7_ST2_MD) +				strcpy(msgbuf, "no address mark in data field"); +			else +				strcpy(msgbuf, "no address mark in ID field"); +		} else if (fdcsp->status[2] & NE7_ST2_WC) +			strcpy(msgbuf, "wrong cylinder (format mismatch)"); +		else if (fdcsp->status[1] & NE7_ST1_ND) +			strcpy(msgbuf, "no data (sector not found)"); +	} +	fputs(msgbuf, stderr); +} + +static struct fd_type fd_types_auto[1] = +    { { 0,0,0,0,0,0,0,0,0,0,0,FL_AUTO } }; + + +static struct fd_type fd_types_288m[] = { +#if 0 +	{ FDF_3_2880 }, +#endif +	{ FDF_3_1722 }, +	{ FDF_3_1476 }, +	{ FDF_3_1440 }, +	{ FDF_3_1200 }, +	{ FDF_3_820 }, +	{ FDF_3_800 }, +	{ FDF_3_720 }, +	{ 0,0,0,0,0,0,0,0,0,0,0,0 } +}; + +static struct fd_type fd_types_144m[] = { +	{ FDF_3_1722 }, +	{ FDF_3_1476 }, +	{ FDF_3_1440 }, +	{ FDF_3_1200 }, +	{ FDF_3_820 }, +	{ FDF_3_800 }, +	{ FDF_3_720 }, +	{ 0,0,0,0,0,0,0,0,0,0,0,0 } +}; + +static struct fd_type fd_types_12m[] = { +	{ FDF_5_1200 }, +	{ FDF_5_1230 }, +	{ FDF_5_1480 }, +	{ FDF_5_1440 }, +	{ FDF_5_820 }, +	{ FDF_5_800 }, +	{ FDF_5_720 }, +	{ FDF_5_360 | FL_2STEP }, +	{ FDF_5_640 }, +	{ 0,0,0,0,0,0,0,0,0,0,0,0 } +}; + +static struct fd_type fd_types_720k[] = +{ +	{ FDF_3_720 }, +	{ 0,0,0,0,0,0,0,0,0,0,0,0 } +}; + +static struct fd_type fd_types_360k[] = +{ +	{ FDF_5_360 }, +	{ 0,0,0,0,0,0,0,0,0,0,0,0 } +}; + + +/* + * Parse a format string, and fill in the parameter pointed to by `out'. + * + * sectrac,secsize,datalen,gap,ncyls,speed,heads,f_gap,f_inter,offs2,flags[...] + * + * sectrac = sectors per track + * secsize = sector size in bytes + * datalen = length of sector if secsize == 128 + * gap     = gap length when reading + * ncyls   = number of cylinders + * speed   = transfer speed 250/300/500/1000 KB/s + * heads   = number of heads + * f_gap   = gap length when formatting + * f_inter = sector interleave when formatting + * offs2   = offset of sectors on side 2 + * flags   = +/-mfm | +/-2step | +/-perpend + *             mfm - use MFM recording + *             2step - use 2 steps between cylinders + *             perpend - user perpendicular (vertical) recording + * + * Any omitted value will be passed on from parameter `in'. + */ +void +parse_fmt(const char *s, enum fd_drivetype type, +	  struct fd_type in, struct fd_type *out) +{ +	int i, j; +	const char *cp; +	char *s1; + +	*out = in; + +	for (i = 0;; i++) { +		if (s == NULL) +			break; + +		if ((cp = strchr(s, ',')) == NULL) { +			s1 = strdup(s); +			if (s1 == NULL) +				abort(); +			s = 0; +		} else { +			s1 = malloc(cp - s + 1); +			if (s1 == NULL) +				abort(); +			memcpy(s1, s, cp - s); +			s1[cp - s] = 0; + +			s = cp + 1; +		} +		if (strlen(s1) == 0) { +			free(s1); +			continue; +		} + +		switch (i) { +		case 0:		/* sectrac */ +			if (getnum(s1, &out->sectrac)) +				errx(EX_USAGE, +				     "bad numeric value for sectrac: %s", s1); +			break; + +		case 1:		/* secsize */ +			if (getnum(s1, &j)) +				errx(EX_USAGE, +				     "bad numeric value for secsize: %s", s1); +			if (j == 128) out->secsize = 0; +			else if (j == 256) out->secsize = 1; +			else if (j == 512) out->secsize = 2; +			else if (j == 1024) out->secsize = 3; +			else +				errx(EX_USAGE, "bad sector size %d", j); +			break; + +		case 2:		/* datalen */ +			if (getnum(s1, &j)) +				errx(EX_USAGE, +				     "bad numeric value for datalen: %s", s1); +			if (j >= 256) +				errx(EX_USAGE, "bad datalen %d", j); +			out->datalen = j; +			break; + +		case 3:		/* gap */ +			if (getnum(s1, &out->gap)) +				errx(EX_USAGE, +				     "bad numeric value for gap: %s", s1); +			break; + +		case 4:		/* ncyls */ +			if (getnum(s1, &j)) +				errx(EX_USAGE, +				     "bad numeric value for ncyls: %s", s1); +			if (j > 85) +				errx(EX_USAGE, "bad # of cylinders %d", j); +			out->tracks = j; +			break; + +		case 5:		/* speed */ +			if (getnum(s1, &j)) +				errx(EX_USAGE, +				     "bad numeric value for speed: %s", s1); +			switch (type) { +			default: +				abort(); /* paranoia */ + +			case FDT_360K: +			case FDT_720K: +				if (j == 250) +					out->trans = FDC_250KBPS; +				else +					errx(EX_USAGE, "bad speed %d", j); +				break; + +			case FDT_12M: +				if (j == 300) +					out->trans = FDC_300KBPS; +				else if (j == 250) +					out->trans = FDC_250KBPS; +				else if (j == 500) +					out->trans = FDC_500KBPS; +				else +					errx(EX_USAGE, "bad speed %d", j); +				break; + +			case FDT_288M: +				if (j == 1000) +					out->trans = FDC_1MBPS; +				/* FALLTHROUGH */ +			case FDT_144M: +				if (j == 250) +					out->trans = FDC_250KBPS; +				else if (j == 500) +					out->trans = FDC_500KBPS; +				else +					errx(EX_USAGE, "bad speed %d", j); +				break; +			} +			break; + +		case 6:		/* heads */ +			if (getnum(s1, &j)) +				errx(EX_USAGE, +				     "bad numeric value for heads: %s", s1); +			if (j == 1 || j == 2) +				out->heads = j; +			else +				errx(EX_USAGE, "bad # of heads %d", j); +			break; + +		case 7:		/* f_gap */ +			if (getnum(s1, &out->f_gap)) +				errx(EX_USAGE, +				     "bad numeric value for f_gap: %s", s1); +			break; + +		case 8:		/* f_inter */ +			if (getnum(s1, &out->f_inter)) +				errx(EX_USAGE, +				     "bad numeric value for f_inter: %s", s1); +			break; + +		case 9:		/* offs2 */ +			if (getnum(s1, &out->offset_side2)) +				errx(EX_USAGE, +				     "bad numeric value for offs2: %s", s1); +			break; + +		default: +			if (strcmp(s1, "+mfm") == 0) +				out->flags |= FL_MFM; +			else if (strcmp(s1, "-mfm") == 0) +				out->flags &= ~FL_MFM; +			else if (strcmp(s1, "+auto") == 0) +				out->flags |= FL_AUTO; +			else if (strcmp(s1, "-auto") == 0) +				out->flags &= ~FL_AUTO; +			else if (strcmp(s1, "+2step") == 0) +				out->flags |= FL_2STEP; +			else if (strcmp(s1, "-2step") == 0) +				out->flags &= ~FL_2STEP; +			else if (strcmp(s1, "+perpnd") == 0) +				out->flags |= FL_PERPND; +			else if (strcmp(s1, "-perpnd") == 0) +				out->flags &= ~FL_PERPND; +			else +				errx(EX_USAGE, "bad flag: %s", s1); +			break; +		} +		free(s1); +	} + +	out->size = out->tracks * out->heads * out->sectrac; +} + +/* + * Print a textual translation of the drive (density) type described + * by `in' to stdout.  The string uses the same form that is parseable + * by parse_fmt(). + */ +void +print_fmt(struct fd_type in) +{ +	int secsize, speed; + +	secsize = 128 << in.secsize; +	switch (in.trans) { +	case FDC_250KBPS:	speed = 250; break; +	case FDC_300KBPS:	speed = 300; break; +	case FDC_500KBPS:	speed = 500; break; +	case FDC_1MBPS:		speed = 1000; break; +	default:		speed = 1; break; +	} + +	printf("%d,%d,%#x,%#x,%d,%d,%d,%#x,%d,%d", +	       in.sectrac, secsize, in.datalen, in.gap, in.tracks, +	       speed, in.heads, in.f_gap, in.f_inter, in.offset_side2); +	if (in.flags & FL_MFM) +		printf(",+mfm"); +	if (in.flags & FL_2STEP) +		printf(",+2step"); +	if (in.flags & FL_PERPND) +		printf(",+perpnd"); +	if (in.flags & FL_AUTO) +		printf(",+auto"); +	putc('\n', stdout); +} + +/* + * Based on `size' (in kilobytes), walk through the table of known + * densities for drive type `type' and see if we can find one.  If + * found, return it (as a pointer to static storage), otherwise return + * NULL. + */ +struct fd_type * +get_fmt(int size, enum fd_drivetype type) +{ +	int i, n; +	struct fd_type *fdtp; + +	switch (type) { +	default: +		return (0); + +	case FDT_360K: +		fdtp = fd_types_360k; +		n = sizeof fd_types_360k / sizeof(struct fd_type); +		break; + +	case FDT_720K: +		fdtp = fd_types_720k; +		n = sizeof fd_types_720k / sizeof(struct fd_type); +		break; + +	case FDT_12M: +		fdtp = fd_types_12m; +		n = sizeof fd_types_12m / sizeof(struct fd_type); +		break; + +	case FDT_144M: +		fdtp = fd_types_144m; +		n = sizeof fd_types_144m / sizeof(struct fd_type); +		break; + +	case FDT_288M: +		fdtp = fd_types_288m; +		n = sizeof fd_types_288m / sizeof(struct fd_type); +		break; +	} + +	if (size == -1) +		return fd_types_auto; + +	for (i = 0; i < n; i++, fdtp++) { +		fdtp->size = fdtp->sectrac * fdtp->heads * fdtp->tracks; +		if (((128 << fdtp->secsize) * fdtp->size / 1024) == size) +			return (fdtp); +	} +	return (0); +} + +/* + * Parse a number from `s'.  If the string cannot be converted into a + * number completely, return -1, otherwise 0.  The result is returned + * in `*res'. + */ +int +getnum(const char *s, int *res) +{ +	unsigned long ul; +	char *cp; + +	ul = strtoul(s, &cp, 0); +	if (*cp != '\0') +	  return (-1); + +	*res = (int)ul; +	return (0); +} + +/* + * Return a short name and a verbose description for the drive + * described by `t'. + */ +void +getname(enum fd_drivetype t, const char **name, const char **descr) +{ + +	switch (t) { +	default: +		*name = "unknown"; +		*descr = "unknown drive type"; +		break; + +	case FDT_360K: +		*name = "360K"; +		*descr = "5.25\" double-density"; +		break; + +	case FDT_12M: +		*name = "1.2M"; +		*descr = "5.25\" high-density"; +		break; + +	case FDT_720K: +		*name = "720K"; +		*descr = "3.5\" double-density"; +		break; + +	case FDT_144M: +		*name = "1.44M"; +		*descr = "3.5\" high-density"; +		break; + +	case FDT_288M: +		*name = "2.88M"; +		*descr = "3.5\" extra-density"; +		break; +	} +} diff --git a/usr.sbin/fdread/fdutil.h b/usr.sbin/fdread/fdutil.h new file mode 100644 index 000000000000..a0c53424824e --- /dev/null +++ b/usr.sbin/fdread/fdutil.h @@ -0,0 +1,37 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2001 Joerg Wunsch + * + * All rights reserved. + * + * 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 DEVELOPERS ``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 DEVELOPERS 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. + */ + + +void	printstatus(struct fdc_status *fdcsp, int terse); +void	parse_fmt(const char *, enum fd_drivetype, +		     struct fd_type, struct fd_type *); +struct	fd_type *get_fmt(int, enum fd_drivetype); +void	print_fmt(struct fd_type); +int	getnum(const char *, int *); +void	getname(enum fd_drivetype, const char **, const char **); + | 
