badblocks.c
上传用户:ygj115
上传日期:2007-08-07
资源大小:3078k
文件大小:27k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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