A small program, which can take a file of any size, format, write and verify

it onto a bunch of floppies in a semi-intelligent way.

Useful for things like:  tar cf - . | gzip -9 | fdwrite -d /dev/rfd0.1720 -v

Where it will keep asking for floppies until tar is done.
This commit is contained in:
Poul-Henning Kamp 1994-09-18 07:39:19 +00:00
parent 9d8044d0d9
commit b5173cbeea
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/cvs2svn/branches/phk/; revision=2849
3 changed files with 341 additions and 0 deletions

16
usr.sbin/fdwrite/Makefile Normal file
View File

@ -0,0 +1,16 @@
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <phk@login.dkuug.dk> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
# ----------------------------------------------------------------------------
#
# $Id$
#
#
PROG = fdwrite
CFLAGS+= -Wall -I${DESTDIR}/sys
.include <bsd.prog.mk>

117
usr.sbin/fdwrite/fdwrite.1 Normal file
View File

@ -0,0 +1,117 @@
.\"
.\" ----------------------------------------------------------------------------
.\" "THE BEER-WARE LICENSE" (Revision 42):
.\" <phk@login.dkuug.dk> wrote this file. As long as you retain this notice you
.\" can do whatever you want with this stuff. If we meet some day, and you think
.\" this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
.\" ----------------------------------------------------------------------------
.\"
.\" $Id$
.\"
.\"
.Dd September 16, 1993
.Os FreeBSD
.Dt FDWRITE 1
.Sh NAME
.Nm fdwrite
.Nd format and write floppy disks
.Sh SYNOPSIS
.Nm fdwrite
.Bq Fl v
.Bq Fl f Ar inputfile
.Bq Fl d Ar device
.Sh DESCRIPTION
.Nm Fdwrite
formats and writes one and more floppy disks.
Any floppy disk device capable of formatting can be used.
.Nm Fdwrite
will ask the user
.Pq on /dev/tty
to insert a new floppy and press return.
The device will then be opened, and queried for it's paramters,
then each track will be formatted, written with data from the
.Ar inputfile ,
read back and compared.
When the floppy disk if filled, the process is repeated, with the next disk.
This continues until the program is interrupted or EOF is encountered on the
.Ar inputfile .
The options are as follows:
.Bl -tag -width 10n -offset indent
.It Fl v
toggles verbosity on stdout.
Default is ``on''.
After
.Ar device
is opened first time the format will be printed.
During operation progress will be reported with the number of tracks
remaining on the current floppy disk, and the letters I, Z, F, W,
R and C, which indicates completion of Input, Zero-fill, Format
Write, Read and Compare of current track respectively.
.It Fl f Ar inputfile
Input file to read. If none is given, stdin is assumed.
.It Fl d Ar device
The name of the floppy device to write to. Default is ``/dev/rfd0''.
.El
.Nm Fdwrite
actually closes the
.Ar device
while it waits for the user to press return,
it is thus quite possible to use the drive for other purposes at this
time and later resume writing with the next floppy.
The parameters returned from
.Ar device
are used for formatting.
If custom formatting is needed, please use
.Xr fdformat 1
instead.
.Sh EXAMPLE
.Nm Fdwrite
was planned as a tool to make life easier when writing a set of floppies,
one such use could be to write a tar-archive:
.ce 1
tar cf - . | gzip -9 | fdwrite -d /dev/rfd0.1720 -v
The main difference from using
.Xr tar 1 's
multivolume facility is of course the formatting of the floppies, which
here is done on the fly,
thus reducing the amount of work for the floppy-jockey.
.Sh SEE ALSO
.Xr fdformat 1 .
.Sh HISTORY
.Nm Fdwrite
was written while waiting for ``make world'' to complete.
Some of the code was taken from
.Xr fdformat 1 .
.Sh AUTHOR
The program has been contributed by
Poul-Henning Kamp <phk@login.dknet.dk>
.Sh BUGS
Diagnostics are less than complete at present.
If a floppy is sick, and the
.Ar inputfile
is seekable, it should ask the user to frisbee the disk, insert
another, and rewind to the right spot and continue.
This concept could be extended to cover non-seekable input also
by employing a temporary file .
An option (defaulting to zero) should allow the user to ask for
retries in case of failure.
At present a suitable tool for reading back a multivolume set
of floppies is missing.
Programs like
.Xr tar 1
for instance, will do the job, if the data has not been compressed.
One can always trust
.Xr dd 1
to help out in this situation of course

208
usr.sbin/fdwrite/fdwrite.c Normal file
View File

