badblocks.c revision 8820c79f75c37a3bc85cea7f56e7277025e157ef
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 */
67981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic int force = 0;			/* force check of mounted device */
684d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
698820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'ostatic void usage(void)
703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
71a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	fprintf(stderr, _("Usage: %s [-b block_size] [-i input_file] [-o output_file] [-svwnf]\n [-c blocks_at_once] [-p num_passes] device [blocks_count [start_count]]\n"),
723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		 program_name);
733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	exit (1);
743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic unsigned long currently_testing = 0;
7719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'ostatic unsigned long num_blocks = 0;
78879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic ext2_badblocks_list bb_list = NULL;
79879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic FILE *out;
80879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic blk_t next_bad = 0;
81879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic ext2_badblocks_iterate bb_iter = NULL;
8219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
83dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o/*
84dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * This routine reports a new bad block.  If the bad block has already
85dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o * been seen before, then it returns 0; otherwise it returns 1.
86dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o */
87dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'ostatic int bb_output (unsigned long bad)
88879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
89879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
90879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
91dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	if (ext2fs_badblocks_list_test(bb_list, bad))
92dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		return 0;
93dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o
94879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	fprintf (out, "%lu\n", bad);
95879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
96879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_add (bb_list, bad);
97879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
98879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		com_err (program_name, errcode, "adding to in-memory bad block list");
99879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
100879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
101879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
102879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* kludge:
103879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   increment the iteration through the bb_list if
104879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   an element was just added before the current iteration
105879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	   position.  This should not cause next_bad to change. */
106879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (bb_iter && bad < next_bad)
107879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
108dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	return 1;
109879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
110879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1118820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'ostatic void print_status(void)
11219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
11319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
11419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
11519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fflush (stderr);
11619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
11719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
118981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic void alarm_intr(int alnum)
11919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o{
12019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	signal (SIGALRM, alarm_intr);
12119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	alarm(1);
12219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (!num_blocks)
12319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		return;
12419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "%9ld/%9ld", currently_testing, num_blocks);
12519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fprintf(stderr, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
12619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	fflush (stderr);
12719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o}
12819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
129879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic void *terminate_addr = NULL;
130879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
131981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic void terminate_intr(int signo)
132879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
133879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (terminate_addr)
134879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		longjmp(terminate_addr,1);
135879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	exit(1);
136879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
137879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
138981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic void capture_terminate(jmp_buf term_addr)
139879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
140879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	terminate_addr = term_addr;
141879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGHUP, terminate_intr);
142879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGINT, terminate_intr);
143879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGPIPE, terminate_intr);
144879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGTERM, terminate_intr);
145879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGUSR1, terminate_intr);
146879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	signal (SIGUSR2, terminate_intr);
147879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
148879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
1498820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'ostatic void uncapture_terminate(void)
1504d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o{
1514d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	terminate_addr = NULL;
1524d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGHUP, SIG_DFL);
1534d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGINT, SIG_DFL);
1544d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGPIPE, SIG_DFL);
1554d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGTERM, SIG_DFL);
1564d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGUSR1, SIG_DFL);
1574d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	signal (SIGUSR2, SIG_DFL);
1584d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o}
1594d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
1603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
161879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Perform a read of a sequence of blocks; return the number of blocks
162879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o *    successfully sequentially read.
1633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
164dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'ostatic long do_read (int dev, char * buffer, int try, int block_size,
1653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		     unsigned long current_block)
1663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	long got;
1683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
16919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag > 1)
17019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		print_status();
17119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o
1723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Seek to the correct loc. */
17319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
174f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			 SEEK_SET) != (ext2_loff_t) current_block * block_size)
175d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("during seek"));
1763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/* Try the read */
1783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got = read (dev, buffer, try * block_size);
1793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (got < 0)
1803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		got = 0;
1819f10a7b31e57288093930fc9565102409eeac6e9Theodore Ts'o	if (got & 511)
182d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("Weird value (%ld) in do_read\n"), got);
183879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	got /= block_size;
184879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return got;
185879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
186879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
187879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o/*
188879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o * Perform a write of a sequence of blocks; return the number of blocks
189879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o *    successfully sequentially written.
190879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o */
191dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'ostatic long do_write (int dev, char * buffer, int try, int block_size,
192879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		     unsigned long current_block)
193879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
194879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	long got;
195879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
196879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag > 1)
197879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		print_status();
198879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
199879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* Seek to the correct loc. */
200879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
201879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			 SEEK_SET) != (ext2_loff_t) current_block * block_size)
202d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("during seek"));
203879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
204879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* Try the write */
205879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	got = write (dev, buffer, try * block_size);
206879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (got < 0)
207879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		got = 0;
208879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (got & 511)
209879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		fprintf (stderr,
210879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			 "Weird value (%ld) in do_write\n", got);
2113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	got /= block_size;
2123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return got;
2133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
2143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
215879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic int host_dev;
216879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
217d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'ostatic void flush_bufs (int dev)
218a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o{
219e2207ce595f05e4db5945326f9b2d553ff7a4d57Theodore Ts'o#ifdef HAVE_FDATASYNC
2208820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'o  if (fdatasync (dev) == -1)
221e2207ce595f05e4db5945326f9b2d553ff7a4d57Theodore Ts'o    com_err (program_name, errno, _("during fdatasync"));
222e2207ce595f05e4db5945326f9b2d553ff7a4d57Theodore Ts'o#else
2238820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'o  if (fsync (dev) == -1)
224d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o    com_err (program_name, errno, _("during fsync"));
225e2207ce595f05e4db5945326f9b2d553ff7a4d57Theodore Ts'o#endif
226a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
227879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o#ifdef BLKFLSBUF
228879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o  ioctl (host_dev, BLKFLSBUF, 0);   /* In case this is a HD */
229a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
230a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#ifdef FDFLUSH
231879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o  ioctl (host_dev, FDFLUSH, 0);   /* In case this is floppy */
232a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o#endif
233a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o}
234a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
235879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic unsigned int test_ro (int dev, unsigned long blocks_count,
236dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     int block_size, unsigned long from_count,
237dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     unsigned long blocks_at_once)
2383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
2393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * blkbuf;
2403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int try;
2413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	long got;
242879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned int bb_count = 0;
243879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
2443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
245879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
246879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
247d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errcode,
248d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			 _("while beginning bad block list iteration"));
249879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
250879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
251879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
252879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
253879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (next_bad && next_bad < from_count);
254879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
255879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	blkbuf = malloc (blocks_at_once * block_size);
2563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!blkbuf)
2573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
258d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, ENOMEM, _("while allocating buffers"));
2593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
2603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
261d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	flush_bufs(dev);
262f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (v_flag) {
263d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	    fprintf(stderr, _("Checking for bad blocks in read-only mode\n"));
264d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	    fprintf (stderr, _("From block %lu to %lu\n"), from_count,
265d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		     blocks_count);
266f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
267879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	try = blocks_at_once;
268f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	currently_testing = from_count;
2693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	num_blocks = blocks_count;
27019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (s_flag || v_flag > 1) {
271d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr,
272d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			_("Checking for bad blocks (read-only test): "));
27319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (v_flag <= 1)
27419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			alarm_intr(SIGALRM);
2753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	while (currently_testing < blocks_count)
2773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
278879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (next_bad) {
279879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (currently_testing == next_bad) {
280879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				/* fprintf (out, "%lu\n", nextbad); */
281879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
282879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				currently_testing++;
283879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				continue;
284879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
285879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			else if (currently_testing + try > next_bad)
286879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				try = next_bad - currently_testing;
287879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
2883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (currently_testing + try > blocks_count)
2893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			try = blocks_count - currently_testing;
290879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		got = do_read (dev, blkbuf, try, block_size, currently_testing);
2913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		currently_testing += got;
2923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (got == try) {
293879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			try = blocks_at_once;
2943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			continue;
2953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
2963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		else
2973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			try = 1;
298879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (got == 0) {
299dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			bb_count += bb_output(currently_testing++);
300879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
3013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	num_blocks = 0;
3033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	alarm(0);
30419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (s_flag || v_flag > 1)
3058f5c0f66ca343ec4689470e5941aa3066ed062bbTheodore Ts'o		fprintf(stderr, _(done_string));
306879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
307f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	fflush (stderr);
3083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	free (blkbuf);
309879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
310879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	ext2fs_badblocks_list_iterate_end(bb_iter);
311879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
312879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
3133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
3143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
315879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic unsigned int test_rw (int dev, unsigned long blocks_count,
316dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     int block_size, unsigned long from_count,
317dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     unsigned long blocks_at_once)
3183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int i;
3203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * buffer;
3218820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'o	static unsigned char pattern[] = {0xaa, 0x55, 0xff, 0x00};
322879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned int bb_count = 0;
3233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	buffer = malloc (2 * block_size);
3253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!buffer)
3263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
327d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, ENOMEM, _("while allocating buffers"));
3283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
3293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
331d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	flush_bufs(dev);
332a418d3ad819323f871005d253f7f9ac378e78ba5Theodore Ts'o
33319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (v_flag) {
33419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		fprintf(stderr,
335d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			_("Checking for bad blocks in read-write mode\n"));
336d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("From block %lu to %lu\n"),
33719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			 from_count, blocks_count);
33819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	}
33919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	for (i = 0; i < sizeof (pattern); i++) {
3403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		memset (buffer, pattern[i], block_size);
341f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
342d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			fprintf (stderr, _("Writing pattern 0x%08x: "),
3433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				 *((int *) buffer));
344f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = blocks_count;
345f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		currently_testing = from_count;
34619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
347f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
348f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		for (;
349f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing < blocks_count;
350f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing++)
3513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
35219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
353f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 block_size, SEEK_SET) !=
354f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			    (ext2_loff_t) currently_testing * block_size)
3553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, errno,
356d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("during seek on block %d"),
357f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 currently_testing);
35819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
35919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
3603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			write (dev, buffer, block_size);
3613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
362f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
363f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
364f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
3658f5c0f66ca343ec4689470e5941aa3066ed062bbTheodore Ts'o			fprintf(stderr, _(done_string));
366d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		flush_bufs(dev);
367f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
368d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			fprintf (stderr, _("Reading and comparing: "));
369f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = blocks_count;
370f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		currently_testing = from_count;
37119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o		if (s_flag && v_flag <= 1)
372f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			alarm_intr(SIGALRM);
373f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		for (;
374f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing < blocks_count;
375f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     currently_testing++)
3763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
37719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (ext2fs_llseek (dev, (ext2_loff_t) currently_testing *
378f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 block_size, SEEK_SET) !=
379f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o			    (ext2_loff_t) currently_testing * block_size)
3803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, errno,
381d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("during seek on block %d"),
382f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o					 currently_testing);
38319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			if (v_flag > 1)
38419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o				print_status();
385dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			if ((read (dev, buffer + block_size, block_size)
3864d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			     != block_size) ||
387dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			    memcmp(buffer, buffer + block_size, block_size))
3884d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				bb_count += bb_output(currently_testing);
3893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
390f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		num_blocks = 0;
391f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		alarm (0);
392f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		if (s_flag | v_flag)
3938f5c0f66ca343ec4689470e5941aa3066ed062bbTheodore Ts'o			fprintf(stderr, _(done_string));
394d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		flush_bufs(dev);
3953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
396879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
397879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
398879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o}
399879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
400d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'ostruct saved_blk_record {
401d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	blk_t	block;
402d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	int	num;
403d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o};
404d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o
405879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'ostatic unsigned int test_nd (int dev, unsigned long blocks_count,
406dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     int block_size, unsigned long from_count,
407dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o			     unsigned long blocks_at_once)
408879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o{
409dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	char *blkbuf, *save_ptr, *test_ptr, *read_ptr;
410879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * ptr;
411dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	int try, i;
412a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	long got, used2, written, save_currently_testing;
413d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	struct saved_blk_record *test_record;
414a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	/* This is static to prevent being clobbered by the longjmp */
415a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	static int num_saved;
416879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	jmp_buf terminate_env;
417879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
418a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	long buf_used;
419a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	unsigned int bb_count;
420879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
421879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
422879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
423dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		com_err (program_name, errcode,
424d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			 _("while beginning bad block list iteration"));
425879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
426879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
427879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
428879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
429879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (next_bad && next_bad < from_count);
430879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
431879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	blkbuf = malloc (3 * blocks_at_once * block_size);
432d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	test_record = malloc (blocks_at_once*sizeof(struct saved_blk_record));
433d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	if (!blkbuf || !test_record) {
434d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err(program_name, ENOMEM, _("while allocating buffers"));
435879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
436879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
437d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	num_saved = 0;
438879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
439879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	/* inititalize the test data randomly: */
440879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag) {
441d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf (stderr, _("Initializing random test data\n"));
442879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
443879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	for(ptr = blkbuf + blocks_at_once * block_size;
444dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	    ptr < blkbuf + 2 * blocks_at_once * block_size;
445dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	    ++ptr) {
446879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		(*ptr) = random() % (1 << sizeof(char));
447879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
448879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
449d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	flush_bufs(dev);
450879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (v_flag) {
451879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	    fprintf (stderr,
452d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		     _("Checking for bad blocks in non-destructive read-write mode\n"));
453d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	    fprintf (stderr, _("From block %lu to %lu\n"), from_count, blocks_count);
454879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
455879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (s_flag || v_flag > 1) {
456d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		fprintf(stderr, _("Checking for bad blocks (non-destructive read-write test): "));
457879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (v_flag <= 1)
458879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			alarm_intr(SIGALRM);
459879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
4604d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	if (setjmp(terminate_env)) {
4614d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		/*
4624d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * Abnormal termination by a signal is handled here.
4634d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 */
464a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		signal (SIGALRM, SIG_IGN);
465a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		fprintf(stderr, _("\nInterrupt caught, cleaning up\n"));
466879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
467d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		save_ptr = blkbuf;
468d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		for (i=0; i < num_saved; i++) {
469d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			do_write(dev, save_ptr, test_record[i].num,
470d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				 block_size, test_record[i].block);
471d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			save_ptr += test_record[i].num * block_size;
472d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		}
473879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		fflush (out);
474dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o		exit(1);
475879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
4764d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
4774d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	/* set up abend handler */
4784d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	capture_terminate(terminate_env);
4794d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
480d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	buf_used = 0;
481a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	bb_count = 0;
482d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	save_ptr = blkbuf;
4834d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	test_ptr = blkbuf + (blocks_at_once * block_size);
4844d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	currently_testing = from_count;
4854d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	num_blocks = blocks_count;
4864d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
4874d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	while (currently_testing < blocks_count) {
4884d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		try = blocks_at_once - buf_used;
4894d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if (next_bad) {
4904d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (currently_testing == next_bad) {
4914d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				/* fprintf (out, "%lu\n", nextbad); */
4924d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
493d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				currently_testing++;
494d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				goto check_for_more;
4954d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			}
4964d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			else if (currently_testing + try > next_bad)
4974d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				try = next_bad - currently_testing;
4984d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		}
4994d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if (currently_testing + try > blocks_count)
5004d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			try = blocks_count - currently_testing;
5014d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		got = do_read (dev, save_ptr, try, block_size,
5024d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			       currently_testing);
503d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		if (got == 0) {
504d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			/* First block must have been bad. */
505d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			bb_count += bb_output(currently_testing++);
506d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			goto check_for_more;
507d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		}
5084d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
509d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		/*
510d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		 * Note the fact that we've saved this much data
511d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		 * *before* we overwrite it with test data
512d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		 */
513d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		test_record[num_saved].block = currently_testing;
514d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		test_record[num_saved].num = got;
515d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		num_saved++;
516d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o
517d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		/* Write the test data */
518d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		written = do_write (dev, test_ptr, got, block_size,
519d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				    currently_testing);
520d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		if (written != got)
521d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o			com_err (program_name, errno,
5224d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				 _("during test data write, block %lu"),
523d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o				 currently_testing + written);
5244d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
5254d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		buf_used += got;
5264d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		save_ptr += got * block_size;
5274d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		test_ptr += got * block_size;
5284d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		currently_testing += got;
5294d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if (got != try)
5304d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			bb_count += bb_output(currently_testing++);
5314d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
532d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	check_for_more:
5334d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		/*
5344d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * If there's room for more blocks to be tested this
5354d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * around, and we're not done yet testing the disk, go
5364d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 * back and get some more blocks.
5374d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		 */
5384d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if ((buf_used != blocks_at_once) &&
539d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		    (currently_testing < blocks_count))
5404d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			continue;
5414d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
542d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o		flush_bufs(dev);
543a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		save_currently_testing = currently_testing;
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);
600a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		currently_testing = save_currently_testing;
6014d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	}
6024d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	num_blocks = 0;
6034d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	alarm(0);
6044d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	uncapture_terminate();
6054d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	if (s_flag || v_flag > 1)
6064d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		fprintf(stderr, _(done_string));
607879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
608dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	fflush(stderr);
609dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	free(blkbuf);
610d49a22b734299e4b433a19b8f5f60d689c92a78eTheodore Ts'o	free(test_record);
611879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
612879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	ext2fs_badblocks_list_iterate_end(bb_iter);
613879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
614879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return bb_count;
6153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
617981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'ostatic void check_mount(char *device_name)
618981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o{
619981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	errcode_t	retval;
620981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	int		mount_flags;
621981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
622981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	retval = ext2fs_check_if_mounted(device_name, &mount_flags);
623981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	if (retval) {
624981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		com_err("ext2fs_check_if_mount", retval,
625981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			_("while determining whether %s is mounted."),
626981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			device_name);
627981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		return;
628981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	}
629981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	if (!(mount_flags & EXT2_MF_MOUNTED))
630981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		return;
631981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
632981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	fprintf(stderr, _("%s is mounted; "), device_name);
633981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	if (force) {
634981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		fprintf(stderr, _("badblocks forced anyway.  "
635981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			"Hope /etc/mtab is incorrect.\n"));
636981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		return;
637981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	}
638981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	fprintf(stderr, _("it's not safe to run badblocks!\n"));
639981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	exit(1);
640981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o}
641981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
642981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
64300e5433eb5e9f70f485968b809fdcf297d7fe7b9Theodore Ts'oint main (int argc, char ** argv)
6443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
645519149fb458b0fa69c10fecd83fae42e838cf01dTheodore Ts'o	int c;
6463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * tmp;
6473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * device_name;
648879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * host_device_name = NULL;
649879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	char * input_file = NULL;
6503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char * output_file = NULL;
651879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	FILE * in = NULL;
652dd018f5aa41cc21d22f01c45a3eee6ce492eb228Theodore Ts'o	int block_size = 1024;
653879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	unsigned long blocks_at_once = 16;
65435964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	blk_t blocks_count, from_count;
655879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	int num_passes = 0;
656879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	int passes_clean = 0;
6573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int dev;
658879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode_t errcode;
6598820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'o	unsigned int (*test_func)(int, unsigned long,
6608820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'o				  int, unsigned long,
6618820c79f75c37a3bc85cea7f56e7277025e157efTheodore Ts'o				  unsigned long);
6623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stdout, NULL);
6643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	setbuf(stderr, NULL);
665d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#ifdef ENABLE_NLS
666d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	setlocale(LC_MESSAGES, "");
667d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
668d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	textdomain(NLS_CAT_NAME);
669d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o#endif
6704d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o	test_func = test_ro;
6714d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
6723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (argc && *argv)
6733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		program_name = *argv;
674a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o	while ((c = getopt (argc, argv, "b:fi:o:svwnc:p:h:")) != EOF) {
6753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		switch (c) {
6763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'b':
6773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			block_size = strtoul (optarg, &tmp, 0);
6783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			if (*tmp || block_size > 4096) {
6793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				com_err (program_name, 0,
680d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("bad block size - %s"), optarg);
6813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				exit (1);
6823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			}
6833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
684981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		case 'f':
685981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			force++;
686981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o			break;
687879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'i':
688879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			input_file = optarg;
689879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
6903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'o':
6913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			output_file = optarg;
6923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
6933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 's':
6943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			s_flag = 1;
6953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
6963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'v':
69719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o			v_flag++;
6983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
6993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		case 'w':
7004d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (w_flag)
7014d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				usage();
7024d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_func = test_rw;
7034d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			w_flag = 1;
704879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
705879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'n':
7064d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			if (w_flag)
7074d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				usage();
7084d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			test_func = test_nd;
709879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			w_flag = 2;
710879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
711879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'c':
712879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			blocks_at_once = strtoul (optarg, &tmp, 0);
713879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (*tmp) {
714879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				com_err (program_name, 0,
715879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					 "bad simultaneous block count - %s", optarg);
716879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
717879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
718879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
719879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'p':
720879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			num_passes = strtoul (optarg, &tmp, 0);
721879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (*tmp) {
722879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				com_err (program_name, 0,
723879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				    "bad number of clean passes - %s", optarg);
724879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
725879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
726879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
727879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		case 'h':
728879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			host_device_name = optarg;
7293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			break;
7303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		default:
731818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o			usage();
7323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
7333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
7343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (optind > argc - 1)
735818180cdfcff84b9048ecdc5dc86323f0fefba24Theodore Ts'o		usage();
7363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	device_name = argv[optind++];
73735964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	if (optind > argc - 1) {
73835964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		errcode = ext2fs_get_device_size(device_name,
73935964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o						 block_size,
74035964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o						 &blocks_count);
74135964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		if (errcode == EXT2_ET_UNIMPLEMENTED) {
74235964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			com_err(program_name, 0,
74335964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				_("Couldn't determine device size; you "
74435964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				  "must specify\nthe size manually\n"));
74535964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			exit(1);
74635964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		}
74735964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		if (errcode) {
74835964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			com_err(program_name, errcode,
74935964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				_("while trying to determine device size"));
75035964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			exit(1);
75135964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		}
75235964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	} else {
75335964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		blocks_count = strtoul (argv[optind], &tmp, 0);
75435964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		if (*tmp) {
75535964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			com_err (program_name, 0, _("bad blocks count - %s"),
75635964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o				 argv[optind]);
75735964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o			exit (1);
75835964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		}
75935964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o		optind++;
7603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
76135964b5c4a85ab73c1ac02caed98584b6527f7c2Theodore Ts'o	if (optind <= argc-1) {
762f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		from_count = strtoul (argv[optind], &tmp, 0);
763a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		if (*tmp) {
764a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o			com_err (program_name, 0, _("bad starting block - %s"),
765a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o				 argv[optind]);
766a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o			exit (1);
767a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o		}
768f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	} else from_count = 0;
769f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (from_count >= blocks_count) {
770d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o	    com_err (program_name, 0, _("bad blocks range: %lu-%lu"),
771f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		     from_count, blocks_count);
772f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	    exit (1);
773f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	}
774981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o	if (w_flag)
775981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o		check_mount(device_name);
776981dc56ae312ef6f13ab5fca57ef51616890e13fTheodore Ts'o
7773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	dev = open (device_name, w_flag ? O_RDWR : O_RDONLY);
7783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (dev == -1)
7793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
780d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errno, _("while trying to open %s"),
7813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			 device_name);
7823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		exit (1);
7833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
784879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (host_device_name) {
785879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		host_dev = open (host_device_name, O_RDONLY);
786879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (host_dev == -1)
787879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		{
788d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			com_err (program_name, errno,
789d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 _("while trying to open %s"),
790d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 host_device_name);
791879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			exit (1);
792879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
793879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} else
794879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		host_dev = dev;
795879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (input_file)
796879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (strcmp (input_file, "-") == 0)
797879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			in = stdin;
798879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		else {
799879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			in = fopen (input_file, "r");
800879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			if (in == NULL)
801879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			{
802d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				com_err (program_name, errno,
803d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o					 _("while trying to open %s"),
804879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					 input_file);
805879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				exit (1);
806879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
807879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
8083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (output_file && strcmp (output_file, "-") != 0)
8093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	{
8103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = fopen (output_file, "w");
8113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (out == NULL)
8123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		{
813d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			com_err (program_name, errno,
814d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				 _("while trying to open %s"),
815879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				 output_file);
8163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			exit (1);
8173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		}
8183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
8193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else
8203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		out = stdout;
821879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
822879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	errcode = ext2fs_badblocks_list_create(&bb_list,0);
823879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (errcode) {
824d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o		com_err (program_name, errcode,
825d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			 _("creating in-memory bad blocks list"));
826879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		exit (1);
827879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
828879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
829879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	if (in) {
830879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		for(;;) {
831a551b783479b47d05ec996da5c87009a092cf491Theodore Ts'o			switch(fscanf (in, "%u\n", &next_bad)) {
832879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				case 0:
833879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					com_err (program_name, 0, "input file - bad format");
834879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					exit (1);
835879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				case EOF:
836879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					break;
837879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o				default:
838879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					errcode = ext2fs_badblocks_list_add(bb_list,next_bad);
839879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					if (errcode) {
840d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o						com_err (program_name, errcode, _("adding to in-memory bad block list"));
841879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o						exit (1);
842879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					}
843879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o					continue;
844879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			}
845879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			break;
846879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		}
847879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
848879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (in != stdin)
849879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o			fclose (in);
850879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	}
851879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
852879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	do {
853879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		unsigned int bb_count;
854879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
8554d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		bb_count = test_func(dev, blocks_count, block_size,
8564d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o				     from_count, blocks_at_once);
8574d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		if (bb_count)
8584d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			passes_clean = 0;
8594d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o		else
8604d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o			++passes_clean;
8614d003982f95ea4151b964f5f986e8af76707bde0Theodore Ts'o
862879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o		if (v_flag)
863d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o			fprintf(stderr,
864d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				_("Pass completed, %u bad blocks found.\n"),
865d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o				bb_count);
866879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
867879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	} while (passes_clean < num_passes);
868879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o
8693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	close (dev);
8703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (out != stdout)
8713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		fclose (out);
872879ac920e347267d4461ba76b349fbef67b42b9bTheodore Ts'o	return 0;
8733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
874d9c56d3ca0bee11e3446ff7e12e3124d28e298a7Theodore Ts'o
875