Announce 1.2.1
[oweals/busybox.git] / util-linux / fdformat.c
1 /* vi: set sw=4 ts=4: */
2 /* fdformat.c  -  Low-level formats a floppy disk - Werner Almesberger */
3
4 /* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
5  * - added Native Language Support
6  * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
7  * - more i18n/nls translatable strings marked
8  *
9  * 5 July 2003 -- modified for Busybox by Erik Andersen
10  */
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <fcntl.h>
15 #include <errno.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <sys/stat.h>
19 #include <sys/ioctl.h>
20 #include "busybox.h"
21
22
23 /* Stuff extracted from linux/fd.h */
24 struct floppy_struct {
25         unsigned int    size,           /* nr of sectors total */
26                         sect,           /* sectors per track */
27                         head,           /* nr of heads */
28                         track,          /* nr of tracks */
29                         stretch;        /* !=0 means double track steps */
30 #define FD_STRETCH 1
31 #define FD_SWAPSIDES 2
32
33         unsigned char   gap,            /* gap1 size */
34
35                         rate,           /* data rate. |= 0x40 for perpendicular */
36 #define FD_2M 0x4
37 #define FD_SIZECODEMASK 0x38
38 #define FD_SIZECODE(floppy) (((((floppy)->rate&FD_SIZECODEMASK)>> 3)+ 2) %8)
39 #define FD_SECTSIZE(floppy) ( (floppy)->rate & FD_2M ? \
40                              512 : 128 << FD_SIZECODE(floppy) )
41 #define FD_PERP 0x40
42
43                         spec1,          /* stepping rate, head unload time */
44                         fmt_gap;        /* gap2 size */
45         const char      * name; /* used only for predefined formats */
46 };
47 struct format_descr {
48         unsigned int device,head,track;
49 };
50 #define FDFMTBEG _IO(2,0x47)
51 #define FDFMTTRK _IOW(2,0x48, struct format_descr)
52 #define FDFMTEND _IO(2,0x49)
53 #define FDGETPRM _IOR(2, 0x04, struct floppy_struct)
54 #define FD_FILL_BYTE 0xF6 /* format fill byte. */
55
56 static void print_and_flush(const char * __restrict format, ...)
57 {
58         va_list arg;
59
60         va_start(arg, format);
61         bb_vfprintf(stdout, format, arg);
62         va_end(arg);
63         bb_xfflush_stdout();
64 }
65
66 static void bb_xioctl(int fd, int request, void *argp, const char *string)
67 {
68         if (ioctl (fd, request, argp) < 0) {
69                 bb_perror_msg_and_die(string);
70         }
71 }
72
73 int fdformat_main(int argc,char **argv)
74 {
75         int fd, n, cyl, read_bytes, verify;
76         unsigned char *data;
77         struct stat st;
78         struct floppy_struct param;
79         struct format_descr descr;
80
81         if (argc < 2) {
82                 bb_show_usage();
83         }
84         verify = !bb_getopt_ulflags(argc, argv, "n");
85         argv += optind;
86
87         /* R_OK is needed for verifying */
88         if (stat(*argv,&st) < 0 || access(*argv,W_OK | R_OK ) < 0) {
89                 bb_perror_msg_and_die("%s",*argv);
90         }
91         if (!S_ISBLK(st.st_mode)) {
92                 bb_error_msg_and_die("%s: not a block device",*argv);
93                 /* do not test major - perhaps this was an USB floppy */
94         }
95
96
97         /* O_RDWR for formatting and verifying */
98         fd = bb_xopen(*argv,O_RDWR );
99
100         bb_xioctl(fd, FDGETPRM, &param, "FDGETPRM");/*original message was: "Could not determine current format type" */
101
102         print_and_flush("%s-sided, %d tracks, %d sec/track. Total capacity %d kB.\n",
103                 (param.head == 2) ? "Double" : "Single",
104                 param.track, param.sect, param.size >> 1);
105
106         /* FORMAT */
107         print_and_flush("Formatting ... ", NULL);
108         bb_xioctl(fd, FDFMTBEG,NULL,"FDFMTBEG");
109
110         /* n == track */
111         for (n = 0; n < param.track; n++)
112         {
113             descr.head = 0;
114             descr.track = n;
115             bb_xioctl(fd, FDFMTTRK,&descr,"FDFMTTRK");
116             print_and_flush("%3d\b\b\b", n);
117             if (param.head == 2) {
118                 descr.head = 1;
119                 bb_xioctl(fd, FDFMTTRK,&descr,"FDFMTTRK");
120             }
121         }
122
123         bb_xioctl(fd,FDFMTEND,NULL,"FDFMTEND");
124         print_and_flush("done\n", NULL);
125
126         /* VERIFY */
127         if(verify) {
128                 /* n == cyl_size */
129                 n = param.sect*param.head*512;
130
131                 data = xmalloc(n);
132                 print_and_flush("Verifying ... ", NULL);
133                 for (cyl = 0; cyl < param.track; cyl++) {
134                         print_and_flush("%3d\b\b\b", cyl);
135                         if((read_bytes = safe_read(fd,data,n))!= n ) {
136                                 if(read_bytes < 0) {
137                                         bb_perror_msg(bb_msg_read_error);
138                                 }
139                                 bb_error_msg_and_die("Problem reading cylinder %d, expected %d, read %d", cyl, n, read_bytes);
140                         }
141                         /* Check backwards so we don't need a counter */
142                         while(--read_bytes>=0) {
143                                 if( data[read_bytes] != FD_FILL_BYTE) {
144                                          print_and_flush("bad data in cyl %d\nContinuing ... ",cyl);
145                                 }
146                         }
147                 }
148                 /* There is no point in freeing blocks at the end of a program, because
149                 all of the program's space is given back to the system when the process
150                 terminates.*/
151
152                 if (ENABLE_FEATURE_CLEAN_UP) free(data);
153
154                 print_and_flush("done\n", NULL);
155         }
156
157         if (ENABLE_FEATURE_CLEAN_UP) close(fd);
158
159         /* Don't bother closing.  Exit does
160          * that, so we can save a few bytes */
161         return EXIT_SUCCESS;
162 }