1 /* readall - read a whole device fast Author: Andy Tanenbaum */
3 /* Readall reads all the blocks on a device as fast as it can. If it hits
4 * an error, it stops reading in large units and reads one block at a time.
5 * It reports on all errors it finds.
7 * If the -b flag is given, the output is a shell script that can be run
8 * to mark all the bad blocks.
10 * If the -t flag is given, only the total numbers of blocks is reported.
13 * readall /dev/hd1 # read /dev/hd1
14 * readall -b /dev/hd2 # prepare bad block list on stdout
15 * readall -t /dev/ram # report size of ram disk
18 #include <sys/types.h>
19 #include <sys/ioc_disk.h>
20 #include <minix/partition.h>
21 #include <minix/u64.h>
28 #define CHUNK 25 /* max number of blocks read at once */
29 #define BLOCK_SIZE 1024 /* size of a block */
30 #define RESUME 200 /* # good reads before going back to CHUNK */
31 #define DIVISOR 1000 /* how often to print statistics */
32 #define STORE 4096 /* save this many bad blocks for summary */
34 int chunk
= CHUNK
; /* current number of blocks being read */
35 long goodies
; /* incremented on good reads */
36 long errors
; /* number of errors so far */
37 int normal
= 1; /* set unless -b flag is given */
38 int total
= 0; /* unset unless -t flag is given */
39 char *name
; /* name of special file being read */
41 char a
[CHUNK
* BLOCK_SIZE
]; /* read buffer */
42 long rotten
[STORE
]; /* list of bad blocks */
44 _PROTOTYPE(int main
, (int argc
, char **argv
));
45 static _PROTOTYPE(void output
, (long blocks_read
));
47 /* print pretty progress meter with remaining no. of blocks and ETA on
51 prettyprogress(long b
, long nblocks
, time_t starttime
)
53 /* print progress indication */
57 spent
= now
- starttime
;
58 if(spent
> 0 && (bpsec
= b
/ spent
) > 0) {
60 long secremain
, minremain
, hremain
;
61 secremain
= (nblocks
- b
) / bpsec
;
62 minremain
= (secremain
/ 60) % 60;
63 hremain
= secremain
/ 3600;
64 len
= fprintf(stderr
, "Remain %ld blocks. ETA: %d:%02d:%02d [",
66 hremain
, minremain
, secremain
% 60);
69 for(i
= 0; i
< (b
* (len
-1) / nblocks
); i
++)
74 fprintf(stderr
, "]\r");
85 struct partition entry
;
86 int fd
, s
, i
, badprinted
;
91 if (argc
!= 2 && argc
!= 3) {
92 fprintf(stderr
, "Usage: readall [-b | -t] file\n");
98 if (*p
== '-' && *(p
+ 1) == 'b' && *(p
+ 2) == '\0') {
103 if (*p
== '-' && *(p
+ 1) == 't' && *(p
+ 2) == '\0') {
109 fd
= open(argv
[i
], O_RDONLY
);
112 fprintf(stderr
, "%s is not readable\n", argv
[i
]);
116 /* Get size of file */
117 if(ioctl(fd
, DIOCGETP
, &entry
) < 0) {
118 perror("ioctl DIOCGETP");
121 nblocks
= div64u(entry
.size
, BLOCK_SIZE
);
124 /* Read the entire file. Try it in large chunks, but if an error
125 * occurs, go to single reads for a while. */
127 if(lseek64(fd
, mul64u(BLOCK_SIZE
, b
), SEEK_SET
, NULL
) < 0) {
131 s
= read(fd
, a
, BLOCK_SIZE
* chunk
);
132 if (s
== BLOCK_SIZE
* chunk
) {
133 /* Normal read, no errors. */
137 if (goodies
>= RESUME
&& b
% DIVISOR
== 0)
140 if(b
% DIVISOR
== 0 && !normal
) {
141 prettyprogress(b
, nblocks
, starttime
);
146 chunk
= 1; /* regress to single block mode */
149 if (errors
== STORE
) {
151 "\n%ld Bad blocks is too many. Exiting\n",
155 rotten
[(int) errors
] = b
; /* log the error */
163 fprintf(stderr
, "\n");
164 } else fprintf(stderr
, "\r%*s\n", -WIDTH
, "Done scanning.");
165 if (total
) printf("%8ld\n", b
);
166 if ((errors
== 0) || total
) exit(0);
168 if (normal
) printf("Summary of bad blocks\n");
170 /* Print summary of bad blocks, possibly as shell script. */
171 for (i
= 0; i
< errors
; i
++) {
172 if (normal
== 0 && badprinted
== 0) {
173 printf("badblocks %s ", name
);
176 printf("%6ld ", rotten
[i
]);
177 if ((i
+ 1) % 7 == 0) {
185 if (normal
&& b
% DIVISOR
== 0) output(b
);
189 static void output(blocks_read
)
192 fprintf(stderr
, "%8ld blocks read, %5ld errors\r", blocks_read
, errors
);