badblocks.c revision cd130a0887b5e5e9436533bbcda4c17ec5202788
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 <linux/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 bindtextdomain(NLS_CAT_NAME, LOCALEDIR); 655 textdomain(NLS_CAT_NAME); 656#endif 657 test_func = test_ro; 658 659 if (argc && *argv) 660 program_name = *argv; 661 while ((c = getopt (argc, argv, "b:fi:o:svwnc:p:h:")) != EOF) { 662 switch (c) { 663 case 'b': 664 block_size = strtoul (optarg, &tmp, 0); 665 if (*tmp || block_size > 4096) { 666 com_err (program_name, 0, 667 _("bad block size - %s"), optarg); 668 exit (1); 669 } 670 break; 671 case 'f': 672 force++; 673 break; 674 case 'i': 675 input_file = optarg; 676 break; 677 case 'o': 678 output_file = optarg; 679 break; 680 case 's': 681 s_flag = 1; 682 break; 683 case 'v': 684 v_flag++; 685 break; 686 case 'w': 687 if (w_flag) 688 usage(); 689 test_func = test_rw; 690 w_flag = 1; 691 break; 692 case 'n': 693 if (w_flag) 694 usage(); 695 test_func = test_nd; 696 w_flag = 2; 697 break; 698 case 'c': 699 blocks_at_once = strtoul (optarg, &tmp, 0); 700 if (*tmp) { 701 com_err (program_name, 0, 702 "bad simultaneous block count - %s", optarg); 703 exit (1); 704 } 705 break; 706 case 'p': 707 num_passes = strtoul (optarg, &tmp, 0); 708 if (*tmp) { 709 com_err (program_name, 0, 710 "bad number of clean passes - %s", optarg); 711 exit (1); 712 } 713 break; 714 case 'h': 715 host_device_name = optarg; 716 break; 717 default: 718 usage(); 719 } 720 } 721 if (optind > argc - 1) 722 usage(); 723 device_name = argv[optind++]; 724 if (optind > argc - 1) { 725 errcode = ext2fs_get_device_size(device_name, 726 block_size, 727 &last_block); 728 if (errcode == EXT2_ET_UNIMPLEMENTED) { 729 com_err(program_name, 0, 730 _("Couldn't determine device size; you " 731 "must specify\nthe size manually\n")); 732 exit(1); 733 } 734 if (errcode) { 735 com_err(program_name, errcode, 736 _("while trying to determine device size")); 737 exit(1); 738 } 739 } else { 740 last_block = strtoul (argv[optind], &tmp, 0); 741 if (*tmp) { 742 com_err (program_name, 0, _("bad blocks count - %s"), 743 argv[optind]); 744 exit (1); 745 } 746 optind++; 747 } 748 if (optind <= argc-1) { 749 from_count = strtoul (argv[optind], &tmp, 0); 750 if (*tmp) { 751 com_err (program_name, 0, _("bad starting block - %s"), 752 argv[optind]); 753 exit (1); 754 } 755 } else from_count = 0; 756 if (from_count >= last_block) { 757 com_err (program_name, 0, _("bad blocks range: %lu-%lu"), 758 from_count, last_block); 759 exit (1); 760 } 761 if (w_flag) 762 check_mount(device_name); 763 764 dev = open (device_name, w_flag ? O_RDWR : O_RDONLY); 765 if (dev == -1) 766 { 767 com_err (program_name, errno, _("while trying to open %s"), 768 device_name); 769 exit (1); 770 } 771 if (host_device_name) { 772 host_dev = open (host_device_name, O_RDONLY); 773 if (host_dev == -1) 774 { 775 com_err (program_name, errno, 776 _("while trying to open %s"), 777 host_device_name); 778 exit (1); 779 } 780 } else 781 host_dev = dev; 782 if (input_file) 783 if (strcmp (input_file, "-") == 0) 784 in = stdin; 785 else { 786 in = fopen (input_file, "r"); 787 if (in == NULL) 788 { 789 com_err (program_name, errno, 790 _("while trying to open %s"), 791 input_file); 792 exit (1); 793 } 794 } 795 if (output_file && strcmp (output_file, "-") != 0) 796 { 797 out = fopen (output_file, "w"); 798 if (out == NULL) 799 { 800 com_err (program_name, errno, 801 _("while trying to open %s"), 802 output_file); 803 exit (1); 804 } 805 } 806 else 807 out = stdout; 808 809 errcode = ext2fs_badblocks_list_create(&bb_list,0); 810 if (errcode) { 811 com_err (program_name, errcode, 812 _("creating in-memory bad blocks list")); 813 exit (1); 814 } 815 816 if (in) { 817 for(;;) { 818 switch(fscanf (in, "%u\n", &next_bad)) { 819 case 0: 820 com_err (program_name, 0, "input file - bad format"); 821 exit (1); 822 case EOF: 823 break; 824 default: 825 errcode = ext2fs_badblocks_list_add(bb_list,next_bad); 826 if (errcode) { 827 com_err (program_name, errcode, _("adding to in-memory bad block list")); 828 exit (1); 829 } 830 continue; 831 } 832 break; 833 } 834 835 if (in != stdin) 836 fclose (in); 837 } 838 839 do { 840 unsigned int bb_count; 841 842 bb_count = test_func(dev, last_block, block_size, 843 from_count, blocks_at_once); 844 if (bb_count) 845 passes_clean = 0; 846 else 847 ++passes_clean; 848 849 if (v_flag) 850 fprintf(stderr, 851 _("Pass completed, %u bad blocks found.\n"), 852 bb_count); 853 854 } while (passes_clean < num_passes); 855 856 close (dev); 857 if (out != stdout) 858 fclose (out); 859 return 0; 860} 861 862