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