source: trunk/minix/commands/simple/readall.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 4.8 KB
Line 
1/* readall - read a whole device fast Author: Andy Tanenbaum */
2
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.
6 *
7 * If the -b flag is given, the output is a shell script that can be run
8 * to mark all the bad blocks.
9 *
10 * If the -t flag is given, only the total numbers of blocks is reported.
11 *
12 * Examples of usage:
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
16 */
17
18#include <sys/types.h>
19#include <sys/ioc_disk.h>
20#include <minix/partition.h>
21#include <minix/u64.h>
22#include <time.h>
23#include <fcntl.h>
24#include <unistd.h>
25#include <stdlib.h>
26#include <stdio.h>
27
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 */
33
34int chunk = CHUNK; /* current number of blocks being read */
35long goodies; /* incremented on good reads */
36long errors; /* number of errors so far */
37int normal = 1; /* set unless -b flag is given */
38int total = 0; /* unset unless -t flag is given */
39char *name; /* name of special file being read */
40
41char a[CHUNK * BLOCK_SIZE]; /* read buffer */
42long rotten[STORE]; /* list of bad blocks */
43
44_PROTOTYPE(int main, (int argc, char **argv));
45static _PROTOTYPE(void output, (long blocks_read));
46
47/* print pretty progress meter with remaining no. of blocks and ETA on
48 * stderr
49 */
50void
51prettyprogress(long b, long nblocks, time_t starttime)
52{
53 /* print progress indication */
54 time_t spent, now;
55 long bpsec;
56 time(&now);
57 spent = now - starttime;
58 if(spent > 0 && (bpsec = b / spent) > 0) {
59 int len, i;
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 [",
65 nblocks - b,
66 hremain, minremain, secremain % 60);
67#define WIDTH 77
68 len = WIDTH - len;
69 for(i = 0; i < (b * (len-1) / nblocks); i++)
70 fprintf(stderr, "=");
71 fprintf(stderr, "|");
72 for(; i < len-2; i++)
73 fprintf(stderr, "-");
74 fprintf(stderr, "]\r");
75 fflush(stderr);
76 }
77
78 return;
79}
80
81int main(argc, argv)
82int argc;
83char *argv[];
84{
85 struct partition entry;
86 int fd, s, i, badprinted;
87 long b = 0, nblocks;
88 char *p;
89 time_t starttime;
90
91 if (argc != 2 && argc != 3) {
92 fprintf(stderr, "Usage: readall [-b | -t] file\n");
93 exit(1);
94 }
95 i = 1;
96
97 p = argv[1];
98 if (*p == '-' && *(p + 1) == 'b' && *(p + 2) == '\0') {
99 normal = 0;
100 i++;
101 name = argv[i];
102 }
103 if (*p == '-' && *(p + 1) == 't' && *(p + 2) == '\0') {
104 normal = 0;
105 total = 1;
106 i++;
107 name = argv[i];
108 }
109 fd = open(argv[i], O_RDONLY);
110 if (fd < 0) {
111 perror(argv[i]);
112 fprintf(stderr, "%s is not readable\n", argv[i]);
113 exit(1);
114 }
115
116 /* Get size of file */
117 if(ioctl(fd, DIOCGETP, &entry) < 0) {
118 perror("ioctl DIOCGETP");
119 return 1;
120 }
121 nblocks = div64u(entry.size, BLOCK_SIZE);
122
123 time(&starttime);
124 /* Read the entire file. Try it in large chunks, but if an error
125 * occurs, go to single reads for a while. */
126 while (1) {
127 if(lseek(fd, BLOCK_SIZE * b, SEEK_SET) < 0) {
128 perror("lseek");
129 return 1;
130 }
131 s = read(fd, a, BLOCK_SIZE * chunk);
132 if (s == BLOCK_SIZE * chunk) {
133 /* Normal read, no errors. */
134 b += chunk;
135 goodies++;
136 if (chunk == 1) {
137 if (goodies >= RESUME && b % DIVISOR == 0)
138 chunk = CHUNK;
139 }
140 if(b % DIVISOR == 0 && !normal) {
141 prettyprogress(b, nblocks, starttime);
142 }
143 } else if (s < 0) {
144 /* I/O error. */
145 if (chunk != 1) {
146 chunk = 1; /* regress to single block mode */
147 continue;
148 }
149 if (errors == STORE) {
150 fprintf(stderr,
151 "\n%ld Bad blocks is too many. Exiting\n",
152 errors);
153 exit(1);
154 }
155 rotten[(int) errors] = b; /* log the error */
156 b += chunk;
157 errors++;
158 } else {
159 /* End of file. */
160 b += s / BLOCK_SIZE;
161 if (normal) {
162 output(b);
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);
167 badprinted = 0;
168 if (normal) printf("Summary of bad blocks\n");
169
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);
174 badprinted = 1;
175 }
176 printf("%6ld ", rotten[i]);
177 if ((i + 1) % 7 == 0) {
178 printf("\n");
179 badprinted = 0;
180 }
181 }
182 printf("\n");
183 exit(0);
184 }
185 if (normal && b % DIVISOR == 0) output(b);
186 }
187}
188
189static void output(blocks_read)
190long blocks_read;
191{
192 fprintf(stderr, "%8ld blocks read, %5ld errors\r", blocks_read, errors);
193 fflush(stderr);
194}
Note: See TracBrowser for help on using the repository browser.