1/*-
2 * SPDX-License-Identifier: Beerware
3 *
4 * ----------------------------------------------------------------------------
5 * "THE BEER-WARE LICENSE" (Revision 42):
6 * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
7 * can do whatever you want with this stuff. If we meet some day, and you think
8 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
9 * ----------------------------------------------------------------------------
10 *
11 * $FreeBSD$
12 *
13 */
14
15#include <ctype.h>
16#include <err.h>
17#include <fcntl.h>
18#include <paths.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <unistd.h>
23
24#include <sys/fdcio.h>
25
26static int
27format_track(int fd, int cyl, int secs, int head, int rate,
28     int gaplen, int secsize, int fill, int interleave)
29{
30    struct fd_formb f;
31    register int i,j;
32    int il[100];
33
34    memset(il,0,sizeof il);
35    for(j = 0, i = 1; i <= secs; i++) {
36	while(il[(j%secs)+1]) j++;
37	il[(j%secs)+1] = i;
38	j += interleave;
39    }
40
41    f.format_version = FD_FORMAT_VERSION;
42    f.head = head;
43    f.cyl = cyl;
44    f.transfer_rate = rate;
45
46    f.fd_formb_secshift = secsize;
47    f.fd_formb_nsecs = secs;
48    f.fd_formb_gaplen = gaplen;
49    f.fd_formb_fillbyte = fill;
50    for(i = 0; i < secs; i++) {
51	f.fd_formb_cylno(i) = cyl;
52	f.fd_formb_headno(i) = head;
53	f.fd_formb_secno(i) = il[i+1];
54	f.fd_formb_secsize(i) = secsize;
55    }
56    return ioctl(fd, FD_FORM, (caddr_t)&f);
57}
58
59static void
60usage(void)
61{
62	fprintf(stderr, "usage: fdwrite [-v] [-y] [-f inputfile] [-d device]\n");
63	exit(2);
64}
65
66int
67main(int argc, char **argv)
68{
69    int inputfd = -1, c, fdn = 0, i,j,fd;
70    int bpt, verbose=1, nbytes=0, track;
71    int interactive = 1;
72    const char *device= "/dev/fd0";
73    char *trackbuf = 0,*vrfybuf = 0;
74    struct fd_type fdt;
75    FILE *tty;
76
77    setbuf(stdout,0);
78    while((c = getopt(argc, argv, "d:f:vy")) != -1)
79	    switch(c) {
80	    case 'd':	/* Which drive */
81		    device = optarg;
82		    break;
83
84	    case 'f':	/* input file */
85		    if (inputfd >= 0)
86			    close(inputfd);
87		    inputfd = open(optarg,O_RDONLY);
88		    if (inputfd < 0)
89			    err(1, "%s", optarg);
90		    break;
91
92	    case 'v':  /* Toggle verbosity */
93		    verbose = !verbose;
94		    break;
95
96	    case 'y':  /* Don't confirm? */
97		    interactive = 0;
98		    break;
99
100	    case '?': default:
101		    usage();
102	    }
103
104    if (inputfd < 0)
105	inputfd = 0;
106
107    if (!isatty(1))
108	interactive = 0;
109
110    if(optind < argc)
111	    usage();
112
113    tty = fopen(_PATH_TTY,"r+");
114    if(!tty)
115	    err(1, _PATH_TTY);
116    setbuf(tty,0);
117
118    for(j=1;j > 0;) {
119        fdn++;
120	if (interactive) {
121	    fprintf(tty,
122		    "Please insert floppy #%d in drive %s and press return >",
123		    fdn,device);
124	    while(1) {
125		i = getc(tty);
126		if(i == '\n') break;
127	    }
128	}
129
130	if((fd = open(device, O_RDWR)) < 0)
131	    err(1, "%s", device);
132
133	if(ioctl(fd, FD_GTYPE, &fdt) < 0)
134	    errx(1, "not a floppy disk: %s", device);
135
136	bpt = fdt.sectrac * (1<<fdt.secsize) * 128;
137	if(!trackbuf) {
138	    trackbuf = malloc(bpt);
139	    if(!trackbuf) errx(1, "malloc");
140	}
141	if(!vrfybuf) {
142	    vrfybuf = malloc(bpt);
143	    if(!vrfybuf) errx(1, "malloc");
144	}
145
146	if(fdn == 1) {
147	    if(verbose) {
148		printf("Format: %d cylinders, %d heads, %d sectors, %d bytes = %dkb\n",
149		fdt.tracks,fdt.heads,fdt.sectrac,(1<<fdt.secsize) * 128,
150		fdt.tracks*bpt*fdt.heads/1024);
151
152	    }
153	    memset(trackbuf,0,bpt);
154	    for(j=0;inputfd >= 0 && j<bpt;j+=i) {
155		if(!(i = read(inputfd,trackbuf+j,bpt-j))) {
156		    close(inputfd);
157		    inputfd = -1;
158		    break;
159		}
160		nbytes += i;
161	    }
162	}
163	for (track = 0; track < fdt.tracks * fdt.heads; track++) {
164	    if(verbose) printf("\r%3d ",fdt.tracks * fdt.heads-track);
165	    if(verbose) putc((j ? 'I':'Z'),stdout);
166	    format_track(fd, track / fdt.heads, fdt.sectrac, track % fdt.heads,
167		    fdt.trans, fdt.f_gap, fdt.secsize, 0xe6,
168		    fdt.f_inter);
169	    if(verbose) putc('F',stdout);
170
171	    if (lseek (fd, (long) track*bpt, 0) < 0) err(1, "lseek");
172	    if (write (fd, trackbuf, bpt) != bpt) err(1, "write");
173	    if(verbose) putc('W',stdout);
174
175	    if (lseek (fd, (long) track*bpt, 0) < 0) err(1, "lseek");
176	    if (read (fd, vrfybuf, bpt) != bpt) err(1, "read");
177	    if(verbose) putc('R',stdout);
178
179	    if (memcmp(trackbuf,vrfybuf,bpt)) err(1, "compare");
180	    if(verbose) putc('C',stdout);
181
182	    memset(trackbuf,0,bpt);
183	    for(j=0;inputfd >= 0 && j<bpt;j+=i) {
184		if(!(i = read(inputfd,trackbuf+j,bpt-j))) {
185		    close(inputfd);
186		    inputfd = -1;
187		    break;
188		}
189		nbytes += i;
190	    }
191	}
192	close(fd);
193	putc('\r',stdout);
194    }
195    if(verbose)
196	printf("%d bytes on %d flopp%s\n",nbytes,fdn,fdn==1?"y":"ies");
197    exit(0);
198}
199