2 * badblocks.c - Bad blocks checker
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)
8 * Copyright 1995, 1996, 1997, 1998, 1999 by Theodore Ts'o
9 * Copyright 1999 by David Beattie
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>
15 * This file may be redistributed under the terms of the GNU Public
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)
32 #define _GNU_SOURCE /* for O_DIRECT */
51 #include <sys/ioctl.h>
52 #include <sys/types.h>
54 #include "et/com_err.h"
55 #include "ext2fs/ext2_io.h"
56 #include "ext2fs/ext2_fs.h"
57 #include "ext2fs/ext2fs.h"
58 #include "nls-enable.h"
60 const char * program_name = "badblocks";
61 const char * done_string = N_("done \n");
63 static int v_flag = 0; /* verbose */
64 static int w_flag = 0; /* do r/w test: 0=no, 1=yes,
65 * 2=non-destructive */
66 static int s_flag = 0; /* show progress of test */
67 static int force = 0; /* force check of mounted device */
68 static int t_flag = 0; /* number of test patterns */
69 static int t_max = 0; /* allocated test patterns */
70 static unsigned int *t_patts = NULL; /* test patterns */
71 static int current_O_DIRECT = 0; /* Current status of O_DIRECT flag */
72 static int exclusive_ok = 0;
76 unsigned int sys_page_size = 4096;
78 static void usage(void)
80 fprintf(stderr, _("Usage: %s [-b block_size] [-i input_file] [-o output_file] [-svwnf]\n [-c blocks_at_once] [-p num_passes] [-t test_pattern [-t test_pattern [...]]]\n device [last_block [start_block]]\n"),
85 static void exclusive_usage(void)
88 _("%s: The -n and -w options are mutually exclusive.\n\n"),
93 static blk_t currently_testing = 0;
94 static blk_t num_blocks = 0;
95 static ext2_badblocks_list bb_list = NULL;
97 static blk_t next_bad = 0;
98 static ext2_badblocks_iterate bb_iter = NULL;
100 static void *allocate_buffer(size_t size)
104 #ifdef HAVE_POSIX_MEMALIGN
105 if (posix_memalign(&ret, sys_page_size, size) < 0)
109 ret = memalign(sys_page_size, size);
113 #endif /* HAVE_VALLOC */
114 #endif /* HAVE_MEMALIGN */
115 #endif /* HAVE_POSIX_MEMALIGN */
124 * This routine reports a new bad block. If the bad block has already
125 * been seen before, then it returns 0; otherwise it returns 1.
127 static int bb_output (blk_t bad)
131 if (ext2fs_badblocks_list_test(bb_list, bad))
134 fprintf(out, "%lu\n", (unsigned long) bad);
137 errcode = ext2fs_badblocks_list_add (bb_list, bad);
139 com_err (program_name, errcode, "adding to in-memory bad block list");
144 increment the iteration through the bb_list if
145 an element was just added before the current iteration
146 position. This should not cause next_bad to change. */
147 if (bb_iter && bad < next_bad)
148 ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
152 static void print_status(void)
154 fprintf(stderr, "%15lu/%15lu", (unsigned long) currently_testing,
155 (unsigned long) num_blocks);
156 fputs("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", stderr);
160 static void alarm_intr(int alnum EXT2FS_ATTR((unused)))
162 signal (SIGALRM, alarm_intr);
169 static void *terminate_addr = NULL;
171 static void terminate_intr(int signo EXT2FS_ATTR((unused)))
174 longjmp(terminate_addr,1);
178 static void capture_terminate(jmp_buf term_addr)
180 terminate_addr = term_addr;
181 signal (SIGHUP, terminate_intr);
182 signal (SIGINT, terminate_intr);
183 signal (SIGPIPE, terminate_intr);
184 signal (SIGTERM, terminate_intr);
185 signal (SIGUSR1, terminate_intr);
186 signal (SIGUSR2, terminate_intr);
189 static void uncapture_terminate(void)
191 terminate_addr = NULL;
192 signal (SIGHUP, SIG_DFL);
193 signal (SIGINT, SIG_DFL);
194 signal (SIGPIPE, SIG_DFL);
195 signal (SIGTERM, SIG_DFL);
196 signal (SIGUSR1, SIG_DFL);
197 signal (SIGUSR2, SIG_DFL);
200 static void set_o_direct(int dev, unsigned char *buffer, size_t size,
204 int new_flag = O_DIRECT;
207 if ((((unsigned long) buffer & (sys_page_size - 1)) != 0) ||
208 ((size & (sys_page_size - 1)) != 0) ||
209 ((current_block & ((sys_page_size >> 9)-1)) != 0))
212 if (new_flag != current_O_DIRECT) {
213 /* printf("%s O_DIRECT\n", new_flag ? "Setting" : "Clearing"); */
214 flag = fcntl(dev, F_GETFL);
216 flag = (flag & ~O_DIRECT) | new_flag;
217 fcntl(dev, F_SETFL, flag);
219 current_O_DIRECT = new_flag;
225 static void pattern_fill(unsigned char *buffer, unsigned int pattern,
229 unsigned char bpattern[sizeof(pattern)], *ptr;
231 if (pattern == (unsigned int) ~0) {
232 for (ptr = buffer; ptr < buffer + n; ptr++) {
233 (*ptr) = random() % (1 << (8 * sizeof(char)));
236 fputs(_("Testing with random pattern: "), stderr);
239 for (i = 0; i < sizeof(bpattern); i++) {
242 bpattern[i] = pattern & 0xFF;
243 pattern = pattern >> 8;
246 for (ptr = buffer, i = nb; ptr < buffer + n; ptr++) {
253 if (s_flag | v_flag) {
254 fputs(_("Testing with pattern 0x"), stderr);
255 for (i = 0; i <= nb; i++)
256 fprintf(stderr, "%02x", buffer[i]);
263 * Perform a read of a sequence of blocks; return the number of blocks
264 * successfully sequentially read.
266 static int do_read (int dev, unsigned char * buffer, int try, int block_size,
271 set_o_direct(dev, buffer, try * block_size, current_block);
276 /* Seek to the correct loc. */
277 if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
278 SEEK_SET) != (ext2_loff_t) current_block * block_size)
279 com_err (program_name, errno, _("during seek"));
282 got = read (dev, buffer, try * block_size);
286 fprintf(stderr, _("Weird value (%ld) in do_read\n"), got);
292 * Perform a write of a sequence of blocks; return the number of blocks
293 * successfully sequentially written.
295 static int do_write(int dev, unsigned char * buffer, int try, int block_size,
296 unsigned long current_block)
300 set_o_direct(dev, buffer, try * block_size, current_block);
305 /* Seek to the correct loc. */
306 if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
307 SEEK_SET) != (ext2_loff_t) current_block * block_size)
308 com_err (program_name, errno, _("during seek"));
311 got = write (dev, buffer, try * block_size);
315 fprintf(stderr, "Weird value (%ld) in do_write\n", got);
322 static void flush_bufs(void)
326 retval = ext2fs_sync_device(host_dev, 1);
328 com_err(program_name, retval, _("during ext2fs_sync_device"));
331 static unsigned int test_ro (int dev, blk_t last_block,
332 int block_size, blk_t from_count,
333 unsigned int blocks_at_once)
335 unsigned char * blkbuf;
338 unsigned int bb_count = 0;
341 errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
343 com_err (program_name, errcode,
344 _("while beginning bad block list iteration"));
348 ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
349 } while (next_bad && next_bad < from_count);
352 blkbuf = allocate_buffer((blocks_at_once + 1) * block_size);
354 blkbuf = allocate_buffer(blocks_at_once * block_size);
358 com_err (program_name, ENOMEM, _("while allocating buffers"));
362 fprintf (stderr, _("Checking blocks %lu to %lu\n"),
363 (unsigned long) from_count,
364 (unsigned long) last_block - 1);
367 fputs(_("Checking for bad blocks in read-only mode\n"), stderr);
368 pattern_fill(blkbuf + blocks_at_once * block_size,
369 t_patts[0], block_size);
372 try = blocks_at_once;
373 currently_testing = from_count;
374 num_blocks = last_block - 1;
375 if (!t_flag && (s_flag || v_flag)) {
376 fputs(_("Checking for bad blocks (read-only test): "), stderr);
380 while (currently_testing < last_block)
383 if (currently_testing == next_bad) {
384 /* fprintf (out, "%lu\n", nextbad); */
385 ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
389 else if (currently_testing + try > next_bad)
390 try = next_bad - currently_testing;
392 if (currently_testing + try > last_block)
393 try = last_block - currently_testing;
394 got = do_read (dev, blkbuf, try, block_size, currently_testing);
396 /* test the comparison between all the
397 blocks successfully read */
399 for (i = 0; i < got; ++i)
400 if (memcmp (blkbuf+i*block_size,
401 blkbuf+blocks_at_once*block_size,
403 bb_count += bb_output(currently_testing + i);
405 currently_testing += got;
407 try = blocks_at_once;
408 /* recover page-aligned offset for O_DIRECT */
409 if ( (blocks_at_once >= sys_page_size >> 9)
410 && (currently_testing % (sys_page_size >> 9)!= 0))
411 try -= (sys_page_size >> 9)
413 % (sys_page_size >> 9));
419 bb_count += bb_output(currently_testing++);
424 if (s_flag || v_flag)
425 fputs(_(done_string), stderr);
430 ext2fs_badblocks_list_iterate_end(bb_iter);
435 static unsigned int test_rw (int dev, blk_t last_block,
436 int block_size, blk_t from_count,
437 unsigned int blocks_at_once)
439 unsigned char *buffer, *read_buffer;
440 const unsigned int patterns[] = {0xaa, 0x55, 0xff, 0x00};
441 const unsigned int *pattern;
442 int i, try, got, nr_pattern, pat_idx;
443 unsigned int bb_count = 0;
445 buffer = allocate_buffer(2 * blocks_at_once * block_size);
446 read_buffer = buffer + blocks_at_once * block_size;
449 com_err (program_name, ENOMEM, _("while allocating buffers"));
456 fputs(_("Checking for bad blocks in read-write mode\n"),
458 fprintf(stderr, _("From block %lu to %lu\n"),
459 (unsigned long) from_count,
460 (unsigned long) last_block);
467 nr_pattern = sizeof(patterns) / sizeof(patterns[0]);
469 for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) {
470 pattern_fill(buffer, pattern[pat_idx],
471 blocks_at_once * block_size);
472 num_blocks = last_block - 1;
473 currently_testing = from_count;
474 if (s_flag && v_flag <= 1)
477 try = blocks_at_once;
478 while (currently_testing < last_block) {
479 if (currently_testing + try > last_block)
480 try = last_block - currently_testing;
481 got = do_write(dev, buffer, try, block_size,
486 currently_testing += got;
488 try = blocks_at_once;
489 /* recover page-aligned offset for O_DIRECT */
490 if ( (blocks_at_once >= sys_page_size >> 9)
491 && (currently_testing %
492 (sys_page_size >> 9)!= 0))
493 try -= (sys_page_size >> 9)
495 % (sys_page_size >> 9));
500 bb_count += bb_output(currently_testing++);
507 fputs(_(done_string), stderr);
510 fputs(_("Reading and comparing: "), stderr);
511 num_blocks = last_block;
512 currently_testing = from_count;
513 if (s_flag && v_flag <= 1)
516 try = blocks_at_once;
517 while (currently_testing < last_block) {
518 if (currently_testing + try > last_block)
519 try = last_block - currently_testing;
520 got = do_read (dev, read_buffer, try, block_size,
523 bb_count += bb_output(currently_testing++);
526 for (i=0; i < got; i++) {
527 if (memcmp(read_buffer + i * block_size,
528 buffer + i * block_size,
530 bb_count += bb_output(currently_testing+i);
532 currently_testing += got;
533 /* recover page-aligned offset for O_DIRECT */
534 if ( (blocks_at_once >= sys_page_size >> 9)
535 && (currently_testing % (sys_page_size >> 9)!= 0))
536 try = blocks_at_once - (sys_page_size >> 9)
538 % (sys_page_size >> 9));
540 try = blocks_at_once;
548 fputs(_(done_string), stderr);
551 uncapture_terminate();
556 struct saved_blk_record {
561 static unsigned int test_nd (int dev, blk_t last_block,
562 int block_size, blk_t from_count,
563 unsigned int blocks_at_once)
565 unsigned char *blkbuf, *save_ptr, *test_ptr, *read_ptr;
566 unsigned char *test_base, *save_base, *read_base;
568 const unsigned int patterns[] = { ~0 };
569 const unsigned int *pattern;
570 int nr_pattern, pat_idx;
571 int got, used2, written;
572 blk_t save_currently_testing;
573 struct saved_blk_record *test_record;
574 /* This is static to prevent being clobbered by the longjmp */
575 static int num_saved;
576 jmp_buf terminate_env;
578 unsigned long buf_used;
579 static unsigned int bb_count;
582 errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
584 com_err (program_name, errcode,
585 _("while beginning bad block list iteration"));
589 ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
590 } while (next_bad && next_bad < from_count);
592 blkbuf = allocate_buffer(3 * blocks_at_once * block_size);
593 test_record = malloc (blocks_at_once*sizeof(struct saved_blk_record));
594 if (!blkbuf || !test_record) {
595 com_err(program_name, ENOMEM, _("while allocating buffers"));
600 test_base = blkbuf + (blocks_at_once * block_size);
601 read_base = blkbuf + (2 * blocks_at_once * block_size);
607 fputs(_("Checking for bad blocks in non-destructive read-write mode\n"), stderr);
608 fprintf (stderr, _("From block %lu to %lu\n"),
609 (unsigned long) from_count, (unsigned long) last_block);
611 if (s_flag || v_flag > 1) {
612 fputs(_("Checking for bad blocks (non-destructive read-write test)\n"), stderr);
614 if (setjmp(terminate_env)) {
616 * Abnormal termination by a signal is handled here.
618 signal (SIGALRM, SIG_IGN);
619 fputs(_("\nInterrupt caught, cleaning up\n"), stderr);
621 save_ptr = save_base;
622 for (i=0; i < num_saved; i++) {
623 do_write(dev, save_ptr, test_record[i].num,
624 block_size, test_record[i].block);
625 save_ptr += test_record[i].num * block_size;
631 /* set up abend handler */
632 capture_terminate(terminate_env);
639 nr_pattern = sizeof(patterns) / sizeof(patterns[0]);
641 for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) {
642 pattern_fill(test_base, pattern[pat_idx],
643 blocks_at_once * block_size);
647 save_ptr = save_base;
648 test_ptr = test_base;
649 currently_testing = from_count;
650 num_blocks = last_block - 1;
651 if (s_flag && v_flag <= 1)
654 while (currently_testing < last_block) {
655 got = try = blocks_at_once - buf_used;
657 if (currently_testing == next_bad) {
658 /* fprintf (out, "%lu\n", nextbad); */
659 ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
663 else if (currently_testing + try > next_bad)
664 try = next_bad - currently_testing;
666 if (currently_testing + try > last_block)
667 try = last_block - currently_testing;
668 got = do_read (dev, save_ptr, try, block_size,
671 /* First block must have been bad. */
672 bb_count += bb_output(currently_testing++);
677 * Note the fact that we've saved this much data
678 * *before* we overwrite it with test data
680 test_record[num_saved].block = currently_testing;
681 test_record[num_saved].num = got;
684 /* Write the test data */
685 written = do_write (dev, test_ptr, got, block_size,
688 com_err (program_name, errno,
689 _("during test data write, block %lu"),
690 (unsigned long) currently_testing +
694 save_ptr += got * block_size;
695 test_ptr += got * block_size;
696 currently_testing += got;
698 bb_count += bb_output(currently_testing++);
702 * If there's room for more blocks to be tested this
703 * around, and we're not done yet testing the disk, go
704 * back and get some more blocks.
706 if ((buf_used != blocks_at_once) &&
707 (currently_testing < last_block))
711 save_currently_testing = currently_testing;
714 * for each contiguous block that we read into the
715 * buffer (and wrote test data into afterwards), read
716 * it back (looping if necessary, to get past newly
717 * discovered unreadable blocks, of which there should
718 * be none, but with a hard drive which is unreliable,
719 * it has happened), and compare with the test data
720 * that was written; output to the bad block list if
724 save_ptr = save_base;
725 test_ptr = test_base;
726 read_ptr = read_base;
731 if (used2 >= num_saved)
733 currently_testing = test_record[used2].block;
734 try = test_record[used2].num;
738 got = do_read (dev, read_ptr, try,
739 block_size, currently_testing);
741 /* test the comparison between all the
742 blocks successfully read */
743 for (i = 0; i < got; ++i)
744 if (memcmp (test_ptr+i*block_size,
745 read_ptr+i*block_size, block_size))
746 bb_count += bb_output(currently_testing + i);
748 bb_count += bb_output(currently_testing + got);
752 /* write back original data */
753 do_write (dev, save_ptr, got,
754 block_size, currently_testing);
755 save_ptr += got * block_size;
757 currently_testing += got;
758 test_ptr += got * block_size;
759 read_ptr += got * block_size;
763 /* empty the buffer so it can be reused */
766 save_ptr = save_base;
767 test_ptr = test_base;
768 currently_testing = save_currently_testing;
772 if (s_flag || v_flag > 1)
773 fputs(_(done_string), stderr);
777 uncapture_terminate();
782 ext2fs_badblocks_list_iterate_end(bb_iter);
787 static void check_mount(char *device_name)
792 retval = ext2fs_check_if_mounted(device_name, &mount_flags);
794 com_err("ext2fs_check_if_mount", retval,
795 _("while determining whether %s is mounted."),
799 if (mount_flags & EXT2_MF_MOUNTED) {
800 fprintf(stderr, _("%s is mounted; "), device_name);
802 fputs(_("badblocks forced anyway. "
803 "Hope /etc/mtab is incorrect.\n"), stderr);
807 fputs(_("it's not safe to run badblocks!\n"), stderr);
811 if ((mount_flags & EXT2_MF_BUSY) && !exclusive_ok) {
812 fprintf(stderr, _("%s is apparently in use by the system; "),
815 fputs(_("badblocks forced anyway.\n"), stderr);
817 goto abort_badblocks;
823 int main (int argc, char ** argv)
828 char * host_device_name = NULL;
829 char * input_file = NULL;
830 char * output_file = NULL;
832 int block_size = 1024;
833 unsigned int blocks_at_once = 64;
834 blk_t last_block, from_count;
836 int passes_clean = 0;
839 unsigned int pattern;
840 unsigned int (*test_func)(int, blk_t,
846 setbuf(stdout, NULL);
847 setbuf(stderr, NULL);
849 setlocale(LC_MESSAGES, "");
850 setlocale(LC_CTYPE, "");
851 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
852 textdomain(NLS_CAT_NAME);
854 srandom((unsigned int)time(NULL)); /* simple randomness is enough */
857 /* Determine the system page size if possible */
859 #if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
860 #define _SC_PAGESIZE _SC_PAGE_SIZE
863 sysval = sysconf(_SC_PAGESIZE);
865 sys_page_size = sysval;
866 #endif /* _SC_PAGESIZE */
867 #endif /* HAVE_SYSCONF */
870 program_name = *argv;
871 while ((c = getopt (argc, argv, "b:fi:o:svwnc:p:h:t:X")) != EOF) {
874 block_size = strtoul (optarg, &tmp, 0);
875 if (*tmp || block_size > 4096) {
876 com_err (program_name, 0,
877 _("bad block size - %s"), optarg);
888 output_file = optarg;
909 blocks_at_once = strtoul (optarg, &tmp, 0);
911 com_err (program_name, 0,
912 "bad simultaneous block count - %s", optarg);
917 num_passes = strtoul (optarg, &tmp, 0);
919 com_err (program_name, 0,
920 "bad number of clean passes - %s", optarg);
925 host_device_name = optarg;
928 if (t_flag + 1 > t_max) {
929 unsigned int *t_patts_new;
931 t_patts_new = realloc(t_patts, t_max + T_INC);
933 com_err(program_name, ENOMEM,
934 _("can't allocate memory for "
935 "test_pattern - %s"),
939 t_patts = t_patts_new;
942 if (!strcmp(optarg, "r") || !strcmp(optarg,"random")) {
943 t_patts[t_flag++] = ~0;
945 pattern = strtoul(optarg, &tmp, 0);
947 com_err(program_name, 0,
948 _("invalid test_pattern: %s\n"),
952 if (pattern == (unsigned int) ~0)
954 t_patts[t_flag++] = pattern;
966 com_err(program_name, 0,
967 _("Maximum of one test_pattern may be specified "
968 "in read-only mode"));
971 if (t_patts && (t_patts[0] == (unsigned int) ~0)) {
972 com_err(program_name, 0,
973 _("Random test_pattern is not allowed "
974 "in read-only mode"));
978 if (optind > argc - 1)
980 device_name = argv[optind++];
981 if (optind > argc - 1) {
982 errcode = ext2fs_get_device_size(device_name,
985 if (errcode == EXT2_ET_UNIMPLEMENTED) {
986 com_err(program_name, 0,
987 _("Couldn't determine device size; you "
988 "must specify\nthe size manually\n"));
992 com_err(program_name, errcode,
993 _("while trying to determine device size"));
998 last_block = strtoul (argv[optind], &tmp, 0);
999 printf("last_block = %d (%s)\n", last_block, argv[optind]);
1000 if (*tmp || errno ||
1001 (last_block == ULONG_MAX && errno == ERANGE)) {
1002 com_err (program_name, 0, _("invalid blocks count - %s"),
1009 if (optind <= argc-1) {
1011 from_count = strtoul (argv[optind], &tmp, 0);
1012 printf("from_count = %d\n", from_count);
1013 if (*tmp || errno ||
1014 (from_count == ULONG_MAX && errno == ERANGE)) {
1015 com_err (program_name, 0, _("invalid starting block - %s"),
1019 } else from_count = 0;
1020 if (from_count >= last_block) {
1021 com_err (program_name, 0, _("invalid starting block (%lu): must be less than %lu"),
1022 (unsigned long) from_count, (unsigned long) last_block);
1026 check_mount(device_name);
1028 open_flag = w_flag ? O_RDWR : O_RDONLY;
1029 dev = open (device_name, open_flag);
1031 com_err (program_name, errno, _("while trying to open %s"),
1035 if (host_device_name) {
1036 host_dev = open (host_device_name, open_flag);
1037 if (host_dev == -1) {
1038 com_err (program_name, errno,
1039 _("while trying to open %s"),
1046 if (strcmp (input_file, "-") == 0)
1049 in = fopen (input_file, "r");
1052 com_err (program_name, errno,
1053 _("while trying to open %s"),
1059 if (output_file && strcmp (output_file, "-") != 0)
1061 out = fopen (output_file, "w");
1064 com_err (program_name, errno,
1065 _("while trying to open %s"),
1073 errcode = ext2fs_badblocks_list_create(&bb_list,0);
1075 com_err (program_name, errcode,
1076 _("while creating in-memory bad blocks list"));
1082 switch(fscanf (in, "%u\n", &next_bad)) {
1084 com_err (program_name, 0, "input file - bad format");
1089 errcode = ext2fs_badblocks_list_add(bb_list,next_bad);
1091 com_err (program_name, errcode, _("while adding to in-memory bad block list"));
1104 unsigned int bb_count;
1106 bb_count = test_func(dev, last_block, block_size,
1107 from_count, blocks_at_once);
1115 _("Pass completed, %u bad blocks found.\n"),
1118 } while (passes_clean < num_passes);