badblocks.c revision 879ac920e347267d4461ba76b349fbef67b42b9b
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 *
819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * Copyright 1995, 1996, 1997 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,
25879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o *                       and a whole host of other features.
263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <errno.h>
293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
30a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#ifdef HAVE_GETOPT_H
313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <getopt.h>
32a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <signal.h>
343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdlib.h>
363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
38879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#include <setjmp.h>
393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/ioctl.h>
41f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#include <sys/types.h>
423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
43a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#if HAVE_LINUX_FS_H
443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <linux/fd.h>
453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <linux/fs.h>
46a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "et/com_err.h"
49d40259fd552d942903f2fd0b426c75a5c2516017Theodore Ts'o#include "ext2fs/ext2_io.h"
50879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#include <linux/ext2_fs.h>
51879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#include "ext2fs/ext2fs.h"
523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oconst char * program_name = "badblocks";
5400eedba1bd3a37812ee9403abca7ea4376ac9a08Theodore Ts'oconst char * done_string = "done                        \n";
553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oint v_flag = 0;			/* verbose */
57879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'oint w_flag = 0;			/* do r/w test: 0=no, 1=yes, 2=non-destructive */
583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oint s_flag = 0;			/* show progress of test */
593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
60818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'ostatic void usage(void)
613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
62879ac920e347267d4461ba76b349fbef67b42b9bTheodore 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",
633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 program_name);
643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	exit (1);
653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic unsigned long currently_testing = 0;
6819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic unsigned long num_blocks = 0;
69879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic ext2_badblocks_list bb_list = NULL;
70879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic FILE *out;
71879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic blk_t next_bad = 0;
72879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic ext2_badblocks_iterate bb_iter = NULL;
7319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
74879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic void bb_output (unsigned long bad)
75879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
76879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
77879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
78879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	fprintf (out, "%lu\n", bad);
79879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
80879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_add (bb_list, bad);
81879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
82879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		com_err (program_name, errcode, "adding to in-memory bad block list");
83879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
84879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
85879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
86879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* kludge:
87879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   increment the iteration through the bb_list if
88879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   an element was just added before the current iteration
89879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   position.  This should not cause next_bad to change. */
90879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (bb_iter && bad < next_bad)
91879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
92879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
93879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
94879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic void print_status (void)
9519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
9619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
9719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
9819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fflush (stderr);
9919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
10019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
10119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic void alarm_intr (int alnum)
10219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
10319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	signal (SIGALRM, alarm_intr);
10419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	alarm(1);
10519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (!num_blocks)
10619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		return;
10719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
10819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
10919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fflush (stderr);
11019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
11119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
112879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic void *terminate_addr = NULL;
113879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
114879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic void terminate_intr (int signo)
115879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
116879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (terminate_addr)
117879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		longjmp(terminate_addr,1);
118879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	exit(1);
119879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
120879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
121879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic void capture_terminate (jmp_buf term_addr)
122879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
123879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	terminate_addr = term_addr;
124879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGHUP, terminate_intr);
125879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGINT, terminate_intr);
126879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGPIPE, terminate_intr);
127879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGTERM, terminate_intr);
128879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGUSR1, terminate_intr);
129879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGUSR2, terminate_intr);
130879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
131879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
133879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Perform a read of a sequence of blocks; return the number of blocks
134879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o *    successfully sequentially read.
1353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
136879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic long do_read (int dev, char * buffer, int try, unsigned long block_size,
1373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		     unsigned long current_block)
1383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	long got;
1403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
14119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag > 1)
14219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		print_status();
14319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
1443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Seek to the correct loc. */
14519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
146f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			 SEEK_SET) != (ext2_loff_t) current_block * block_size)
147f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		com_err (program_name, errno, "during seek");
1483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Try the read */
1503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got = read (dev, buffer, try * block_size);
1513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (got < 0)
1523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		got = 0;
1539f10a7b31e57288093930fc9565102409eeac6e9Theodore Ts'o	if (got & 511)
154f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		fprintf (stderr,
155879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			 "Weird value (%ld) in do_read\n", got);
156879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	got /= block_size;
157879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return got;
158879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
159879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
160879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o/*
161879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Perform a write of a sequence of blocks; return the number of blocks
162879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o *    successfully sequentially written.
163879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o */
164879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic long do_write (int dev, char * buffer, int try, unsigned long block_size,
165879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		     unsigned long current_block)
166879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
167879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	long got;
168879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
169879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag > 1)
170879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		print_status();
171879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
172879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* Seek to the correct loc. */
173879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
174879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			 SEEK_SET) != (ext2_loff_t) current_block * block_size)
175879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		com_err (program_name, errno, "during seek");
176879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
177879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* Try the write */
178879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	got = write (dev, buffer, try * block_size);
179879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (got < 0)
180879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		got = 0;
181879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (got & 511)
182879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		fprintf (stderr,
183879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			 "Weird value (%ld) in do_write\n", got);
1843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got /= block_size;
1853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return got;
1863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
188879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic int host_dev;
189879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
190a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'ostatic void flush_bufs (int dev, int sync)
191a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o{
192a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o  if (v_flag
193a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#if !defined (BLKFLSBUF) && !defined (FDFLUSH)
194a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o      && sync
195a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
196a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o      )
197a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o    fprintf (stderr, "Flushing buffers\n");
198a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
199879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o  if (sync && fdatasync (dev) == -1)
200a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o    com_err (program_name, errno, "during fsync");
201a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
202879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#ifdef BLKFLSBUF
203879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o  ioctl (host_dev, BLKFLSBUF, 0);   /* In case this is a HD */
204a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
205a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#ifdef FDFLUSH
206879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o  ioctl (host_dev, FDFLUSH, 0);   /* In case this is floppy */
207a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
208a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o}
209a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
210879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic unsigned int test_ro (int dev, unsigned long blocks_count,
211879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		     unsigned long block_size,
212879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		     unsigned long from_count, unsigned long blocks_at_once)
2133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
2143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * blkbuf;
2153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int try;
2163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	long got;
217879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned int bb_count = 0;
218879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
2193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
220879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
221879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
222879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		com_err (program_name, errcode, "while beginning bad block list iteration");
223879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
224879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
225879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
226879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
227879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (next_bad && next_bad < from_count);
228879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
229879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	blkbuf = malloc (blocks_at_once * block_size);
2303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!blkbuf)
2313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
2323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err (program_name, ENOMEM, "while allocating buffers");
2333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
2343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
235a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o	flush_bufs (dev, 0);
236f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (v_flag) {
237f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	    fprintf (stderr,
238f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     "Checking for bad blocks in read-only mode\n");
239f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	    fprintf (stderr, "From block %lu to %lu\n", from_count, blocks_count);
240f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
241879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	try = blocks_at_once;
242f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	currently_testing = from_count;
2433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	num_blocks = blocks_count;
24419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (s_flag || v_flag > 1) {
2453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fprintf(stderr, "Checking for bad blocks (read-only test): ");
24619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (v_flag <= 1)
24719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			alarm_intr(SIGALRM);
2483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	while (currently_testing < blocks_count)
2503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
251879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (next_bad) {
252879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (currently_testing == next_bad) {
253879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				/* fprintf (out, "%lu\n", nextbad); */
254879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
255879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				currently_testing++;
256879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				continue;
257879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
258879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			else if (currently_testing + try > next_bad)
259879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				try = next_bad - currently_testing;
260879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
2613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (currently_testing + try > blocks_count)
2623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			try = blocks_count - currently_testing;
263879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		got = do_read (dev, blkbuf, try, block_size, currently_testing);
2643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		currently_testing += got;
2653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (got == try) {
266879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			try = blocks_at_once;
2673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			continue;
2683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
2693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		else
2703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			try = 1;
271879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (got == 0) {
272879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			bb_output (currently_testing++), ++bb_count;
273879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
2743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	num_blocks = 0;
2763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	alarm(0);
27719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (s_flag || v_flag > 1)
27800eedba1bd3a37812ee9403abca7ea4376ac9a08Theodore Ts'o		fprintf(stderr, done_string);
279879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
280f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	fflush (stderr);
2813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	free (blkbuf);
282879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
283879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	ext2fs_badblocks_list_iterate_end(bb_iter);
284879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
285879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
2863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
2873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
288879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic unsigned int test_rw (int dev, unsigned long blocks_count,
289879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		     unsigned long block_size,
290879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		     unsigned long from_count, unsigned long blocks_at_once)
2913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
2923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int i;
2933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * buffer;
2943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unsigned char pattern[] = {0xaa, 0x55, 0xff, 0x00};
295879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned int bb_count = 0;
2963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	buffer = malloc (2 * block_size);
2983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!buffer)
2993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
3003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err (program_name, ENOMEM, "while allocating buffers");
3013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
3023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
304a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o	flush_bufs (dev, 0);
305a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
30619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag) {
30719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		fprintf(stderr,
30819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			"Checking for bad blocks in read-write mode\n");
30919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		fprintf(stderr, "From block %lu to %lu\n",
31019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			 from_count, blocks_count);
31119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	}
31219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	for (i = 0; i < sizeof (pattern); i++) {
3133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		memset (buffer, pattern[i], block_size);
314f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
315f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			fprintf (stderr, "Writing pattern 0x%08x: ",
3163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				 *((int *) buffer));
317f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = blocks_count;
318f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		currently_testing = from_count;
31919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
320f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
321f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		for (;
322f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing < blocks_count;
323f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing++)
3243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
32519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
326f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 block_size, SEEK_SET) !=
327f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			    (ext2_loff_t) currently_testing * block_size)
3283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, errno,
329f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 "during seek on block %d",
330f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 currently_testing);
33119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
33219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
3333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			write (dev, buffer, block_size);
3343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
335f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
336f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
337f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
33800eedba1bd3a37812ee9403abca7ea4376ac9a08Theodore Ts'o			fprintf(stderr, done_string);
339a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o		flush_bufs (dev, 1);
340f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
341f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			fprintf (stderr, "Reading and comparing: ");
342f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = blocks_count;
343f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		currently_testing = from_count;
34419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
345f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
346f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		for (;
347f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing < blocks_count;
348f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing++)
3493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
35019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
351f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 block_size, SEEK_SET) !=
352f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			    (ext2_loff_t) currently_testing * block_size)
3533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, errno,
354f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 "during seek on block %d",
355f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 currently_testing);
35619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
35719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
3583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			if (read (dev, buffer + block_size, block_size) < block_size)
359879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
360879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				ext2fs_badblocks_list_test (bb_list, currently_testing)
361879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				|| ( bb_output (currently_testing), ++bb_count );
362879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
3633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			else if (memcmp (buffer, buffer + block_size, block_size))
364879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
365879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				ext2fs_badblocks_list_test (bb_list, currently_testing)
366879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				|| ( bb_output (currently_testing), ++bb_count );
367879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
3683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
369f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
370f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
371f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
37200eedba1bd3a37812ee9403abca7ea4376ac9a08Theodore Ts'o			fprintf(stderr, done_string);
373a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o		flush_bufs (dev, 0);
3743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
375879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
376879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
377879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
378879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
379879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic unsigned int test_nd (int dev, unsigned long blocks_count,
380879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		     unsigned long block_size,
381879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		     unsigned long from_count, unsigned long blocks_at_once)
382879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
383879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * blkbuf;
384879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * ptr;
385879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	int try;
386879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	long got;
387879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	long buf_used;
388879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned long bufblk[blocks_at_once];
389879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned long bufblks[blocks_at_once];
390879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	jmp_buf terminate_env;
391879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned int bb_count = 0;
392879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
393879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
394879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
395879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
396879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		com_err (program_name, errcode, "while beginning bad block list iteration");
397879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
398879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
399879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
400879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
401879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (next_bad && next_bad < from_count);
402879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
403879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	blkbuf = malloc (3 * blocks_at_once * block_size);
404879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (!blkbuf)
405879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	{
406879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		com_err (program_name, ENOMEM, "while allocating buffers");
407879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
408879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
409879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
410879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* inititalize the test data randomly: */
411879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag) {
412879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		fprintf (stderr, "Initializing random test data\n");
413879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
414879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	for(ptr = blkbuf + blocks_at_once * block_size;
415879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	       ptr < blkbuf + 2 * blocks_at_once * block_size;
416879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	          ++ptr) {
417879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		(*ptr) = random() % (1 << sizeof(char));
418879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
419879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
420879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	flush_bufs (dev, 0);
421879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag) {
422879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	    fprintf (stderr,
423879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		     "Checking for bad blocks in non-destructive read-write mode\n");
424879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	    fprintf (stderr, "From block %lu to %lu\n", from_count, blocks_count);
425879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
426879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	buf_used = 0;
427879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	currently_testing = from_count;
428879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	num_blocks = blocks_count;
429879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (s_flag || v_flag > 1) {
430879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		fprintf (stderr, "Checking for bad blocks (non-destructive read-write test): ");
431879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (v_flag <= 1)
432879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			alarm_intr(SIGALRM);
433879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
434879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (! setjmp(terminate_env)) {
435879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		/* set up abend handler */
436879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		capture_terminate(terminate_env);
437879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
438879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		while (currently_testing < blocks_count)
439879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		{
440879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			try = blocks_at_once - buf_used;
441879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (next_bad) {
442879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				if (currently_testing == next_bad) {
443879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					/* fprintf (out, "%lu\n", nextbad); */
444879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
445879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					bufblk[buf_used] = currently_testing++;
446879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					goto test_full_buf;
447879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				}
448879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				else if (currently_testing + try > next_bad)
449879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					try = next_bad - currently_testing;
450879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
451879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (currently_testing + try > blocks_count)
452879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				try = blocks_count - currently_testing;
453879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			got = do_read (dev, blkbuf + buf_used * block_size, try,
454879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			                                block_size, currently_testing);
455879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
456879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			/* if reading succeeded, write the test data */
457879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (got) {
458879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				long written;
459879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
460879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				written = do_write (dev, blkbuf + (buf_used + blocks_at_once) * block_size,
461879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				                             got, block_size, currently_testing);
462879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				if (written != got)
463879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					com_err (program_name, errno, "during test data write, block %lu",
464879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					                                  currently_testing + written);
465879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
466879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
467879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			bufblk[buf_used] = currently_testing;
468879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			bufblks[buf_used] = got;
469879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			buf_used += got;
470879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			currently_testing += got;
471879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (got != try)
472879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				bb_output (currently_testing++), ++bb_count;
473879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
474879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			test_full_buf:
475879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
476879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (buf_used == blocks_at_once || currently_testing == blocks_count) {
477879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				if (s_flag || v_flag > 1)
478879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					fprintf(stderr, "\n");
479879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				flush_bufs (dev, 1);
480879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
481879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				for (buf_used = 0, currently_testing = bufblk[0];
482879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				        buf_used < blocks_at_once &&
483879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				        currently_testing < blocks_count &&
484879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o                    (currently_testing = bufblk[buf_used]) < blocks_count;
485879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				           buf_used += bufblks[buf_used])
486879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					{
487879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						/* for each contiguous block that we read into the buffer
488879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						   (and wrote test data into afterwards), read it back
489879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						   (looping if necessary, to get past newly discovered
490879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						   unreadable blocks, of which there should be none, but with
491879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						   a hard drive which is unreliable, it has happened), and
492879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						   compare with the test data that was written; output to
493879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						   the bad block list if it doesn't match. */
494879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
495879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						int offset;
496879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
497879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						while ((offset = currently_testing - bufblk[buf_used]) <
498879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						                                          bufblks[buf_used]) {
499879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o							int i;
500879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
501879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o							try = bufblks[buf_used] - offset;
502879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o							got = do_read (dev, blkbuf + (2 * blocks_at_once + buf_used + offset) * block_size,
503879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						                       try, block_size, currently_testing);
504879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
505879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o							/* test the comparison between all the blocks successfully read */
506879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o							for (i = 0; i < got; ++i)
507879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o								if (memcmp (blkbuf + (blocks_at_once + buf_used + offset + i) * block_size,
508879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o								            blkbuf + (2 * blocks_at_once + buf_used + offset + i) * block_size,
509879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o								            block_size))
510879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o									bb_output (currently_testing + i), ++bb_count;
511879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
512879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o							currently_testing += got;
513879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o							if (got != try)
514879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o								bb_output (currently_testing++), ++bb_count;
515879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						}
516879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
517879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						/* when done, write back original data */
518879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						do_write (dev, blkbuf + buf_used * block_size,
519879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						               bufblks[buf_used], block_size, bufblk[buf_used]);
520879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					}
521879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
522879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				/* empty the buffer so it can be reused */
523879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				buf_used = 0;
524879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
525879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
526879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		num_blocks = 0;
527879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		alarm(0);
528879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (s_flag || v_flag > 1)
529879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			fprintf(stderr, "done               \n");
530879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
531879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} else {
532879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		/* abnormal termination by a signal is handled here */
533879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		/* logic is: write back the data that is in the buffer,
534879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		   so that we can maintain data integrity on disk.  Then
535879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		   abort. */
536879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		long buf_written;
537879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
538879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		fprintf(stderr, "Interrupt caught, cleaning up\n");
539879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
540879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		for (buf_written = 0;
541879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		        buf_written < buf_used;
542879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		           buf_written += bufblks[buf_written])
543879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			do_write (dev, blkbuf + buf_written * block_size,
544879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			               bufblks[buf_written], block_size, bufblk[buf_written]);
545879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
546879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		fflush (out);
547879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
548879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		abort ();
549879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
550879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
551879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	fflush (stderr);
552879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	free (blkbuf);
553879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
554879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	ext2fs_badblocks_list_iterate_end(bb_iter);
555879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
556879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
5573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
55900e5433eb5e9f70f485968b809fdcf297d7fe7b9Theodore Ts'oint main (int argc, char ** argv)
5603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
561519149fb458b0fa69c10fecd83fae42e838cf01dTheodore Ts'o	int c;
5623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * tmp;
5633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * device_name;
564879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * host_device_name = NULL;
565879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * input_file = NULL;
5663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * output_file = NULL;
567879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	FILE * in = NULL;
5683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unsigned long block_size = 1024;
569879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned long blocks_at_once = 16;
570f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	unsigned long blocks_count, from_count;
571879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	int num_passes = 0;
572879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	int passes_clean = 0;
5733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int dev;
574879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
5753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stdout, NULL);
5773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stderr, NULL);
5783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (argc && *argv)
5793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		program_name = *argv;
580879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	while ((c = getopt (argc, argv, "b:i:o:svwnc:p:h:")) != EOF) {
5813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		switch (c) {
5823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'b':
5833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			block_size = strtoul (optarg, &tmp, 0);
5843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			if (*tmp || block_size > 4096) {
5853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, 0,
5863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					 "bad block size - %s", optarg);
5873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				exit (1);
5883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
5893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
590879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'i':
591879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			input_file = optarg;
592879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
5933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'o':
5943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			output_file = optarg;
5953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
5963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 's':
5973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			s_flag = 1;
5983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
5993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'v':
60019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			v_flag++;
6013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
6023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'w':
603879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (! w_flag)
604879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				w_flag = 1;
605879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
606879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'n':
607879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			w_flag = 2;
608879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
609879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'c':
610879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			blocks_at_once = strtoul (optarg, &tmp, 0);
611879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (*tmp) {
612879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				com_err (program_name, 0,
613879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					 "bad simultaneous block count - %s", optarg);
614879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
615879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
616879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
617879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'p':
618879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			num_passes = strtoul (optarg, &tmp, 0);
619879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (*tmp) {
620879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				com_err (program_name, 0,
621879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				    "bad number of clean passes - %s", optarg);
622879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
623879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
624879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
625879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'h':
626879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			host_device_name = optarg;
6273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
6283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		default:
629818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o			usage();
6303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
6313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (optind > argc - 1)
633818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o		usage();
6343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	device_name = argv[optind++];
6353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (optind > argc - 1)
636818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o		usage();
6373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	blocks_count = strtoul (argv[optind], &tmp, 0);
6383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (*tmp)
6393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
6403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		com_err (program_name, 0, "bad blocks count - %s", argv[optind]);
6413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
6423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
643f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (++optind <= argc-1) {
644f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		from_count = strtoul (argv[optind], &tmp, 0);
645f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	} else from_count = 0;
646f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (from_count >= blocks_count) {
647f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	    com_err (program_name, 0, "bad blocks range: %lu-%lu",
648f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     from_count, blocks_count);
649f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	    exit (1);
650f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
6513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	dev = open (device_name, w_flag ? O_RDWR : O_RDONLY);
6523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (dev == -1)
6533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
654879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		com_err (program_name, errno, "while trying to open %s",
6553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 device_name);
6563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
6573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
658879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (host_device_name) {
659879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		host_dev = open (host_device_name, O_RDONLY);
660879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (host_dev == -1)
661879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		{
662879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			com_err (program_name, errno, "while trying to open %s",
663879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			    host_device_name);
664879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			exit (1);
665879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
666879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} else
667879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		host_dev = dev;
668879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (input_file)
669879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (strcmp (input_file, "-") == 0)
670879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			in = stdin;
671879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		else {
672879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			in = fopen (input_file, "r");
673879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (in == NULL)
674879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			{
675879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				com_err (program_name, errno,"while trying to open %s",
676879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					 input_file);
677879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
678879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
679879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
6803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (output_file && strcmp (output_file, "-") != 0)
6813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
6823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = fopen (output_file, "w");
6833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (out == NULL)
6843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
6853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			com_err (program_name, errno,"while trying to open %s",
686879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				 output_file);
6873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			exit (1);
6883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
6893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
6913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = stdout;
692879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
693879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_create(&bb_list,0);
694879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
695879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		com_err (program_name, errcode, "creating in-memory bad blocks list");
696879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
697879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
698879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
699879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (in) {
700879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		for(;;) {
701879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			switch(fscanf (in, "%lu\n", &next_bad)) {
702879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				case 0:
703879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					com_err (program_name, 0, "input file - bad format");
704879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					exit (1);
705879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				case EOF:
706879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					break;
707879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				default:
708879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					errcode = ext2fs_badblocks_list_add(bb_list,next_bad);
709879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					if (errcode) {
710879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						com_err (program_name, errcode, "adding to in-memory bad block list");
711879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						exit (1);
712879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					}
713879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					continue;
714879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
715879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
716879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
717879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
718879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (in != stdin)
719879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			fclose (in);
720879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
721879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
722879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
723879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		unsigned int bb_count;
724879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
725879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		(bb_count =
726879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
727879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		(w_flag == 2 ? test_nd
728879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		    : w_flag ? test_rw
729879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		             : test_ro)
730879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		                        (dev, blocks_count, block_size, from_count,
731879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		                              blocks_at_once)
732879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		)	? passes_clean = 0 : ++passes_clean;
733879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
734879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (v_flag)
735879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			fprintf(stderr,"Pass completed, %u bad blocks found.\n", bb_count);
736879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
737879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (passes_clean < num_passes);
738879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
7393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	close (dev);
7403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (out != stdout)
7413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fclose (out);
742879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return 0;
7433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
744