badblocks.c revision d49a22b734299e4b433a19b8f5f60d689c92a78e
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * badblocks.c		- Bad blocks checker
33839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
43839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Copyright (C) 1992, 1993, 1994  Remy Card <card@masi.ibp.fr>
53839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *                                 Laboratoire MASI, Institut Blaise Pascal
63839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *                                 Universite Pierre et Marie Curie (Paris VI)
73839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
8dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * Copyright 1995, 1996, 1997, 1998, 1999 by Theodore Ts'o
9879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Copyright 1999 by David Beattie
1019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This file is based on the minix file system programs fsck and mkfs
123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * written and copyrighted by Linus Torvalds <Linus.Torvalds@cs.helsinki.fi>
1319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
1419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header%
1519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
1619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * License.
1719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header%
183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * History:
223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 93/05/26	- Creation from e2fsck
233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 94/02/27	- Made a separate bad blocks checker
24879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * 99/06/30...99/07/26 - Added non-destructive write-testing,
25dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o *                       configurable blocks-at-once parameter,
26dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * 			 loading of badblocks list to avoid testing
27dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * 			 blocks known to be bad, multiple passes to
28dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * 			 make sure that no new blocks are added to the
29dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * 			 list.  (Work done by David Beattie)
303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <errno.h>
333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
34a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#ifdef HAVE_GETOPT_H
353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <getopt.h>
36373b8337c7b6c6243810be250083fa4773891e92Theodore Ts'o#else
37373b8337c7b6c6243810be250083fa4773891e92Theodore Ts'oextern char *optarg;
38373b8337c7b6c6243810be250083fa4773891e92Theodore Ts'oextern int optind;
39a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <signal.h>
413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdlib.h>
433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
45879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#include <setjmp.h>
463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/ioctl.h>
48f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <sys/types.h>
493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
50a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#if HAVE_LINUX_FS_H
513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <linux/fd.h>
52a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "et/com_err.h"
55d40259fd552d942903f2fd0b426c75a5c2516017Theodore Ts'o#include "ext2fs/ext2_io.h"
56879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#include <linux/ext2_fs.h>
57879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#include "ext2fs/ext2fs.h"
58d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#include "nls-enable.h"
593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oconst char * program_name = "badblocks";
618f5c0f66ca343ec4689470e5941aa3066ed062bbTheodore Ts'oconst char * done_string = N_("done                        \n");
623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
634d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'ostatic int v_flag = 0;			/* verbose */
644d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'ostatic int w_flag = 0;			/* do r/w test: 0=no, 1=yes,
654d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o					 * 2=non-destructive */
664d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'ostatic int s_flag = 0;			/* show progress of test */
674d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
684d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'ostatic char *blkbuf;		/* Allocation array for bad block testing */
694d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
71818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'ostatic void usage(void)
723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
73d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	fprintf(stderr, _("Usage: %s [-b block_size] [-i input_file] [-o output_file] [-svwn]\n [-c blocks_at_once] [-p num_passes] device blocks_count [start_count]\n"),
743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 program_name);
753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	exit (1);
763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic unsigned long currently_testing = 0;
7919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic unsigned long num_blocks = 0;
80879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic ext2_badblocks_list bb_list = NULL;
81879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic FILE *out;
82879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic blk_t next_bad = 0;
83879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic ext2_badblocks_iterate bb_iter = NULL;
8419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
85dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o/*
86dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * This routine reports a new bad block.  If the bad block has already
87dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * been seen before, then it returns 0; otherwise it returns 1.
88dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o */
89dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'ostatic int bb_output (unsigned long bad)
90879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
91879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
92879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
93dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	if (ext2fs_badblocks_list_test(bb_list, bad))
94dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		return 0;
95dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o
96879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	fprintf (out, "%lu\n", bad);
97879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
98879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_add (bb_list, bad);
99879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
100879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		com_err (program_name, errcode, "adding to in-memory bad block list");
101879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
102879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
103879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
104879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* kludge:
105879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   increment the iteration through the bb_list if
106879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   an element was just added before the current iteration
107879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   position.  This should not cause next_bad to change. */
108879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (bb_iter && bad < next_bad)
109879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
110dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	return 1;
111879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
112879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
113879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic void print_status (void)
11419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
11519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
11619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
11719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fflush (stderr);
11819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
11919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
12019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic void alarm_intr (int alnum)
12119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
12219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	signal (SIGALRM, alarm_intr);
12319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	alarm(1);
12419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (!num_blocks)
12519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		return;
12619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
12719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
12819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fflush (stderr);
12919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
13019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
131879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic void *terminate_addr = NULL;
132879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
133879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic void terminate_intr (int signo)
134879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
135879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (terminate_addr)
136879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		longjmp(terminate_addr,1);
137879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	exit(1);
138879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
139879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
140879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic void capture_terminate (jmp_buf term_addr)
141879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
142879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	terminate_addr = term_addr;
143879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGHUP, terminate_intr);
144879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGINT, terminate_intr);
145879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGPIPE, terminate_intr);
146879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGTERM, terminate_intr);
147879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGUSR1, terminate_intr);
148879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGUSR2, terminate_intr);
149879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
150879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1514d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'ostatic void uncapture_terminate()
1524d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o{
1534d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	terminate_addr = NULL;
1544d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGHUP, SIG_DFL);
1554d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGINT, SIG_DFL);
1564d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGPIPE, SIG_DFL);
1574d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGTERM, SIG_DFL);
1584d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGUSR1, SIG_DFL);
1594d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGUSR2, SIG_DFL);
1604d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o}
1614d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
1623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
163879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Perform a read of a sequence of blocks; return the number of blocks
164879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o *    successfully sequentially read.
1653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
166dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'ostatic long do_read (int dev, char * buffer, int try, int block_size,
1673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		     unsigned long current_block)
1683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	long got;
1703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
17119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag > 1)
17219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		print_status();
17319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
1743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Seek to the correct loc. */
17519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
176f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			 SEEK_SET) != (ext2_loff_t) current_block * block_size)
177d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("during seek"));
1783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Try the read */
1803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got = read (dev, buffer, try * block_size);
1813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (got < 0)
1823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		got = 0;
1839f10a7b31e57288093930fc9565102409eeac6e9Theodore Ts'o	if (got & 511)
184d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("Weird value (%ld) in do_read\n"), got);
185879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	got /= block_size;
186879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return got;
187879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
188879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
189879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o/*
190879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Perform a write of a sequence of blocks; return the number of blocks
191879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o *    successfully sequentially written.
192879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o */
193dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'ostatic long do_write (int dev, char * buffer, int try, int block_size,
194879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		     unsigned long current_block)
195879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
196879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	long got;
197879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
198879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag > 1)
199879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		print_status();
200879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
201879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* Seek to the correct loc. */
202879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
203879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			 SEEK_SET) != (ext2_loff_t) current_block * block_size)
204d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("during seek"));
205879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
206879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* Try the write */
207879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	got = write (dev, buffer, try * block_size);
208879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (got < 0)
209879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		got = 0;
210879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (got & 511)
211879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		fprintf (stderr,
212879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			 "Weird value (%ld) in do_write\n", got);
2133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got /= block_size;
2143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return got;
2153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
2163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
217879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic int host_dev;
218879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
219d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'ostatic void flush_bufs (int dev)
220a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o{
221e2207ce595f05e4db5945326f9b2d553ff7a4d57Theodore Ts'o#ifdef HAVE_FDATASYNC
222879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o  if (sync && fdatasync (dev) == -1)
223e2207ce595f05e4db5945326f9b2d553ff7a4d57Theodore Ts'o    com_err (program_name, errno, _("during fdatasync"));
224e2207ce595f05e4db5945326f9b2d553ff7a4d57Theodore Ts'o#else
225e2207ce595f05e4db5945326f9b2d553ff7a4d57Theodore Ts'o  if (sync && fsync (dev) == -1)
226d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o    com_err (program_name, errno, _("during fsync"));
227e2207ce595f05e4db5945326f9b2d553ff7a4d57Theodore Ts'o#endif
228a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
229879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#ifdef BLKFLSBUF
230879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o  ioctl (host_dev, BLKFLSBUF, 0);   /* In case this is a HD */
231a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
232a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#ifdef FDFLUSH
233879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o  ioctl (host_dev, FDFLUSH, 0);   /* In case this is floppy */
234a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
235a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o}
236a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
237879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic unsigned int test_ro (int dev, unsigned long blocks_count,
238dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     int block_size, unsigned long from_count,
239dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     unsigned long blocks_at_once)
2403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
2413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * blkbuf;
2423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int try;
2433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	long got;
244879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned int bb_count = 0;
245879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
2463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
247879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
248879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
249d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errcode,
250d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			 _("while beginning bad block list iteration"));
251879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
252879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
253879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
254879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
255879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (next_bad && next_bad < from_count);
256879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
257879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	blkbuf = malloc (blocks_at_once * block_size);
2583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!blkbuf)
2593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
260d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, ENOMEM, _("while allocating buffers"));
2613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
2623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
263d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	flush_bufs(dev);
264f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (v_flag) {
265d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	    fprintf(stderr, _("Checking for bad blocks in read-only mode\n"));
266d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	    fprintf (stderr, _("From block %lu to %lu\n"), from_count,
267d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		     blocks_count);
268f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
269879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	try = blocks_at_once;
270f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	currently_testing = from_count;
2713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	num_blocks = blocks_count;
27219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (s_flag || v_flag > 1) {
273d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr,
274d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			_("Checking for bad blocks (read-only test): "));
27519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (v_flag <= 1)
27619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			alarm_intr(SIGALRM);
2773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	while (currently_testing < blocks_count)
2793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
280879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (next_bad) {
281879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (currently_testing == next_bad) {
282879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				/* fprintf (out, "%lu\n", nextbad); */
283879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
284879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				currently_testing++;
285879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				continue;
286879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
287879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			else if (currently_testing + try > next_bad)
288879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				try = next_bad - currently_testing;
289879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
2903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (currently_testing + try > blocks_count)
2913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			try = blocks_count - currently_testing;
292879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		got = do_read (dev, blkbuf, try, block_size, currently_testing);
2933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		currently_testing += got;
2943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (got == try) {
295879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			try = blocks_at_once;
2963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			continue;
2973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
2983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		else
2993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			try = 1;
300879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (got == 0) {
301dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			bb_count += bb_output(currently_testing++);
302879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
3033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	num_blocks = 0;
3053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	alarm(0);
30619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (s_flag || v_flag > 1)
3078f5c0f66ca343ec4689470e5941aa3066ed062bbTheodore Ts'o		fprintf(stderr, _(done_string));
308879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
309f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	fflush (stderr);
3103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	free (blkbuf);
311879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
312879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	ext2fs_badblocks_list_iterate_end(bb_iter);
313879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
314879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
3153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
3163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
317879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic unsigned int test_rw (int dev, unsigned long blocks_count,
318dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     int block_size, unsigned long from_count,
319dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     unsigned long blocks_at_once)
3203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int i;
3223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * buffer;
3233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unsigned char pattern[] = {0xaa, 0x55, 0xff, 0x00};
324879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned int bb_count = 0;
3253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	buffer = malloc (2 * block_size);
3273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!buffer)
3283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
329d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, ENOMEM, _("while allocating buffers"));
3303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
3313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
333d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	flush_bufs(dev);
334a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
33519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag) {
33619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		fprintf(stderr,
337d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			_("Checking for bad blocks in read-write mode\n"));
338d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("From block %lu to %lu\n"),
33919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			 from_count, blocks_count);
34019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	}
34119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	for (i = 0; i < sizeof (pattern); i++) {
3423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		memset (buffer, pattern[i], block_size);
343f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
344d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			fprintf (stderr, _("Writing pattern 0x%08x: "),
3453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				 *((int *) buffer));
346f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = blocks_count;
347f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		currently_testing = from_count;
34819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
349f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
350f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		for (;
351f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing < blocks_count;
352f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing++)
3533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
35419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
355f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 block_size, SEEK_SET) !=
356f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			    (ext2_loff_t) currently_testing * block_size)
3573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, errno,
358d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("during seek on block %d"),
359f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 currently_testing);
36019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
36119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
3623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			write (dev, buffer, block_size);
3633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
364f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
365f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
366f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
3678f5c0f66ca343ec4689470e5941aa3066ed062bbTheodore Ts'o			fprintf(stderr, _(done_string));
368d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		flush_bufs(dev);
369f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
370d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			fprintf (stderr, _("Reading and comparing: "));
371f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = blocks_count;
372f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		currently_testing = from_count;
37319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
374f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
375f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		for (;
376f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing < blocks_count;
377f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing++)
3783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
37919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
380f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 block_size, SEEK_SET) !=
381f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			    (ext2_loff_t) currently_testing * block_size)
3823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, errno,
383d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("during seek on block %d"),
384f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 currently_testing);
38519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
38619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
387dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			if ((read (dev, buffer + block_size, block_size)
3884d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			     != block_size) ||
389dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			    memcmp(buffer, buffer + block_size, block_size))
3904d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				bb_count += bb_output(currently_testing);
3913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
392f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
393f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
394f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
3958f5c0f66ca343ec4689470e5941aa3066ed062bbTheodore Ts'o			fprintf(stderr, _(done_string));
396d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		flush_bufs(dev);
3973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
398879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
399879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
400879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
401879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
402d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'ostruct saved_blk_record {
403d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	blk_t	block;
404d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	int	num;
405d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o};
406d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o
407879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic unsigned int test_nd (int dev, unsigned long blocks_count,
408dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     int block_size, unsigned long from_count,
409dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     unsigned long blocks_at_once)
410879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
411dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	char *blkbuf, *save_ptr, *test_ptr, *read_ptr;
412879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * ptr;
413dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	int try, i;
414d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	long got, used2, written;
415d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	struct saved_blk_record *test_record;
416d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	int	num_saved;
417879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	jmp_buf terminate_env;
418879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
419dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	/* These are static to prevent being clobbered by the longjmp */
4204d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	static long buf_used = 0;
4214d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	static unsigned int bb_count = 0;
422879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
423879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
424879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
425dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		com_err (program_name, errcode,
426d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			 _("while beginning bad block list iteration"));
427879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
428879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
429879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
430879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
431879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (next_bad && next_bad < from_count);
432879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
433879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	blkbuf = malloc (3 * blocks_at_once * block_size);
434d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	test_record = malloc (blocks_at_once*sizeof(struct saved_blk_record));
435d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	if (!blkbuf || !test_record) {
436d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err(program_name, ENOMEM, _("while allocating buffers"));
437879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
438879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
439d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	num_saved = 0;
440879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
441879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* inititalize the test data randomly: */
442879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag) {
443d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf (stderr, _("Initializing random test data\n"));
444879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
445879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	for(ptr = blkbuf + blocks_at_once * block_size;
446dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	    ptr < blkbuf + 2 * blocks_at_once * block_size;
447dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	    ++ptr) {
448879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		(*ptr) = random() % (1 << sizeof(char));
449879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
450879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
451d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	flush_bufs(dev);
452879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag) {
453879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	    fprintf (stderr,
454d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		     _("Checking for bad blocks in non-destructive read-write mode\n"));
455d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	    fprintf (stderr, _("From block %lu to %lu\n"), from_count, blocks_count);
456879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
457879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (s_flag || v_flag > 1) {
458d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("Checking for bad blocks (non-destructive read-write test): "));
459879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (v_flag <= 1)
460879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			alarm_intr(SIGALRM);
461879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
4624d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	if (setjmp(terminate_env)) {
4634d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		/*
4644d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * Abnormal termination by a signal is handled here.
4654d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 */
466879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
467d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("Interrupt caught, cleaning up\n"));
468879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
469d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		save_ptr = blkbuf;
470d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		for (i=0; i < num_saved; i++) {
471d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			do_write(dev, save_ptr, test_record[i].num,
472d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				 block_size, test_record[i].block);
473d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			save_ptr += test_record[i].num * block_size;
474d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		}
475879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		fflush (out);
476dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		exit(1);
477879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
4784d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
4794d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	/* set up abend handler */
4804d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	capture_terminate(terminate_env);
4814d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
482d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	buf_used = 0;
483d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	save_ptr = blkbuf;
4844d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	test_ptr = blkbuf + (blocks_at_once * block_size);
4854d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	currently_testing = from_count;
4864d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	num_blocks = blocks_count;
4874d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
4884d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	while (currently_testing < blocks_count) {
4894d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		try = blocks_at_once - buf_used;
4904d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if (next_bad) {
4914d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (currently_testing == next_bad) {
4924d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				/* fprintf (out, "%lu\n", nextbad); */
4934d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
494d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				currently_testing++;
495d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				goto check_for_more;
4964d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			}
4974d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			else if (currently_testing + try > next_bad)
4984d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				try = next_bad - currently_testing;
4994d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		}
5004d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if (currently_testing + try > blocks_count)
5014d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			try = blocks_count - currently_testing;
5024d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		got = do_read (dev, save_ptr, try, block_size,
5034d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			       currently_testing);
504d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		if (got == 0) {
505d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			/* First block must have been bad. */
506d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			bb_count += bb_output(currently_testing++);
507d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			goto check_for_more;
508d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		}
5094d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
510d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		/*
511d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		 * Note the fact that we've saved this much data
512d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		 * *before* we overwrite it with test data
513d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		 */
514d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		test_record[num_saved].block = currently_testing;
515d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		test_record[num_saved].num = got;
516d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		num_saved++;
517d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o
518d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		/* Write the test data */
519d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		written = do_write (dev, test_ptr, got, block_size,
520d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				    currently_testing);
521d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		if (written != got)
522d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			com_err (program_name, errno,
5234d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				 _("during test data write, block %lu"),
524d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				 currently_testing + written);
5254d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
5264d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		buf_used += got;
5274d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		save_ptr += got * block_size;
5284d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		test_ptr += got * block_size;
5294d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		currently_testing += got;
5304d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if (got != try)
5314d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			bb_count += bb_output(currently_testing++);
5324d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
533d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	check_for_more:
5344d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		/*
5354d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * If there's room for more blocks to be tested this
5364d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * around, and we're not done yet testing the disk, go
5374d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * back and get some more blocks.
5384d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 */
5394d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if ((buf_used != blocks_at_once) &&
540d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		    (currently_testing < blocks_count))
5414d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			continue;
5424d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
543d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		flush_bufs(dev);
5444d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
5454d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		/*
5464d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * for each contiguous block that we read into the
5474d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * buffer (and wrote test data into afterwards), read
5484d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * it back (looping if necessary, to get past newly
5494d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * discovered unreadable blocks, of which there should
5504d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * be none, but with a hard drive which is unreliable,
5514d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * it has happened), and compare with the test data
5524d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * that was written; output to the bad block list if
5534d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * it doesn't match.
5544d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 */
5554d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		used2 = 0;
5564d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		save_ptr = blkbuf;
5574d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		test_ptr = blkbuf + (blocks_at_once * block_size);
5584d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		read_ptr = blkbuf + (2 * blocks_at_once * block_size);
559d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		try = 0;
5604d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
561d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		while (1) {
562d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			if (try == 0) {
563d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				if (used2 >= num_saved)
564d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o					break;
565d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				currently_testing = test_record[used2].block;
566d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				try = test_record[used2].num;
567d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				used2++;
568d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			}
569d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o
5704d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			got = do_read (dev, read_ptr, try,
5714d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				       block_size, currently_testing);
5724d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
5734d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			/* test the comparison between all the
5744d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			   blocks successfully read  */
5754d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			for (i = 0; i < got; ++i)
5764d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				if (memcmp (test_ptr+i*block_size,
5774d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o					    read_ptr+i*block_size, block_size))
5784d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o					bb_count += bb_output(currently_testing + i);
5794d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (got < try) {
5804d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				bb_count += bb_output(currently_testing + got);
5814d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				got++;
5824d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			}
5834d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
5844d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			/* when done, write back original data */
5854d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			do_write (dev, save_ptr, got, block_size,
5864d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				  currently_testing);
5874d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
5884d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			currently_testing += got;
5894d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			save_ptr += got * block_size;
5904d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_ptr += got * block_size;
5914d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			read_ptr += got * block_size;
5924d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			try -= got;
5934d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		}
5944d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
5954d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		/* empty the buffer so it can be reused */
596d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		num_saved = 0;
5974d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		buf_used = 0;
598d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		save_ptr = blkbuf;
599d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		test_ptr = blkbuf + (blocks_at_once * block_size);
6004d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	}
6014d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	num_blocks = 0;
6024d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	alarm(0);
6034d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	uncapture_terminate();
6044d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	if (s_flag || v_flag > 1)
6054d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		fprintf(stderr, _(done_string));
606879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
607dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	fflush(stderr);
608dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	free(blkbuf);
609d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	free(test_record);
610879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
611879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	ext2fs_badblocks_list_iterate_end(bb_iter);
612879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
613879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
6143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
61600e5433eb5e9f70f485968b809fdcf297d7fe7b9Theodore Ts'oint main (int argc, char ** argv)
6173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
618519149fb458b0fa69c10fecd83fae42e838cf01dTheodore Ts'o	int c;
6193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * tmp;
6203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * device_name;
621879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * host_device_name = NULL;
622879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * input_file = NULL;
6233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * output_file = NULL;
624879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	FILE * in = NULL;
625dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	int block_size = 1024;
626879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned long blocks_at_once = 16;
627f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	unsigned long blocks_count, from_count;
628879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	int num_passes = 0;
629879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	int passes_clean = 0;
6303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int dev;
631879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
6324d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	unsigned int (*test_func)(int dev, unsigned long blocks_count,
6334d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				  int block_size, unsigned long from_count,
6344d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				  unsigned long blocks_at_once);
6354d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	size_t	buf_size;
6363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stdout, NULL);
6383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stderr, NULL);
639d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#ifdef ENABLE_NLS
640d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	setlocale(LC_MESSAGES, "");
641d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
642d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	textdomain(NLS_CAT_NAME);
643d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#endif
6444d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	test_func = test_ro;
6454d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
6463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (argc && *argv)
6473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		program_name = *argv;
648879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	while ((c = getopt (argc, argv, "b:i:o:svwnc:p:h:")) != EOF) {
6493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		switch (c) {
6503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'b':
6513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			block_size = strtoul (optarg, &tmp, 0);
6523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			if (*tmp || block_size > 4096) {
6533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, 0,
654d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("bad block size - %s"), optarg);
6553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				exit (1);
6563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
6573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
658879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'i':
659879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			input_file = optarg;
660879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
6613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'o':
6623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			output_file = optarg;
6633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
6643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 's':
6653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			s_flag = 1;
6663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
6673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'v':
66819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			v_flag++;
6693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
6703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'w':
6714d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (w_flag)
6724d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				usage();
6734d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_func = test_rw;
6744d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			w_flag = 1;
675879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
676879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'n':
6774d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (w_flag)
6784d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				usage();
6794d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_func = test_nd;
680879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			w_flag = 2;
681879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
682879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'c':
683879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			blocks_at_once = strtoul (optarg, &tmp, 0);
684879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (*tmp) {
685879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				com_err (program_name, 0,
686879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					 "bad simultaneous block count - %s", optarg);
687879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
688879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
689879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
690879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'p':
691879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			num_passes = strtoul (optarg, &tmp, 0);
692879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (*tmp) {
693879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				com_err (program_name, 0,
694879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				    "bad number of clean passes - %s", optarg);
695879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
696879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
697879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
698879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'h':
699879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			host_device_name = optarg;
7003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
7013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		default:
702818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o			usage();
7033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
7043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
7053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (optind > argc - 1)
706818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o		usage();
7073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	device_name = argv[optind++];
7083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (optind > argc - 1)
709818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o		usage();
7103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	blocks_count = strtoul (argv[optind], &tmp, 0);
7113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (*tmp)
7123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
713d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, 0, _("bad blocks count - %s"),
714d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			 argv[optind]);
7153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
7163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
717f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (++optind <= argc-1) {
718f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		from_count = strtoul (argv[optind], &tmp, 0);
719f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	} else from_count = 0;
720f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (from_count >= blocks_count) {
721d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	    com_err (program_name, 0, _("bad blocks range: %lu-%lu"),
722f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     from_count, blocks_count);
723f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	    exit (1);
724f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
7253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	dev = open (device_name, w_flag ? O_RDWR : O_RDONLY);
7263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (dev == -1)
7273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
728d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("while trying to open %s"),
7293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 device_name);
7303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
7313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
732879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (host_device_name) {
733879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		host_dev = open (host_device_name, O_RDONLY);
734879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (host_dev == -1)
735879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		{
736d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			com_err (program_name, errno,
737d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 _("while trying to open %s"),
738d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 host_device_name);
739879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			exit (1);
740879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
741879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} else
742879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		host_dev = dev;
743879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (input_file)
744879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (strcmp (input_file, "-") == 0)
745879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			in = stdin;
746879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		else {
747879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			in = fopen (input_file, "r");
748879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (in == NULL)
749879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			{
750d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				com_err (program_name, errno,
751d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("while trying to open %s"),
752879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					 input_file);
753879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
754879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
755879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
7563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (output_file && strcmp (output_file, "-") != 0)
7573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
7583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = fopen (output_file, "w");
7593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (out == NULL)
7603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
761d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			com_err (program_name, errno,
762d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 _("while trying to open %s"),
763879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				 output_file);
7643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			exit (1);
7653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
7663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
7673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
7683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = stdout;
769879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
770879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_create(&bb_list,0);
771879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
772d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errcode,
773d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			 _("creating in-memory bad blocks list"));
774879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
775879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
776879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
777879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (in) {
778879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		for(;;) {
779879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			switch(fscanf (in, "%lu\n", &next_bad)) {
780879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				case 0:
781879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					com_err (program_name, 0, "input file - bad format");
782879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					exit (1);
783879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				case EOF:
784879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					break;
785879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				default:
786879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					errcode = ext2fs_badblocks_list_add(bb_list,next_bad);
787879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					if (errcode) {
788d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o						com_err (program_name, errcode, _("adding to in-memory bad block list"));
789879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						exit (1);
790879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					}
791879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					continue;
792879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
793879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
794879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
795879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
796879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (in != stdin)
797879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			fclose (in);
798879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
799879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
800879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
801879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		unsigned int bb_count;
802879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
8034d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		bb_count = test_func(dev, blocks_count, block_size,
8044d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				     from_count, blocks_at_once);
8054d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if (bb_count)
8064d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			passes_clean = 0;
8074d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		else
8084d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			++passes_clean;
8094d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
810879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (v_flag)
811d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			fprintf(stderr,
812d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				_("Pass completed, %u bad blocks found.\n"),
813d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				bb_count);
814879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
815879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (passes_clean < num_passes);
816879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
8173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	close (dev);
8183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (out != stdout)
8193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fclose (out);
820879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return 0;
8213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
822d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o
823