]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - misc/badblocks.c
Many files:
[thirdparty/e2fsprogs.git] / misc / badblocks.c
CommitLineData
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 *
dd018f5a 8 * Copyright 1995, 1996, 1997, 1998, 1999 by Theodore Ts'o
879ac920 9 * Copyright 1999 by David Beattie
19c78dc0 10 *
3839e657
TT
11 * This file is based on the minix file system programs fsck and mkfs
12 * written and copyrighted by Linus Torvalds <Linus.Torvalds@cs.helsinki.fi>
19c78dc0
TT
13 *
14 * %Begin-Header%
15 * This file may be redistributed under the terms of the GNU Public
16 * License.
17 * %End-Header%
3839e657
TT
18 */
19
20/*
21 * History:
22 * 93/05/26 - Creation from e2fsck
23 * 94/02/27 - Made a separate bad blocks checker
879ac920 24 * 99/06/30...99/07/26 - Added non-destructive write-testing,
dd018f5a
TT
25 * configurable blocks-at-once parameter,
26 * loading of badblocks list to avoid testing
27 * blocks known to be bad, multiple passes to
28 * make sure that no new blocks are added to the
29 * list. (Work done by David Beattie)
3839e657
TT
30 */
31
32#include <errno.h>
33#include <fcntl.h>
a418d3ad 34#ifdef HAVE_GETOPT_H
3839e657 35#include <getopt.h>
a418d3ad 36#endif
3839e657
TT
37#include <signal.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <unistd.h>
879ac920 42#include <setjmp.h>
3839e657
TT
43
44#include <sys/ioctl.h>
f3db3566 45#include <sys/types.h>
3839e657 46
a418d3ad 47#if HAVE_LINUX_FS_H
3839e657 48#include <linux/fd.h>
a418d3ad 49#endif
3839e657
TT
50
51#include "et/com_err.h"
d40259fd 52#include "ext2fs/ext2_io.h"
879ac920
TT
53#include <linux/ext2_fs.h>
54#include "ext2fs/ext2fs.h"
3839e657
TT
55
56const char * program_name = "badblocks";
00eedba1 57const char * done_string = "done \n";
3839e657
TT
58
59int v_flag = 0; /* verbose */
879ac920 60int w_flag = 0; /* do r/w test: 0=no, 1=yes, 2=non-destructive */
3839e657
TT
61int s_flag = 0; /* show progress of test */
62
818180cd 63static void usage(void)
3839e657 64{
879ac920 65 fprintf (stderr, "Usage: %s [-b block_size] [-i input_file] [-o output_file] [-svwn]\n [-c blocks_at_once] [-p num_passes] device blocks_count [start_count]\n",
3839e657
TT
66 program_name);
67 exit (1);
68}
69
19c78dc0
TT
70static unsigned long currently_testing = 0;
71static unsigned long num_blocks = 0;
879ac920
TT
72static ext2_badblocks_list bb_list = NULL;
73static FILE *out;
74static blk_t next_bad = 0;
75static ext2_badblocks_iterate bb_iter = NULL;
19c78dc0 76
dd018f5a
TT
77/*
78 * This routine reports a new bad block. If the bad block has already
79 * been seen before, then it returns 0; otherwise it returns 1.
80 */
81static int bb_output (unsigned long bad)
879ac920
TT
82{
83 errcode_t errcode;
84
dd018f5a
TT
85 if (ext2fs_badblocks_list_test(bb_list, bad))
86 return 0;
87
879ac920
TT
88 fprintf (out, "%lu\n", bad);
89
90 errcode = ext2fs_badblocks_list_add (bb_list, bad);
91 if (errcode) {
92 com_err (program_name, errcode, "adding to in-memory bad block list");
93 exit (1);
94 }
95
96 /* kludge:
97 increment the iteration through the bb_list if
98 an element was just added before the current iteration
99 position. This should not cause next_bad to change. */
100 if (bb_iter && bad < next_bad)
101 ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
dd018f5a 102 return 1;
879ac920
TT
103}
104
105static void print_status (void)
19c78dc0
TT
106{
107 fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
108 fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
109 fflush (stderr);
110}
111
112static void alarm_intr (int alnum)
113{
114 signal (SIGALRM, alarm_intr);
115 alarm(1);
116 if (!num_blocks)
117 return;
118 fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
119 fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
120 fflush (stderr);
121}
122
879ac920
TT
123static void *terminate_addr = NULL;
124
125static void terminate_intr (int signo)
126{
127 if (terminate_addr)
128 longjmp(terminate_addr,1);
129 exit(1);
130}
131
132static void capture_terminate (jmp_buf term_addr)
133{
134 terminate_addr = term_addr;
135 signal (SIGHUP, terminate_intr);
136 signal (SIGINT, terminate_intr);
137 signal (SIGPIPE, terminate_intr);
138 signal (SIGTERM, terminate_intr);
139 signal (SIGUSR1, terminate_intr);
140 signal (SIGUSR2, terminate_intr);
141}
142
3839e657 143/*
879ac920
TT
144 * Perform a read of a sequence of blocks; return the number of blocks
145 * successfully sequentially read.
3839e657 146 */
dd018f5a 147static long do_read (int dev, char * buffer, int try, int block_size,
3839e657
TT
148 unsigned long current_block)
149{
150 long got;
151
19c78dc0
TT
152 if (v_flag > 1)
153 print_status();
154
3839e657 155 /* Seek to the correct loc. */
19c78dc0 156 if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
f3db3566
TT
157 SEEK_SET) != (ext2_loff_t) current_block * block_size)
158 com_err (program_name, errno, "during seek");
3839e657
TT
159
160 /* Try the read */
161 got = read (dev, buffer, try * block_size);
162 if (got < 0)
163 got = 0;
9f10a7b3 164 if (got & 511)
f3db3566 165 fprintf (stderr,
879ac920
TT
166 "Weird value (%ld) in do_read\n", got);
167 got /= block_size;
168 return got;
169}
170
171/*
172 * Perform a write of a sequence of blocks; return the number of blocks
173 * successfully sequentially written.
174 */
dd018f5a 175static long do_write (int dev, char * buffer, int try, int block_size,
879ac920
TT
176 unsigned long current_block)
177{
178 long got;
179
180 if (v_flag > 1)
181 print_status();
182
183 /* Seek to the correct loc. */
184 if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
185 SEEK_SET) != (ext2_loff_t) current_block * block_size)
186 com_err (program_name, errno, "during seek");
187
188 /* Try the write */
189 got = write (dev, buffer, try * block_size);
190 if (got < 0)
191 got = 0;
192 if (got & 511)
193 fprintf (stderr,
194 "Weird value (%ld) in do_write\n", got);
3839e657
TT
195 got /= block_size;
196 return got;
197}
198
879ac920
TT
199static int host_dev;
200
a418d3ad
TT
201static void flush_bufs (int dev, int sync)
202{
203 if (v_flag
204#if !defined (BLKFLSBUF) && !defined (FDFLUSH)
205 && sync
206#endif
207 )
208 fprintf (stderr, "Flushing buffers\n");
209
879ac920 210 if (sync && fdatasync (dev) == -1)
a418d3ad
TT
211 com_err (program_name, errno, "during fsync");
212
879ac920
TT
213#ifdef BLKFLSBUF
214 ioctl (host_dev, BLKFLSBUF, 0); /* In case this is a HD */
a418d3ad
TT
215#endif
216#ifdef FDFLUSH
879ac920 217 ioctl (host_dev, FDFLUSH, 0); /* In case this is floppy */
a418d3ad
TT
218#endif
219}
220
879ac920 221static unsigned int test_ro (int dev, unsigned long blocks_count,
dd018f5a
TT
222 int block_size, unsigned long from_count,
223 unsigned long blocks_at_once)
3839e657 224{
3839e657
TT
225 char * blkbuf;
226 int try;
227 long got;
879ac920
TT
228 unsigned int bb_count = 0;
229 errcode_t errcode;
3839e657 230
879ac920
TT
231 errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
232 if (errcode) {
233 com_err (program_name, errcode, "while beginning bad block list iteration");
234 exit (1);
235 }
236 do {
237 ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
238 } while (next_bad && next_bad < from_count);
239
240 blkbuf = malloc (blocks_at_once * block_size);
3839e657
TT
241 if (!blkbuf)
242 {
243 com_err (program_name, ENOMEM, "while allocating buffers");
244 exit (1);
245 }
a418d3ad 246 flush_bufs (dev, 0);
f3db3566
TT
247 if (v_flag) {
248 fprintf (stderr,
249 "Checking for bad blocks in read-only mode\n");
250 fprintf (stderr, "From block %lu to %lu\n", from_count, blocks_count);
251 }
879ac920 252 try = blocks_at_once;
f3db3566 253 currently_testing = from_count;
3839e657 254 num_blocks = blocks_count;
19c78dc0 255 if (s_flag || v_flag > 1) {
3839e657 256 fprintf(stderr, "Checking for bad blocks (read-only test): ");
19c78dc0
TT
257 if (v_flag <= 1)
258 alarm_intr(SIGALRM);
3839e657
TT
259 }
260 while (currently_testing < blocks_count)
261 {
879ac920
TT
262 if (next_bad) {
263 if (currently_testing == next_bad) {
264 /* fprintf (out, "%lu\n", nextbad); */
265 ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
266 currently_testing++;
267 continue;
268 }
269 else if (currently_testing + try > next_bad)
270 try = next_bad - currently_testing;
271 }
3839e657
TT
272 if (currently_testing + try > blocks_count)
273 try = blocks_count - currently_testing;
879ac920 274 got = do_read (dev, blkbuf, try, block_size, currently_testing);
3839e657
TT
275 currently_testing += got;
276 if (got == try) {
879ac920 277 try = blocks_at_once;
3839e657
TT
278 continue;
279 }
280 else
281 try = 1;
879ac920 282 if (got == 0) {
dd018f5a 283 bb_count += bb_output(currently_testing++);
879ac920 284 }
3839e657
TT
285 }
286 num_blocks = 0;
287 alarm(0);
19c78dc0 288 if (s_flag || v_flag > 1)
00eedba1 289 fprintf(stderr, done_string);
879ac920 290
f3db3566 291 fflush (stderr);
3839e657 292 free (blkbuf);
879ac920
TT
293
294 ext2fs_badblocks_list_iterate_end(bb_iter);
295
296 return bb_count;
3839e657
TT
297}
298
879ac920 299static unsigned int test_rw (int dev, unsigned long blocks_count,
dd018f5a
TT
300 int block_size, unsigned long from_count,
301 unsigned long blocks_at_once)
3839e657
TT
302{
303 int i;
3839e657
TT
304 char * buffer;
305 unsigned char pattern[] = {0xaa, 0x55, 0xff, 0x00};
879ac920 306 unsigned int bb_count = 0;
3839e657
TT
307
308 buffer = malloc (2 * block_size);
309 if (!buffer)
310 {
311 com_err (program_name, ENOMEM, "while allocating buffers");
312 exit (1);
313 }
314
a418d3ad
TT
315 flush_bufs (dev, 0);
316
19c78dc0
TT
317 if (v_flag) {
318 fprintf(stderr,
319 "Checking for bad blocks in read-write mode\n");
320 fprintf(stderr, "From block %lu to %lu\n",
321 from_count, blocks_count);
322 }
323 for (i = 0; i < sizeof (pattern); i++) {
3839e657 324 memset (buffer, pattern[i], block_size);
f3db3566
TT
325 if (s_flag | v_flag)
326 fprintf (stderr, "Writing pattern 0x%08x: ",
3839e657 327 *((int *) buffer));
f3db3566
TT
328 num_blocks = blocks_count;
329 currently_testing = from_count;
19c78dc0 330 if (s_flag && v_flag <= 1)
f3db3566
TT
331 alarm_intr(SIGALRM);
332 for (;
333 currently_testing < blocks_count;
334 currently_testing++)
3839e657 335 {
19c78dc0 336 if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
f3db3566
TT
337 block_size, SEEK_SET) !=
338 (ext2_loff_t) currently_testing * block_size)
3839e657 339 com_err (program_name, errno,
f3db3566
TT
340 "during seek on block %d",
341 currently_testing);
19c78dc0
TT
342 if (v_flag > 1)
343 print_status();
3839e657
TT
344 write (dev, buffer, block_size);
345 }
f3db3566
TT
346 num_blocks = 0;
347 alarm (0);
348 if (s_flag | v_flag)
00eedba1 349 fprintf(stderr, done_string);
a418d3ad 350 flush_bufs (dev, 1);
f3db3566
TT
351 if (s_flag | v_flag)
352 fprintf (stderr, "Reading and comparing: ");
353 num_blocks = blocks_count;
354 currently_testing = from_count;
19c78dc0 355 if (s_flag && v_flag <= 1)
f3db3566
TT
356 alarm_intr(SIGALRM);
357 for (;
358 currently_testing < blocks_count;
359 currently_testing++)
3839e657 360 {
19c78dc0 361 if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
f3db3566
TT
362 block_size, SEEK_SET) !=
363 (ext2_loff_t) currently_testing * block_size)
3839e657 364 com_err (program_name, errno,
f3db3566
TT
365 "during seek on block %d",
366 currently_testing);
19c78dc0
TT
367 if (v_flag > 1)
368 print_status();
dd018f5a
TT
369 if ((read (dev, buffer + block_size, block_size)
370 < block_size) ||
371 memcmp(buffer, buffer + block_size, block_size))
372 bb_count = bb_output(currently_testing);
3839e657 373 }
f3db3566
TT
374 num_blocks = 0;
375 alarm (0);
376 if (s_flag | v_flag)
00eedba1 377 fprintf(stderr, done_string);
a418d3ad 378 flush_bufs (dev, 0);
3839e657 379 }
879ac920
TT
380
381 return bb_count;
382}
383
384static unsigned int test_nd (int dev, unsigned long blocks_count,
dd018f5a
TT
385 int block_size, unsigned long from_count,
386 unsigned long blocks_at_once)
879ac920 387{
dd018f5a 388 char *blkbuf, *save_ptr, *test_ptr, *read_ptr;
879ac920 389 char * ptr;
dd018f5a
TT
390 int try, i;
391 long got, used2;
392 unsigned long *bufblk;
393 unsigned long *bufblks;
879ac920 394 jmp_buf terminate_env;
879ac920 395 errcode_t errcode;
dd018f5a
TT
396 /* These are static to prevent being clobbered by the longjmp */
397 static long buf_used;
398 static unsigned int bb_count;
399
400 bb_count = 0;
401 buf_used = 0;
879ac920
TT
402
403 errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
404 if (errcode) {
dd018f5a
TT
405 com_err (program_name, errcode,
406 "while beginning bad block list iteration");
879ac920
TT
407 exit (1);
408 }
409 do {
410 ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
411 } while (next_bad && next_bad < from_count);
412
413 blkbuf = malloc (3 * blocks_at_once * block_size);
dd018f5a
TT
414 bufblk = malloc (blocks_at_once * sizeof(unsigned long));
415 bufblks = malloc (blocks_at_once * sizeof(unsigned long));
416 if (!blkbuf || !bufblk || !bufblks) {
879ac920
TT
417 com_err (program_name, ENOMEM, "while allocating buffers");
418 exit (1);
419 }
420
421 /* inititalize the test data randomly: */
422 if (v_flag) {
423 fprintf (stderr, "Initializing random test data\n");
424 }
425 for(ptr = blkbuf + blocks_at_once * block_size;
dd018f5a
TT
426 ptr < blkbuf + 2 * blocks_at_once * block_size;
427 ++ptr) {
879ac920
TT
428 (*ptr) = random() % (1 << sizeof(char));
429 }
430
431 flush_bufs (dev, 0);
432 if (v_flag) {
433 fprintf (stderr,
434 "Checking for bad blocks in non-destructive read-write mode\n");
435 fprintf (stderr, "From block %lu to %lu\n", from_count, blocks_count);
436 }
879ac920
TT
437 if (s_flag || v_flag > 1) {
438 fprintf (stderr, "Checking for bad blocks (non-destructive read-write test): ");
439 if (v_flag <= 1)
440 alarm_intr(SIGALRM);
441 }
442 if (! setjmp(terminate_env)) {
443 /* set up abend handler */
444 capture_terminate(terminate_env);
445
dd018f5a
TT
446 buf_used = 0; save_ptr = blkbuf;
447 test_ptr = blkbuf + (blocks_at_once * block_size);
448 currently_testing = from_count;
449 num_blocks = blocks_count;
450
451 while (currently_testing < blocks_count) {
879ac920
TT
452 try = blocks_at_once - buf_used;
453 if (next_bad) {
454 if (currently_testing == next_bad) {
455 /* fprintf (out, "%lu\n", nextbad); */
456 ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
457 bufblk[buf_used] = currently_testing++;
458 goto test_full_buf;
459 }
460 else if (currently_testing + try > next_bad)
461 try = next_bad - currently_testing;
462 }
463 if (currently_testing + try > blocks_count)
464 try = blocks_count - currently_testing;
dd018f5a
TT
465 got = do_read (dev, save_ptr, try, block_size,
466 currently_testing);
879ac920
TT
467
468 /* if reading succeeded, write the test data */
469 if (got) {
470 long written;
471
dd018f5a
TT
472 written = do_write (dev, test_ptr, got,
473 block_size,
474 currently_testing);
879ac920 475 if (written != got)
dd018f5a
TT
476 com_err (program_name, errno,
477 "during test data write, block %lu",
478 currently_testing + written);
879ac920
TT
479 }
480
481 bufblk[buf_used] = currently_testing;
482 bufblks[buf_used] = got;
483 buf_used += got;
dd018f5a
TT
484 save_ptr += got * block_size;
485 test_ptr += got * block_size;
879ac920
TT
486 currently_testing += got;
487 if (got != try)
dd018f5a 488 bb_count += bb_output(currently_testing++);
879ac920
TT
489
490 test_full_buf:
dd018f5a
TT
491 /*
492 * If there's room for more blocks to be
493 * tested this around, and we're not done yet
494 * testing the disk, go back and get some
495 * more blocks.
496 */
497 if ((buf_used != blocks_at_once) &&
498 (currently_testing != blocks_count))
499 continue;
879ac920 500
dd018f5a
TT
501 flush_bufs (dev, 1);
502
503 /*
504 * for each contiguous block that we read into
505 * the buffer (and wrote test data into
506 * afterwards), read it back (looping if
507 * necessary, to get past newly discovered
508 * unreadable blocks, of which there should be
509 * none, but with a hard drive which is
510 * unreliable, it has happened), and compare
511 * with the test data that was written; output
512 * to the bad block list if it doesn't match.
513 */
514 used2 = 0;
515 save_ptr = blkbuf;
516 test_ptr = blkbuf + (blocks_at_once * block_size);
517 read_ptr = blkbuf + (2 * blocks_at_once * block_size);
518 currently_testing = bufblk[0];
519 try = bufblks[0];
520 while (currently_testing < blocks_count) {
521
522 got = do_read (dev, read_ptr, try,
523 block_size, currently_testing);
524
525 /* test the comparison between all the
526 blocks successfully read */
527 for (i = 0; i < got; ++i)
528 if (memcmp (test_ptr, read_ptr,
529 block_size))
530 bb_count += bb_output(currently_testing + i);
531 if (got == 0) {
532 bb_count += bb_output(currently_testing);
533 got = 1;
534 }
535
536 /* when done, write back original data */
537 do_write (dev, save_ptr, got, block_size,
538 currently_testing);
539
540 currently_testing += got;
541 save_ptr += bufblks[got] * block_size;
542 test_ptr += bufblks[got] * block_size;
543 read_ptr += bufblks[got] * block_size;
544 try -= got;
545
546 if (try == 0) {
547 used2 += bufblks[used2];
548 if (used2 >= blocks_at_once)
549 break;
550 currently_testing = bufblk[used2];
551 try = bufblks[used2];
552 }
879ac920 553 }
dd018f5a
TT
554
555 /* empty the buffer so it can be reused */
556 buf_used = 0;
879ac920
TT
557 }
558 num_blocks = 0;
559 alarm(0);
560 if (s_flag || v_flag > 1)
561 fprintf(stderr, "done \n");
562
563 } else {
564 /* abnormal termination by a signal is handled here */
565 /* logic is: write back the data that is in the buffer,
566 so that we can maintain data integrity on disk. Then
567 abort. */
568 long buf_written;
569
570 fprintf(stderr, "Interrupt caught, cleaning up\n");
571
572 for (buf_written = 0;
573 buf_written < buf_used;
574 buf_written += bufblks[buf_written])
575 do_write (dev, blkbuf + buf_written * block_size,
dd018f5a
TT
576 bufblks[buf_written], block_size,
577 bufblk[buf_written]);
879ac920
TT
578
579 fflush (out);
dd018f5a 580 exit(1);
879ac920
TT
581 }
582
dd018f5a
TT
583 fflush(stderr);
584 free(blkbuf);
585 free(bufblk);
586 free(bufblks);
879ac920
TT
587
588 ext2fs_badblocks_list_iterate_end(bb_iter);
589
590 return bb_count;
3839e657
TT
591}
592
00e5433e 593int main (int argc, char ** argv)
3839e657 594{
519149fb 595 int c;
3839e657
TT
596 char * tmp;
597 char * device_name;
879ac920
TT
598 char * host_device_name = NULL;
599 char * input_file = NULL;
3839e657 600 char * output_file = NULL;
879ac920 601 FILE * in = NULL;
dd018f5a 602 int block_size = 1024;
879ac920 603 unsigned long blocks_at_once = 16;
f3db3566 604 unsigned long blocks_count, from_count;
879ac920
TT
605 int num_passes = 0;
606 int passes_clean = 0;
3839e657 607 int dev;
879ac920 608 errcode_t errcode;
3839e657
TT
609
610 setbuf(stdout, NULL);
611 setbuf(stderr, NULL);
612 if (argc && *argv)
613 program_name = *argv;
879ac920 614 while ((c = getopt (argc, argv, "b:i:o:svwnc:p:h:")) != EOF) {
3839e657
TT
615 switch (c) {
616 case 'b':
617 block_size = strtoul (optarg, &tmp, 0);
618 if (*tmp || block_size > 4096) {
619 com_err (program_name, 0,
620 "bad block size - %s", optarg);
621 exit (1);
622 }
623 break;
879ac920
TT
624 case 'i':
625 input_file = optarg;
626 break;
3839e657
TT
627 case 'o':
628 output_file = optarg;
629 break;
630 case 's':
631 s_flag = 1;
632 break;
633 case 'v':
19c78dc0 634 v_flag++;
3839e657
TT
635 break;
636 case 'w':
879ac920
TT
637 if (! w_flag)
638 w_flag = 1;
639 break;
640 case 'n':
641 w_flag = 2;
642 break;
643 case 'c':
644 blocks_at_once = strtoul (optarg, &tmp, 0);
645 if (*tmp) {
646 com_err (program_name, 0,
647 "bad simultaneous block count - %s", optarg);
648 exit (1);
649 }
650 break;
651 case 'p':
652 num_passes = strtoul (optarg, &tmp, 0);
653 if (*tmp) {
654 com_err (program_name, 0,
655 "bad number of clean passes - %s", optarg);
656 exit (1);
657 }
658 break;
659 case 'h':
660 host_device_name = optarg;
3839e657
TT
661 break;
662 default:
818180cd 663 usage();
3839e657
TT
664 }
665 }
666 if (optind > argc - 1)
818180cd 667 usage();
3839e657
TT
668 device_name = argv[optind++];
669 if (optind > argc - 1)
818180cd 670 usage();
3839e657
TT
671 blocks_count = strtoul (argv[optind], &tmp, 0);
672 if (*tmp)
673 {
674 com_err (program_name, 0, "bad blocks count - %s", argv[optind]);
675 exit (1);
676 }
f3db3566
TT
677 if (++optind <= argc-1) {
678 from_count = strtoul (argv[optind], &tmp, 0);
679 } else from_count = 0;
680 if (from_count >= blocks_count) {
681 com_err (program_name, 0, "bad blocks range: %lu-%lu",
682 from_count, blocks_count);
683 exit (1);
684 }
3839e657
TT
685 dev = open (device_name, w_flag ? O_RDWR : O_RDONLY);
686 if (dev == -1)
687 {
879ac920 688 com_err (program_name, errno, "while trying to open %s",
3839e657
TT
689 device_name);
690 exit (1);
691 }
879ac920
TT
692 if (host_device_name) {
693 host_dev = open (host_device_name, O_RDONLY);
694 if (host_dev == -1)
695 {
696 com_err (program_name, errno, "while trying to open %s",
697 host_device_name);
698 exit (1);
699 }
700 } else
701 host_dev = dev;
702 if (input_file)
703 if (strcmp (input_file, "-") == 0)
704 in = stdin;
705 else {
706 in = fopen (input_file, "r");
707 if (in == NULL)
708 {
709 com_err (program_name, errno,"while trying to open %s",
710 input_file);
711 exit (1);
712 }
713 }
3839e657
TT
714 if (output_file && strcmp (output_file, "-") != 0)
715 {
716 out = fopen (output_file, "w");
717 if (out == NULL)
718 {
719 com_err (program_name, errno,"while trying to open %s",
879ac920 720 output_file);
3839e657
TT
721 exit (1);
722 }
723 }
724 else
725 out = stdout;
879ac920
TT
726
727 errcode = ext2fs_badblocks_list_create(&bb_list,0);
728 if (errcode) {
729 com_err (program_name, errcode, "creating in-memory bad blocks list");
730 exit (1);
731 }
732
733 if (in) {
734 for(;;) {
735 switch(fscanf (in, "%lu\n", &next_bad)) {
736 case 0:
737 com_err (program_name, 0, "input file - bad format");
738 exit (1);
739 case EOF:
740 break;
741 default:
742 errcode = ext2fs_badblocks_list_add(bb_list,next_bad);
743 if (errcode) {
744 com_err (program_name, errcode, "adding to in-memory bad block list");
745 exit (1);
746 }
747 continue;
748 }
749 break;
750 }
751
752 if (in != stdin)
753 fclose (in);
754 }
755
756 do {
757 unsigned int bb_count;
758
759 (bb_count =
760
761 (w_flag == 2 ? test_nd
762 : w_flag ? test_rw
763 : test_ro)
764 (dev, blocks_count, block_size, from_count,
765 blocks_at_once)
766 ) ? passes_clean = 0 : ++passes_clean;
767
768 if (v_flag)
769 fprintf(stderr,"Pass completed, %u bad blocks found.\n", bb_count);
770
771 } while (passes_clean < num_passes);
772
3839e657
TT
773 close (dev);
774 if (out != stdout)
775 fclose (out);
879ac920 776 return 0;
3839e657 777}