]>
Commit | Line | Data |
---|---|---|
3839e657 TT |
1 | /* |
2 | * badblocks.c - Bad blocks checker | |
3 | * | |
4 | * Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr> | |
5 | * Laboratoire MASI, Institut Blaise Pascal | |
6 | * Universite Pierre et Marie Curie (Paris VI) | |
7 | * | |
8 | * This file is based on the minix file system programs fsck and mkfs | |
9 | * written and copyrighted by Linus Torvalds <Linus.Torvalds@cs.helsinki.fi> | |
10 | * | |
11 | * This file can be redistributed under the terms of the GNU General | |
12 | * Public License | |
13 | */ | |
14 | ||
15 | /* | |
16 | * History: | |
17 | * 93/05/26 - Creation from e2fsck | |
18 | * 94/02/27 - Made a separate bad blocks checker | |
19 | */ | |
20 | ||
21 | #include <errno.h> | |
22 | #include <fcntl.h> | |
23 | #include <getopt.h> | |
24 | #include <signal.h> | |
25 | #include <stdio.h> | |
26 | #include <stdlib.h> | |
27 | #include <string.h> | |
28 | #include <unistd.h> | |
29 | ||
30 | #include <sys/ioctl.h> | |
f3db3566 | 31 | #include <sys/types.h> |
3839e657 TT |
32 | |
33 | #include <linux/fd.h> | |
34 | #include <linux/fs.h> | |
35 | ||
36 | #include "et/com_err.h" | |
f3db3566 | 37 | #include "ext2fs/io.h" |
3839e657 TT |
38 | |
39 | const char * program_name = "badblocks"; | |
40 | ||
41 | int v_flag = 0; /* verbose */ | |
42 | int w_flag = 0; /* do r/w test */ | |
43 | int s_flag = 0; /* show progress of test */ | |
44 | ||
45 | static volatile void usage (void) | |
46 | { | |
f3db3566 | 47 | fprintf (stderr, "Usage: %s [-b block_size] [-o output_file] [-svw] device blocks_count\n [start_count]\n", |
3839e657 TT |
48 | program_name); |
49 | exit (1); | |
50 | } | |
51 | ||
52 | /* | |
53 | * Perform a test of a block; return the number of blocks readable/writeable. | |
54 | */ | |
55 | static long do_test (int dev, char * buffer, int try, unsigned long block_size, | |
56 | unsigned long current_block) | |
57 | { | |
58 | long got; | |
59 | ||
60 | /* Seek to the correct loc. */ | |
f3db3566 TT |
61 | if (ext2_llseek (dev, (ext2_loff_t) current_block * block_size, |
62 | SEEK_SET) != (ext2_loff_t) current_block * block_size) | |
63 | com_err (program_name, errno, "during seek"); | |
3839e657 TT |
64 | |
65 | /* Try the read */ | |
66 | got = read (dev, buffer, try * block_size); | |
67 | if (got < 0) | |
68 | got = 0; | |
69 | if (got & (block_size - 1)) | |
f3db3566 TT |
70 | fprintf (stderr, |
71 | "Weird value (%ld) in do_test: probably bugs\n", | |
72 | got); | |
3839e657 TT |
73 | got /= block_size; |
74 | return got; | |
75 | } | |
76 | ||
77 | static unsigned long currently_testing = 0; | |
78 | static unsigned long num_blocks = 0; | |
79 | ||
80 | static void alarm_intr (int alnum) | |
81 | { | |
82 | signal (SIGALRM, alarm_intr); | |
83 | alarm(1); | |
84 | if (!num_blocks) | |
85 | return; | |
f3db3566 TT |
86 | fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks); |
87 | fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); | |
3839e657 TT |
88 | fflush (stderr); |
89 | } | |
90 | ||
91 | static void test_ro (int dev, unsigned long blocks_count, | |
f3db3566 TT |
92 | unsigned long block_size, FILE * out, |
93 | unsigned long from_count) | |
3839e657 TT |
94 | { |
95 | #define TEST_BUFFER_BLOCKS 16 | |
96 | char * blkbuf; | |
97 | int try; | |
98 | long got; | |
99 | ||
100 | blkbuf = malloc (TEST_BUFFER_BLOCKS * block_size); | |
101 | if (!blkbuf) | |
102 | { | |
103 | com_err (program_name, ENOMEM, "while allocating buffers"); | |
104 | exit (1); | |
105 | } | |
106 | ||
107 | if (v_flag) | |
108 | fprintf (stderr, "Flushing buffers\n"); | |
109 | ioctl (dev, BLKFLSBUF, 0); /* In case this is a HD */ | |
110 | ioctl (dev, FDFLUSH, 0); /* In case this is floppy */ | |
f3db3566 TT |
111 | if (v_flag) { |
112 | fprintf (stderr, | |
113 | "Checking for bad blocks in read-only mode\n"); | |
114 | fprintf (stderr, "From block %lu to %lu\n", from_count, blocks_count); | |
115 | } | |
3839e657 | 116 | try = TEST_BUFFER_BLOCKS; |
f3db3566 | 117 | currently_testing = from_count; |
3839e657 TT |
118 | num_blocks = blocks_count; |
119 | if (s_flag) { | |
120 | fprintf(stderr, "Checking for bad blocks (read-only test): "); | |
121 | alarm_intr(SIGALRM); | |
122 | } | |
123 | while (currently_testing < blocks_count) | |
124 | { | |
125 | if (currently_testing + try > blocks_count) | |
126 | try = blocks_count - currently_testing; | |
127 | got = do_test (dev, blkbuf, try, block_size, currently_testing); | |
128 | currently_testing += got; | |
129 | if (got == try) { | |
130 | try = TEST_BUFFER_BLOCKS; | |
131 | continue; | |
132 | } | |
133 | else | |
134 | try = 1; | |
135 | if (got == 0) | |
136 | fprintf (out, "%lu\n", currently_testing++); | |
137 | } | |
138 | num_blocks = 0; | |
139 | alarm(0); | |
140 | if (s_flag) | |
f3db3566 TT |
141 | fprintf(stderr, "done \n"); |
142 | fflush (stderr); | |
3839e657 TT |
143 | free (blkbuf); |
144 | } | |
145 | ||
146 | static void test_rw (int dev, unsigned long blocks_count, | |
f3db3566 TT |
147 | unsigned long block_size, FILE * out, |
148 | unsigned long from_count) | |
3839e657 TT |
149 | { |
150 | int i; | |
3839e657 TT |
151 | char * buffer; |
152 | unsigned char pattern[] = {0xaa, 0x55, 0xff, 0x00}; | |
153 | ||
154 | buffer = malloc (2 * block_size); | |
155 | if (!buffer) | |
156 | { | |
157 | com_err (program_name, ENOMEM, "while allocating buffers"); | |
158 | exit (1); | |
159 | } | |
160 | ||
161 | if (v_flag) | |
162 | fprintf (stderr, "Flushing buffers\n"); | |
163 | ioctl (dev, BLKFLSBUF, 0); /* In case this is a HD */ | |
164 | ioctl (dev, FDFLUSH, 0); /* In case this is floppy */ | |
165 | if (v_flag) | |
166 | fprintf (stderr, "Checking for bad blocks in read-write mode\n"); | |
167 | for (i = 0; i < sizeof (pattern); i++) | |
168 | { | |
169 | memset (buffer, pattern[i], block_size); | |
f3db3566 TT |
170 | if (s_flag | v_flag) |
171 | fprintf (stderr, "Writing pattern 0x%08x: ", | |
3839e657 | 172 | *((int *) buffer)); |
f3db3566 TT |
173 | num_blocks = blocks_count; |
174 | currently_testing = from_count; | |
175 | if (s_flag) | |
176 | alarm_intr(SIGALRM); | |
177 | for (; | |
178 | currently_testing < blocks_count; | |
179 | currently_testing++) | |
3839e657 | 180 | { |
f3db3566 TT |
181 | if (ext2_llseek (dev, (ext2_loff_t) currently_testing * |
182 | block_size, SEEK_SET) != | |
183 | (ext2_loff_t) currently_testing * block_size) | |
3839e657 | 184 | com_err (program_name, errno, |
f3db3566 TT |
185 | "during seek on block %d", |
186 | currently_testing); | |
3839e657 TT |
187 | write (dev, buffer, block_size); |
188 | } | |
f3db3566 TT |
189 | num_blocks = 0; |
190 | alarm (0); | |
191 | if (s_flag | v_flag) | |
192 | fprintf(stderr, "done \n"); | |
3839e657 TT |
193 | if (v_flag) |
194 | fprintf (stderr, "Flushing buffers\n"); | |
195 | if (fsync (dev) == -1) | |
196 | com_err (program_name, errno, "during fsync"); | |
197 | ioctl (dev, BLKFLSBUF, 0); /* In case this is a HD */ | |
198 | ioctl (dev, FDFLUSH, 0); /* In case this is floppy */ | |
f3db3566 TT |
199 | if (s_flag | v_flag) |
200 | fprintf (stderr, "Reading and comparing: "); | |
201 | num_blocks = blocks_count; | |
202 | currently_testing = from_count; | |
203 | if (s_flag) | |
204 | alarm_intr(SIGALRM); | |
205 | for (; | |
206 | currently_testing < blocks_count; | |
207 | currently_testing++) | |
3839e657 | 208 | { |
f3db3566 TT |
209 | if (ext2_llseek (dev, (ext2_loff_t) currently_testing * |
210 | block_size, SEEK_SET) != | |
211 | (ext2_loff_t) currently_testing * block_size) | |
3839e657 | 212 | com_err (program_name, errno, |
f3db3566 TT |
213 | "during seek on block %d", |
214 | currently_testing); | |
3839e657 | 215 | if (read (dev, buffer + block_size, block_size) < block_size) |
f3db3566 | 216 | fprintf (out, "%ld\n", currently_testing); |
3839e657 | 217 | else if (memcmp (buffer, buffer + block_size, block_size)) |
f3db3566 | 218 | fprintf (out, "%ld\n", currently_testing); |
3839e657 | 219 | } |
f3db3566 TT |
220 | num_blocks = 0; |
221 | alarm (0); | |
222 | if (s_flag | v_flag) | |
223 | fprintf(stderr, "done \n"); | |
3839e657 TT |
224 | if (v_flag) |
225 | fprintf (stderr, "Flushing buffers\n"); | |
226 | ioctl (dev, BLKFLSBUF, 0); /* In case this is a HD */ | |
227 | ioctl (dev, FDFLUSH, 0); /* In case this is floppy */ | |
228 | } | |
229 | } | |
230 | ||
231 | void main (int argc, char ** argv) | |
232 | { | |
233 | char c; | |
234 | char * tmp; | |
235 | char * device_name; | |
236 | char * output_file = NULL; | |
237 | FILE * out; | |
238 | unsigned long block_size = 1024; | |
f3db3566 | 239 | unsigned long blocks_count, from_count; |
3839e657 TT |
240 | int dev; |
241 | ||
242 | setbuf(stdout, NULL); | |
243 | setbuf(stderr, NULL); | |
244 | if (argc && *argv) | |
245 | program_name = *argv; | |
246 | while ((c = getopt (argc, argv, "b:o:svw")) != EOF) { | |
247 | switch (c) { | |
248 | case 'b': | |
249 | block_size = strtoul (optarg, &tmp, 0); | |
250 | if (*tmp || block_size > 4096) { | |
251 | com_err (program_name, 0, | |
252 | "bad block size - %s", optarg); | |
253 | exit (1); | |
254 | } | |
255 | break; | |
256 | case 'o': | |
257 | output_file = optarg; | |
258 | break; | |
259 | case 's': | |
260 | s_flag = 1; | |
261 | break; | |
262 | case 'v': | |
263 | v_flag = 1; | |
264 | break; | |
265 | case 'w': | |
266 | w_flag = 1; | |
267 | break; | |
268 | default: | |
269 | usage (); | |
270 | } | |
271 | } | |
272 | if (optind > argc - 1) | |
273 | usage (); | |
274 | device_name = argv[optind++]; | |
275 | if (optind > argc - 1) | |
276 | usage (); | |
277 | blocks_count = strtoul (argv[optind], &tmp, 0); | |
278 | if (*tmp) | |
279 | { | |
280 | com_err (program_name, 0, "bad blocks count - %s", argv[optind]); | |
281 | exit (1); | |
282 | } | |
f3db3566 TT |
283 | if (++optind <= argc-1) { |
284 | from_count = strtoul (argv[optind], &tmp, 0); | |
285 | } else from_count = 0; | |
286 | if (from_count >= blocks_count) { | |
287 | com_err (program_name, 0, "bad blocks range: %lu-%lu", | |
288 | from_count, blocks_count); | |
289 | exit (1); | |
290 | } | |
3839e657 TT |
291 | dev = open (device_name, w_flag ? O_RDWR : O_RDONLY); |
292 | if (dev == -1) | |
293 | { | |
294 | com_err (program_name, errno,"while trying to open %s", | |
295 | device_name); | |
296 | exit (1); | |
297 | } | |
298 | if (output_file && strcmp (output_file, "-") != 0) | |
299 | { | |
300 | out = fopen (output_file, "w"); | |
301 | if (out == NULL) | |
302 | { | |
303 | com_err (program_name, errno,"while trying to open %s", | |
304 | device_name); | |
305 | exit (1); | |
306 | } | |
307 | } | |
308 | else | |
309 | out = stdout; | |
310 | if (w_flag) | |
f3db3566 | 311 | test_rw (dev, blocks_count, block_size, out, from_count); |
3839e657 | 312 | else |
f3db3566 | 313 | test_ro (dev, blocks_count, block_size, out, from_count); |
3839e657 TT |
314 | close (dev); |
315 | if (out != stdout) | |
316 | fclose (out); | |
317 | } |