@ -0,0 +1,208 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk@login.dkuug.dk> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*
* $Id$
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <strings.h>
#include <ctype.h>
#include <errno.h>
#include <machine/ioctl_fd.h>
#include <i386/isa/fdreg.h> /* XXX should be in <machine> dir */
int
format_track(int fd, int cyl, int secs, int head, int rate,
int gaplen, int secsize, int fill,int interleave)
{
struct fd_formb f;
register int i,j;
int il[100];
memset(il,0,sizeof il);
for(j = 0, i = 1; i <= secs; i++) {
while(il[(j%secs)+1]) j++;
il[(j%secs)+1] = i;
j += interleave;
}
f.format_version = FD_FORMAT_VERSION;
f.head = head;
f.cyl = cyl;
f.transfer_rate = rate;
f.fd_formb_secshift = secsize;
f.fd_formb_nsecs = secs;
f.fd_formb_gaplen = gaplen;
f.fd_formb_fillbyte = fill;
for(i = 0; i < secs; i++) {
f.fd_formb_cylno(i) = cyl;
f.fd_formb_headno(i) = head;
f.fd_formb_secno(i) = il[i+1];
f.fd_formb_secsize(i) = secsize;
}
return ioctl(fd, FD_FORM, (caddr_t)&f);
}
static void
usage ()
{
printf("Usage:\n\tfdwrite [-v] [-f inputfile] [-d device]\n");
exit(2);
}
int
main(int argc, char **argv)
{
int inputfd = -1, c, fdn = 0, i,j,fd;
int bpt, verbose=1, nbytes=0, track;
char *device= "/dev/rfd0", *trackbuf = 0,*vrfybuf = 0;
struct fd_type fdt;
FILE *tty;
setbuf(stdout,0);
while((c = getopt(argc, argv, "d:s:f:v")) != -1)
switch(c) {
case 'd': /* Which drive */
device = optarg;
break;
case 'f': /* input file */
if (inputfd >= 0)
close(inputfd);
inputfd = open(optarg,O_RDONLY);
if (inputfd < 0) {
perror(optarg);
exit(1);
}
break;
case 'v': /* Toggle verbosity */
verbose = !verbose;
break;
case '?': default:
usage();
}
if (inputfd < 0)
inputfd = 0;
if(optind < argc)
usage();
tty = fopen("/dev/tty","r+");
if(!tty) {
perror("/dev/tty");
exit(1);
}
setbuf(tty,0);
for(j=1;j > 0;) {
fdn++;
fprintf(tty,
"Please insert floppy #%d in drive %s and press return >",
fdn,device);
while(1) {
i = getc(tty);
if(i == '\n') break;
}
if((fd = open(device, O_RDWR)) < 0) {
perror(device);
exit(1);
}
if(ioctl(fd, FD_GTYPE, &fdt) < 0) {
fprintf(stderr, "fdformat: not a floppy disk: %s\n", device);
exit(1);
}
bpt = fdt.sectrac * (1<<fdt.secsize) * 128;
if(!trackbuf) {
trackbuf = malloc(bpt);
if(!trackbuf) { perror("malloc"); exit(1); }
}
if(!vrfybuf) {
vrfybuf = malloc(bpt);
if(!vrfybuf) { perror("malloc"); exit(1); }
}
if(fdn == 1) {
if(verbose) {
printf("Format: %d cylinders, %d heads, %d sectors, %d bytes = %dkb\n",
fdt.tracks,fdt.heads,fdt.sectrac,(1<<fdt.secsize) * 128,
fdt.tracks*bpt*fdt.heads/1024);
}
memset(trackbuf,0,bpt);
for(j=0;inputfd >= 0 && j<bpt;j+=i) {
if(!(i = read(inputfd,trackbuf+j,bpt-j))) {
close(inputfd);
inputfd = -1;
break;
}
nbytes += i;
}
}
for (track = 0; track < fdt.tracks * fdt.heads; track++) {
if(verbose) printf("\r%3d ",fdt.tracks * fdt.heads-track);
if(verbose) putc((j ? 'I':'Z'),stdout);
format_track(fd, track / fdt.heads, fdt.sectrac, track % fdt.heads,
fdt.trans, fdt.f_gap, fdt.secsize, 0xe6,
fdt.f_inter);
if(verbose) putc('F',stdout);
if (lseek (fd, (long) track*bpt, 0) < 0) {
perror("lseek");
exit (1);
}
if (write (fd, trackbuf, bpt) != bpt) {
perror("write");
exit (1);
}
if(verbose) putc('W',stdout);
if (lseek (fd, (long) track*bpt, 0) < 0) {
perror("lseek");
exit (1);
}
if (read (fd, vrfybuf, bpt) != bpt) {
perror("read");
exit (1);
}
if(verbose) putc('R',stdout);
if (memcmp(trackbuf,vrfybuf,bpt)) {
perror("compare");
exit (1);
}
if(verbose) putc('C',stdout);
memset(trackbuf,0,bpt);
for(j=0;inputfd >= 0 && j<bpt;j+=i) {
if(!(i = read(inputfd,trackbuf+j,bpt-j))) {
close(inputfd);
inputfd = -1;
break;
}
nbytes += i;
}
}
close(fd);
putc('\r',stdout);
}
if(verbose)
printf("%d bytes on %d flopp%s\n",nbytes,fdn,fdn==1?"y":"ies");
exit(0);
}