xref: /freebsd/usr.sbin/fdwrite/fdwrite.c (revision c697fb7f)
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 
26 static int
27 format_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 
59 static void
60 usage(void)
61 {
62 	fprintf(stderr, "usage: fdwrite [-v] [-y] [-f inputfile] [-d device]\n");
63 	exit(2);
64 }
65 
66 int
67 main(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