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