1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker * badblocks.c - Bad blocks checker
3*6a54128fSAndroid Build Coastguard Worker *
4*6a54128fSAndroid Build Coastguard Worker * Copyright (C) 1992, 1993, 1994 Remy Card <[email protected]>
5*6a54128fSAndroid Build Coastguard Worker * Laboratoire MASI, Institut Blaise Pascal
6*6a54128fSAndroid Build Coastguard Worker * Universite Pierre et Marie Curie (Paris VI)
7*6a54128fSAndroid Build Coastguard Worker *
8*6a54128fSAndroid Build Coastguard Worker * Copyright 1995, 1996, 1997, 1998, 1999 by Theodore Ts'o
9*6a54128fSAndroid Build Coastguard Worker * Copyright 1999 by David Beattie
10*6a54128fSAndroid Build Coastguard Worker *
11*6a54128fSAndroid Build Coastguard Worker * This file is based on the minix file system programs fsck and mkfs
12*6a54128fSAndroid Build Coastguard Worker * written and copyrighted by Linus Torvalds <[email protected]>
13*6a54128fSAndroid Build Coastguard Worker *
14*6a54128fSAndroid Build Coastguard Worker * %Begin-Header%
15*6a54128fSAndroid Build Coastguard Worker * This file may be redistributed under the terms of the GNU Public
16*6a54128fSAndroid Build Coastguard Worker * License.
17*6a54128fSAndroid Build Coastguard Worker * %End-Header%
18*6a54128fSAndroid Build Coastguard Worker */
19*6a54128fSAndroid Build Coastguard Worker
20*6a54128fSAndroid Build Coastguard Worker /*
21*6a54128fSAndroid Build Coastguard Worker * History:
22*6a54128fSAndroid Build Coastguard Worker * 93/05/26 - Creation from e2fsck
23*6a54128fSAndroid Build Coastguard Worker * 94/02/27 - Made a separate bad blocks checker
24*6a54128fSAndroid Build Coastguard Worker * 99/06/30...99/07/26 - Added non-destructive write-testing,
25*6a54128fSAndroid Build Coastguard Worker * configurable blocks-at-once parameter,
26*6a54128fSAndroid Build Coastguard Worker * loading of badblocks list to avoid testing
27*6a54128fSAndroid Build Coastguard Worker * blocks known to be bad, multiple passes to
28*6a54128fSAndroid Build Coastguard Worker * make sure that no new blocks are added to the
29*6a54128fSAndroid Build Coastguard Worker * list. (Work done by David Beattie)
30*6a54128fSAndroid Build Coastguard Worker */
31*6a54128fSAndroid Build Coastguard Worker
32*6a54128fSAndroid Build Coastguard Worker #ifndef _GNU_SOURCE
33*6a54128fSAndroid Build Coastguard Worker #define _GNU_SOURCE /* for O_DIRECT */
34*6a54128fSAndroid Build Coastguard Worker #endif
35*6a54128fSAndroid Build Coastguard Worker
36*6a54128fSAndroid Build Coastguard Worker #include "config.h"
37*6a54128fSAndroid Build Coastguard Worker #include <errno.h>
38*6a54128fSAndroid Build Coastguard Worker #include <fcntl.h>
39*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_GETOPT_H
40*6a54128fSAndroid Build Coastguard Worker #include <getopt.h>
41*6a54128fSAndroid Build Coastguard Worker #else
42*6a54128fSAndroid Build Coastguard Worker extern char *optarg;
43*6a54128fSAndroid Build Coastguard Worker extern int optind;
44*6a54128fSAndroid Build Coastguard Worker #endif
45*6a54128fSAndroid Build Coastguard Worker #include <signal.h>
46*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
47*6a54128fSAndroid Build Coastguard Worker #include <stdlib.h>
48*6a54128fSAndroid Build Coastguard Worker #include <string.h>
49*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
50*6a54128fSAndroid Build Coastguard Worker #include <setjmp.h>
51*6a54128fSAndroid Build Coastguard Worker #include <time.h>
52*6a54128fSAndroid Build Coastguard Worker #include <limits.h>
53*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_MBSTOWCS
54*6a54128fSAndroid Build Coastguard Worker #include <wchar.h>
55*6a54128fSAndroid Build Coastguard Worker #endif
56*6a54128fSAndroid Build Coastguard Worker
57*6a54128fSAndroid Build Coastguard Worker #include <sys/time.h>
58*6a54128fSAndroid Build Coastguard Worker #include <sys/ioctl.h>
59*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
60*6a54128fSAndroid Build Coastguard Worker
61*6a54128fSAndroid Build Coastguard Worker #include "et/com_err.h"
62*6a54128fSAndroid Build Coastguard Worker #include "ext2fs/ext2_io.h"
63*6a54128fSAndroid Build Coastguard Worker #include "ext2fs/ext2_fs.h"
64*6a54128fSAndroid Build Coastguard Worker #include "ext2fs/ext2fs.h"
65*6a54128fSAndroid Build Coastguard Worker #include "support/nls-enable.h"
66*6a54128fSAndroid Build Coastguard Worker
67*6a54128fSAndroid Build Coastguard Worker #ifndef O_LARGEFILE
68*6a54128fSAndroid Build Coastguard Worker #define O_LARGEFILE 0
69*6a54128fSAndroid Build Coastguard Worker #endif
70*6a54128fSAndroid Build Coastguard Worker
71*6a54128fSAndroid Build Coastguard Worker /* Maximum number of bad blocks we support */
72*6a54128fSAndroid Build Coastguard Worker #define MAX_BAD_BLOCKS (INT_MAX/2)
73*6a54128fSAndroid Build Coastguard Worker
74*6a54128fSAndroid Build Coastguard Worker static const char * program_name = "badblocks";
75*6a54128fSAndroid Build Coastguard Worker static const char * done_string = N_("done \n");
76*6a54128fSAndroid Build Coastguard Worker
77*6a54128fSAndroid Build Coastguard Worker static int v_flag; /* verbose */
78*6a54128fSAndroid Build Coastguard Worker static int w_flag; /* do r/w test: 0=no, 1=yes,
79*6a54128fSAndroid Build Coastguard Worker * 2=non-destructive */
80*6a54128fSAndroid Build Coastguard Worker static int s_flag; /* show progress of test */
81*6a54128fSAndroid Build Coastguard Worker static int force; /* force check of mounted device */
82*6a54128fSAndroid Build Coastguard Worker static int t_flag; /* number of test patterns */
83*6a54128fSAndroid Build Coastguard Worker static int t_max; /* allocated test patterns */
84*6a54128fSAndroid Build Coastguard Worker static unsigned int *t_patts; /* test patterns */
85*6a54128fSAndroid Build Coastguard Worker static int use_buffered_io;
86*6a54128fSAndroid Build Coastguard Worker static int exclusive_ok;
87*6a54128fSAndroid Build Coastguard Worker static unsigned int max_bb = MAX_BAD_BLOCKS; /* Abort test if more than this
88*6a54128fSAndroid Build Coastguard Worker * number of bad blocks has been
89*6a54128fSAndroid Build Coastguard Worker * encountered */
90*6a54128fSAndroid Build Coastguard Worker static unsigned int d_flag; /* delay factor between reads */
91*6a54128fSAndroid Build Coastguard Worker static struct timeval time_start;
92*6a54128fSAndroid Build Coastguard Worker
93*6a54128fSAndroid Build Coastguard Worker #define T_INC 32
94*6a54128fSAndroid Build Coastguard Worker
95*6a54128fSAndroid Build Coastguard Worker static unsigned int sys_page_size = 4096;
96*6a54128fSAndroid Build Coastguard Worker
usage(void)97*6a54128fSAndroid Build Coastguard Worker static void usage(void)
98*6a54128fSAndroid Build Coastguard Worker {
99*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, _(
100*6a54128fSAndroid Build Coastguard Worker "Usage: %s [-b block_size] [-i input_file] [-o output_file] [-svwnfBX]\n"
101*6a54128fSAndroid Build Coastguard Worker " [-c blocks_at_once] [-d delay_factor_between_reads] [-e max_bad_blocks]\n"
102*6a54128fSAndroid Build Coastguard Worker " [-p num_passes] [-t test_pattern [-t test_pattern [...]]]\n"
103*6a54128fSAndroid Build Coastguard Worker " device [last_block [first_block]]\n"),
104*6a54128fSAndroid Build Coastguard Worker program_name);
105*6a54128fSAndroid Build Coastguard Worker exit (1);
106*6a54128fSAndroid Build Coastguard Worker }
107*6a54128fSAndroid Build Coastguard Worker
exclusive_usage(void)108*6a54128fSAndroid Build Coastguard Worker static void exclusive_usage(void)
109*6a54128fSAndroid Build Coastguard Worker {
110*6a54128fSAndroid Build Coastguard Worker fprintf(stderr,
111*6a54128fSAndroid Build Coastguard Worker _("%s: The -n and -w options are mutually exclusive.\n\n"),
112*6a54128fSAndroid Build Coastguard Worker program_name);
113*6a54128fSAndroid Build Coastguard Worker exit(1);
114*6a54128fSAndroid Build Coastguard Worker }
115*6a54128fSAndroid Build Coastguard Worker
116*6a54128fSAndroid Build Coastguard Worker static blk_t currently_testing = 0;
117*6a54128fSAndroid Build Coastguard Worker static blk_t num_blocks = 0;
118*6a54128fSAndroid Build Coastguard Worker static blk_t num_read_errors = 0;
119*6a54128fSAndroid Build Coastguard Worker static blk_t num_write_errors = 0;
120*6a54128fSAndroid Build Coastguard Worker static blk_t num_corruption_errors = 0;
121*6a54128fSAndroid Build Coastguard Worker static ext2_badblocks_list bb_list = NULL;
122*6a54128fSAndroid Build Coastguard Worker static FILE *out;
123*6a54128fSAndroid Build Coastguard Worker static blk_t next_bad = 0;
124*6a54128fSAndroid Build Coastguard Worker static ext2_badblocks_iterate bb_iter = NULL;
125*6a54128fSAndroid Build Coastguard Worker
126*6a54128fSAndroid Build Coastguard Worker enum error_types { READ_ERROR, WRITE_ERROR, CORRUPTION_ERROR };
127*6a54128fSAndroid Build Coastguard Worker
allocate_buffer(size_t size)128*6a54128fSAndroid Build Coastguard Worker static void *allocate_buffer(size_t size)
129*6a54128fSAndroid Build Coastguard Worker {
130*6a54128fSAndroid Build Coastguard Worker void *ret = 0;
131*6a54128fSAndroid Build Coastguard Worker
132*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_POSIX_MEMALIGN
133*6a54128fSAndroid Build Coastguard Worker if (posix_memalign(&ret, sys_page_size, size) != 0)
134*6a54128fSAndroid Build Coastguard Worker ret = 0;
135*6a54128fSAndroid Build Coastguard Worker #else
136*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_MEMALIGN
137*6a54128fSAndroid Build Coastguard Worker ret = memalign(sys_page_size, size);
138*6a54128fSAndroid Build Coastguard Worker #else
139*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_VALLOC
140*6a54128fSAndroid Build Coastguard Worker ret = valloc(size);
141*6a54128fSAndroid Build Coastguard Worker #endif /* HAVE_VALLOC */
142*6a54128fSAndroid Build Coastguard Worker #endif /* HAVE_MEMALIGN */
143*6a54128fSAndroid Build Coastguard Worker #endif /* HAVE_POSIX_MEMALIGN */
144*6a54128fSAndroid Build Coastguard Worker
145*6a54128fSAndroid Build Coastguard Worker if (!ret)
146*6a54128fSAndroid Build Coastguard Worker ret = malloc(size);
147*6a54128fSAndroid Build Coastguard Worker
148*6a54128fSAndroid Build Coastguard Worker return ret;
149*6a54128fSAndroid Build Coastguard Worker }
150*6a54128fSAndroid Build Coastguard Worker
151*6a54128fSAndroid Build Coastguard Worker /*
152*6a54128fSAndroid Build Coastguard Worker * This routine reports a new bad block. If the bad block has already
153*6a54128fSAndroid Build Coastguard Worker * been seen before, then it returns 0; otherwise it returns 1.
154*6a54128fSAndroid Build Coastguard Worker */
bb_output(blk_t bad,enum error_types error_type)155*6a54128fSAndroid Build Coastguard Worker static int bb_output (blk_t bad, enum error_types error_type)
156*6a54128fSAndroid Build Coastguard Worker {
157*6a54128fSAndroid Build Coastguard Worker errcode_t errcode;
158*6a54128fSAndroid Build Coastguard Worker
159*6a54128fSAndroid Build Coastguard Worker if (ext2fs_badblocks_list_test(bb_list, bad))
160*6a54128fSAndroid Build Coastguard Worker return 0;
161*6a54128fSAndroid Build Coastguard Worker
162*6a54128fSAndroid Build Coastguard Worker fprintf(out, "%lu\n", (unsigned long) bad);
163*6a54128fSAndroid Build Coastguard Worker fflush(out);
164*6a54128fSAndroid Build Coastguard Worker
165*6a54128fSAndroid Build Coastguard Worker errcode = ext2fs_badblocks_list_add (bb_list, bad);
166*6a54128fSAndroid Build Coastguard Worker if (errcode) {
167*6a54128fSAndroid Build Coastguard Worker com_err (program_name, errcode, "adding to in-memory bad block list");
168*6a54128fSAndroid Build Coastguard Worker exit (1);
169*6a54128fSAndroid Build Coastguard Worker }
170*6a54128fSAndroid Build Coastguard Worker
171*6a54128fSAndroid Build Coastguard Worker /* kludge:
172*6a54128fSAndroid Build Coastguard Worker increment the iteration through the bb_list if
173*6a54128fSAndroid Build Coastguard Worker an element was just added before the current iteration
174*6a54128fSAndroid Build Coastguard Worker position. This should not cause next_bad to change. */
175*6a54128fSAndroid Build Coastguard Worker if (bb_iter && bad < next_bad)
176*6a54128fSAndroid Build Coastguard Worker ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
177*6a54128fSAndroid Build Coastguard Worker
178*6a54128fSAndroid Build Coastguard Worker if (error_type == READ_ERROR) {
179*6a54128fSAndroid Build Coastguard Worker num_read_errors++;
180*6a54128fSAndroid Build Coastguard Worker } else if (error_type == WRITE_ERROR) {
181*6a54128fSAndroid Build Coastguard Worker num_write_errors++;
182*6a54128fSAndroid Build Coastguard Worker } else if (error_type == CORRUPTION_ERROR) {
183*6a54128fSAndroid Build Coastguard Worker num_corruption_errors++;
184*6a54128fSAndroid Build Coastguard Worker }
185*6a54128fSAndroid Build Coastguard Worker return 1;
186*6a54128fSAndroid Build Coastguard Worker }
187*6a54128fSAndroid Build Coastguard Worker
time_diff_format(struct timeval * tv1,struct timeval * tv2,char * buf)188*6a54128fSAndroid Build Coastguard Worker static char *time_diff_format(struct timeval *tv1,
189*6a54128fSAndroid Build Coastguard Worker struct timeval *tv2, char *buf)
190*6a54128fSAndroid Build Coastguard Worker {
191*6a54128fSAndroid Build Coastguard Worker time_t diff = (tv1->tv_sec - tv2->tv_sec);
192*6a54128fSAndroid Build Coastguard Worker int hr,min,sec;
193*6a54128fSAndroid Build Coastguard Worker
194*6a54128fSAndroid Build Coastguard Worker sec = diff % 60;
195*6a54128fSAndroid Build Coastguard Worker diff /= 60;
196*6a54128fSAndroid Build Coastguard Worker min = diff % 60;
197*6a54128fSAndroid Build Coastguard Worker hr = diff / 60;
198*6a54128fSAndroid Build Coastguard Worker
199*6a54128fSAndroid Build Coastguard Worker if (hr)
200*6a54128fSAndroid Build Coastguard Worker sprintf(buf, "%d:%02d:%02d", hr, min, sec);
201*6a54128fSAndroid Build Coastguard Worker else
202*6a54128fSAndroid Build Coastguard Worker sprintf(buf, "%d:%02d", min, sec);
203*6a54128fSAndroid Build Coastguard Worker return buf;
204*6a54128fSAndroid Build Coastguard Worker }
205*6a54128fSAndroid Build Coastguard Worker
calc_percent(unsigned long current,unsigned long total)206*6a54128fSAndroid Build Coastguard Worker static float calc_percent(unsigned long current, unsigned long total) {
207*6a54128fSAndroid Build Coastguard Worker float percent = 0.0;
208*6a54128fSAndroid Build Coastguard Worker if (total <= 0)
209*6a54128fSAndroid Build Coastguard Worker return percent;
210*6a54128fSAndroid Build Coastguard Worker if (current >= total) {
211*6a54128fSAndroid Build Coastguard Worker percent = 100.0;
212*6a54128fSAndroid Build Coastguard Worker } else {
213*6a54128fSAndroid Build Coastguard Worker percent=(100.0*(float)current/(float)total);
214*6a54128fSAndroid Build Coastguard Worker }
215*6a54128fSAndroid Build Coastguard Worker return percent;
216*6a54128fSAndroid Build Coastguard Worker }
217*6a54128fSAndroid Build Coastguard Worker
print_status(void)218*6a54128fSAndroid Build Coastguard Worker static void print_status(void)
219*6a54128fSAndroid Build Coastguard Worker {
220*6a54128fSAndroid Build Coastguard Worker struct timeval time_end;
221*6a54128fSAndroid Build Coastguard Worker char diff_buf[32], line_buf[128];
222*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_MBSTOWCS
223*6a54128fSAndroid Build Coastguard Worker wchar_t wline_buf[128];
224*6a54128fSAndroid Build Coastguard Worker #endif
225*6a54128fSAndroid Build Coastguard Worker int len;
226*6a54128fSAndroid Build Coastguard Worker
227*6a54128fSAndroid Build Coastguard Worker gettimeofday(&time_end, 0);
228*6a54128fSAndroid Build Coastguard Worker len = snprintf(line_buf, sizeof(line_buf),
229*6a54128fSAndroid Build Coastguard Worker _("%6.2f%% done, %s elapsed. "
230*6a54128fSAndroid Build Coastguard Worker "(%d/%d/%d errors)"),
231*6a54128fSAndroid Build Coastguard Worker calc_percent((unsigned long) currently_testing,
232*6a54128fSAndroid Build Coastguard Worker (unsigned long) num_blocks),
233*6a54128fSAndroid Build Coastguard Worker time_diff_format(&time_end, &time_start, diff_buf),
234*6a54128fSAndroid Build Coastguard Worker num_read_errors,
235*6a54128fSAndroid Build Coastguard Worker num_write_errors,
236*6a54128fSAndroid Build Coastguard Worker num_corruption_errors);
237*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_MBSTOWCS
238*6a54128fSAndroid Build Coastguard Worker mbstowcs(wline_buf, line_buf, sizeof(line_buf));
239*6a54128fSAndroid Build Coastguard Worker len = wcswidth(wline_buf, sizeof(line_buf));
240*6a54128fSAndroid Build Coastguard Worker if (len < 0)
241*6a54128fSAndroid Build Coastguard Worker len = strlen(line_buf); /* Should never happen... */
242*6a54128fSAndroid Build Coastguard Worker #endif
243*6a54128fSAndroid Build Coastguard Worker fputs(line_buf, stderr);
244*6a54128fSAndroid Build Coastguard Worker memset(line_buf, '\b', len);
245*6a54128fSAndroid Build Coastguard Worker line_buf[len] = 0;
246*6a54128fSAndroid Build Coastguard Worker fputs(line_buf, stderr);
247*6a54128fSAndroid Build Coastguard Worker fflush (stderr);
248*6a54128fSAndroid Build Coastguard Worker }
249*6a54128fSAndroid Build Coastguard Worker
alarm_intr(int alnum EXT2FS_ATTR ((unused)))250*6a54128fSAndroid Build Coastguard Worker static void alarm_intr(int alnum EXT2FS_ATTR((unused)))
251*6a54128fSAndroid Build Coastguard Worker {
252*6a54128fSAndroid Build Coastguard Worker signal (SIGALRM, alarm_intr);
253*6a54128fSAndroid Build Coastguard Worker alarm(1);
254*6a54128fSAndroid Build Coastguard Worker if (!num_blocks)
255*6a54128fSAndroid Build Coastguard Worker return;
256*6a54128fSAndroid Build Coastguard Worker print_status();
257*6a54128fSAndroid Build Coastguard Worker }
258*6a54128fSAndroid Build Coastguard Worker
259*6a54128fSAndroid Build Coastguard Worker static void *terminate_addr = NULL;
260*6a54128fSAndroid Build Coastguard Worker
terminate_intr(int signo EXT2FS_ATTR ((unused)))261*6a54128fSAndroid Build Coastguard Worker static void terminate_intr(int signo EXT2FS_ATTR((unused)))
262*6a54128fSAndroid Build Coastguard Worker {
263*6a54128fSAndroid Build Coastguard Worker fflush(out);
264*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, "\n\nInterrupted at block %llu\n",
265*6a54128fSAndroid Build Coastguard Worker (unsigned long long) currently_testing);
266*6a54128fSAndroid Build Coastguard Worker fflush(stderr);
267*6a54128fSAndroid Build Coastguard Worker if (terminate_addr)
268*6a54128fSAndroid Build Coastguard Worker longjmp(terminate_addr,1);
269*6a54128fSAndroid Build Coastguard Worker exit(1);
270*6a54128fSAndroid Build Coastguard Worker }
271*6a54128fSAndroid Build Coastguard Worker
capture_terminate(jmp_buf term_addr)272*6a54128fSAndroid Build Coastguard Worker static void capture_terminate(jmp_buf term_addr)
273*6a54128fSAndroid Build Coastguard Worker {
274*6a54128fSAndroid Build Coastguard Worker terminate_addr = term_addr;
275*6a54128fSAndroid Build Coastguard Worker signal (SIGHUP, terminate_intr);
276*6a54128fSAndroid Build Coastguard Worker signal (SIGINT, terminate_intr);
277*6a54128fSAndroid Build Coastguard Worker signal (SIGPIPE, terminate_intr);
278*6a54128fSAndroid Build Coastguard Worker signal (SIGTERM, terminate_intr);
279*6a54128fSAndroid Build Coastguard Worker signal (SIGUSR1, terminate_intr);
280*6a54128fSAndroid Build Coastguard Worker signal (SIGUSR2, terminate_intr);
281*6a54128fSAndroid Build Coastguard Worker }
282*6a54128fSAndroid Build Coastguard Worker
uncapture_terminate(void)283*6a54128fSAndroid Build Coastguard Worker static void uncapture_terminate(void)
284*6a54128fSAndroid Build Coastguard Worker {
285*6a54128fSAndroid Build Coastguard Worker terminate_addr = NULL;
286*6a54128fSAndroid Build Coastguard Worker signal (SIGHUP, SIG_DFL);
287*6a54128fSAndroid Build Coastguard Worker signal (SIGINT, SIG_DFL);
288*6a54128fSAndroid Build Coastguard Worker signal (SIGPIPE, SIG_DFL);
289*6a54128fSAndroid Build Coastguard Worker signal (SIGTERM, SIG_DFL);
290*6a54128fSAndroid Build Coastguard Worker signal (SIGUSR1, SIG_DFL);
291*6a54128fSAndroid Build Coastguard Worker signal (SIGUSR2, SIG_DFL);
292*6a54128fSAndroid Build Coastguard Worker }
293*6a54128fSAndroid Build Coastguard Worker
294*6a54128fSAndroid Build Coastguard Worker /* Linux requires that O_DIRECT I/Os be 512-byte sector aligned */
295*6a54128fSAndroid Build Coastguard Worker
296*6a54128fSAndroid Build Coastguard Worker #define O_DIRECT_SIZE 512
297*6a54128fSAndroid Build Coastguard Worker
set_o_direct(int dev,unsigned char * buffer,size_t size,ext2_loff_t offset)298*6a54128fSAndroid Build Coastguard Worker static void set_o_direct(int dev, unsigned char *buffer, size_t size,
299*6a54128fSAndroid Build Coastguard Worker ext2_loff_t offset)
300*6a54128fSAndroid Build Coastguard Worker {
301*6a54128fSAndroid Build Coastguard Worker #ifdef O_DIRECT
302*6a54128fSAndroid Build Coastguard Worker static int current_O_DIRECT; /* Current status of O_DIRECT flag */
303*6a54128fSAndroid Build Coastguard Worker int new_flag = O_DIRECT;
304*6a54128fSAndroid Build Coastguard Worker int flag;
305*6a54128fSAndroid Build Coastguard Worker
306*6a54128fSAndroid Build Coastguard Worker if ((use_buffered_io != 0) ||
307*6a54128fSAndroid Build Coastguard Worker (((unsigned long) buffer & (sys_page_size - 1)) != 0) ||
308*6a54128fSAndroid Build Coastguard Worker ((size & (sys_page_size - 1)) != 0) ||
309*6a54128fSAndroid Build Coastguard Worker ((offset & (O_DIRECT_SIZE - 1)) != 0))
310*6a54128fSAndroid Build Coastguard Worker new_flag = 0;
311*6a54128fSAndroid Build Coastguard Worker
312*6a54128fSAndroid Build Coastguard Worker if (new_flag != current_O_DIRECT) {
313*6a54128fSAndroid Build Coastguard Worker /* printf("%s O_DIRECT\n", new_flag ? "Setting" : "Clearing"); */
314*6a54128fSAndroid Build Coastguard Worker flag = fcntl(dev, F_GETFL);
315*6a54128fSAndroid Build Coastguard Worker if (flag > 0) {
316*6a54128fSAndroid Build Coastguard Worker flag = (flag & ~O_DIRECT) | new_flag;
317*6a54128fSAndroid Build Coastguard Worker if (fcntl(dev, F_SETFL, flag) < 0)
318*6a54128fSAndroid Build Coastguard Worker perror("set_o_direct");
319*6a54128fSAndroid Build Coastguard Worker }
320*6a54128fSAndroid Build Coastguard Worker current_O_DIRECT = new_flag;
321*6a54128fSAndroid Build Coastguard Worker }
322*6a54128fSAndroid Build Coastguard Worker #endif
323*6a54128fSAndroid Build Coastguard Worker }
324*6a54128fSAndroid Build Coastguard Worker
325*6a54128fSAndroid Build Coastguard Worker
pattern_fill(unsigned char * buffer,unsigned int pattern,size_t n)326*6a54128fSAndroid Build Coastguard Worker static void pattern_fill(unsigned char *buffer, unsigned int pattern,
327*6a54128fSAndroid Build Coastguard Worker size_t n)
328*6a54128fSAndroid Build Coastguard Worker {
329*6a54128fSAndroid Build Coastguard Worker unsigned int i, nb;
330*6a54128fSAndroid Build Coastguard Worker unsigned char bpattern[sizeof(pattern)], *ptr;
331*6a54128fSAndroid Build Coastguard Worker
332*6a54128fSAndroid Build Coastguard Worker if (pattern == (unsigned int) ~0) {
333*6a54128fSAndroid Build Coastguard Worker for (ptr = buffer; ptr < buffer + n; ptr++) {
334*6a54128fSAndroid Build Coastguard Worker (*ptr) = random() % (1 << (8 * sizeof(char)));
335*6a54128fSAndroid Build Coastguard Worker }
336*6a54128fSAndroid Build Coastguard Worker if (s_flag | v_flag)
337*6a54128fSAndroid Build Coastguard Worker fputs(_("Testing with random pattern: "), stderr);
338*6a54128fSAndroid Build Coastguard Worker } else {
339*6a54128fSAndroid Build Coastguard Worker bpattern[0] = 0;
340*6a54128fSAndroid Build Coastguard Worker for (i = 0; i < sizeof(bpattern); i++) {
341*6a54128fSAndroid Build Coastguard Worker if (pattern == 0)
342*6a54128fSAndroid Build Coastguard Worker break;
343*6a54128fSAndroid Build Coastguard Worker bpattern[i] = pattern & 0xFF;
344*6a54128fSAndroid Build Coastguard Worker pattern = pattern >> 8;
345*6a54128fSAndroid Build Coastguard Worker }
346*6a54128fSAndroid Build Coastguard Worker nb = i ? (i-1) : 0;
347*6a54128fSAndroid Build Coastguard Worker for (ptr = buffer, i = nb; ptr < buffer + n; ptr++) {
348*6a54128fSAndroid Build Coastguard Worker *ptr = bpattern[i];
349*6a54128fSAndroid Build Coastguard Worker if (i == 0)
350*6a54128fSAndroid Build Coastguard Worker i = nb;
351*6a54128fSAndroid Build Coastguard Worker else
352*6a54128fSAndroid Build Coastguard Worker i--;
353*6a54128fSAndroid Build Coastguard Worker }
354*6a54128fSAndroid Build Coastguard Worker if (s_flag | v_flag) {
355*6a54128fSAndroid Build Coastguard Worker fputs(_("Testing with pattern 0x"), stderr);
356*6a54128fSAndroid Build Coastguard Worker for (i = 0; i <= nb; i++)
357*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, "%02x", buffer[i]);
358*6a54128fSAndroid Build Coastguard Worker fputs(": ", stderr);
359*6a54128fSAndroid Build Coastguard Worker }
360*6a54128fSAndroid Build Coastguard Worker }
361*6a54128fSAndroid Build Coastguard Worker }
362*6a54128fSAndroid Build Coastguard Worker
363*6a54128fSAndroid Build Coastguard Worker /*
364*6a54128fSAndroid Build Coastguard Worker * Perform a read of a sequence of blocks; return the number of blocks
365*6a54128fSAndroid Build Coastguard Worker * successfully sequentially read.
366*6a54128fSAndroid Build Coastguard Worker */
do_read(int dev,unsigned char * buffer,int try,int block_size,blk_t current_block)367*6a54128fSAndroid Build Coastguard Worker static int do_read (int dev, unsigned char * buffer, int try, int block_size,
368*6a54128fSAndroid Build Coastguard Worker blk_t current_block)
369*6a54128fSAndroid Build Coastguard Worker {
370*6a54128fSAndroid Build Coastguard Worker long got;
371*6a54128fSAndroid Build Coastguard Worker struct timeval tv1, tv2;
372*6a54128fSAndroid Build Coastguard Worker #define NANOSEC (1000000000L)
373*6a54128fSAndroid Build Coastguard Worker #define MILISEC (1000L)
374*6a54128fSAndroid Build Coastguard Worker
375*6a54128fSAndroid Build Coastguard Worker #if 0
376*6a54128fSAndroid Build Coastguard Worker printf("do_read: block %d, try %d\n", current_block, try);
377*6a54128fSAndroid Build Coastguard Worker #endif
378*6a54128fSAndroid Build Coastguard Worker set_o_direct(dev, buffer, try * block_size,
379*6a54128fSAndroid Build Coastguard Worker ((ext2_loff_t) current_block) * block_size);
380*6a54128fSAndroid Build Coastguard Worker
381*6a54128fSAndroid Build Coastguard Worker if (v_flag > 1)
382*6a54128fSAndroid Build Coastguard Worker print_status();
383*6a54128fSAndroid Build Coastguard Worker
384*6a54128fSAndroid Build Coastguard Worker /* Seek to the correct loc. */
385*6a54128fSAndroid Build Coastguard Worker if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
386*6a54128fSAndroid Build Coastguard Worker SEEK_SET) != (ext2_loff_t) current_block * block_size)
387*6a54128fSAndroid Build Coastguard Worker com_err (program_name, errno, "%s", _("during seek"));
388*6a54128fSAndroid Build Coastguard Worker
389*6a54128fSAndroid Build Coastguard Worker /* Try the read */
390*6a54128fSAndroid Build Coastguard Worker if (d_flag)
391*6a54128fSAndroid Build Coastguard Worker gettimeofday(&tv1, NULL);
392*6a54128fSAndroid Build Coastguard Worker got = read (dev, buffer, (size_t) try * block_size);
393*6a54128fSAndroid Build Coastguard Worker if (d_flag)
394*6a54128fSAndroid Build Coastguard Worker gettimeofday(&tv2, NULL);
395*6a54128fSAndroid Build Coastguard Worker if (got < 0)
396*6a54128fSAndroid Build Coastguard Worker got = 0;
397*6a54128fSAndroid Build Coastguard Worker if (got & 511)
398*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, _("Weird value (%ld) in do_read\n"), got);
399*6a54128fSAndroid Build Coastguard Worker got /= block_size;
400*6a54128fSAndroid Build Coastguard Worker if (d_flag && got == try) {
401*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_NANOSLEEP
402*6a54128fSAndroid Build Coastguard Worker struct timespec ts;
403*6a54128fSAndroid Build Coastguard Worker ts.tv_sec = tv2.tv_sec - tv1.tv_sec;
404*6a54128fSAndroid Build Coastguard Worker ts.tv_nsec = (tv2.tv_usec - tv1.tv_usec) * MILISEC;
405*6a54128fSAndroid Build Coastguard Worker if (ts.tv_nsec < 0) {
406*6a54128fSAndroid Build Coastguard Worker ts.tv_nsec += NANOSEC;
407*6a54128fSAndroid Build Coastguard Worker ts.tv_sec -= 1;
408*6a54128fSAndroid Build Coastguard Worker }
409*6a54128fSAndroid Build Coastguard Worker /* increase/decrease the sleep time based on d_flag value */
410*6a54128fSAndroid Build Coastguard Worker ts.tv_sec = ts.tv_sec * d_flag / 100;
411*6a54128fSAndroid Build Coastguard Worker ts.tv_nsec = ts.tv_nsec * d_flag / 100;
412*6a54128fSAndroid Build Coastguard Worker if (ts.tv_nsec > NANOSEC) {
413*6a54128fSAndroid Build Coastguard Worker ts.tv_sec += ts.tv_nsec / NANOSEC;
414*6a54128fSAndroid Build Coastguard Worker ts.tv_nsec %= NANOSEC;
415*6a54128fSAndroid Build Coastguard Worker }
416*6a54128fSAndroid Build Coastguard Worker if (ts.tv_sec || ts.tv_nsec)
417*6a54128fSAndroid Build Coastguard Worker nanosleep(&ts, NULL);
418*6a54128fSAndroid Build Coastguard Worker #else
419*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_USLEEP
420*6a54128fSAndroid Build Coastguard Worker struct timeval tv;
421*6a54128fSAndroid Build Coastguard Worker tv.tv_sec = tv2.tv_sec - tv1.tv_sec;
422*6a54128fSAndroid Build Coastguard Worker tv.tv_usec = tv2.tv_usec - tv1.tv_usec;
423*6a54128fSAndroid Build Coastguard Worker tv.tv_sec = tv.tv_sec * d_flag / 100;
424*6a54128fSAndroid Build Coastguard Worker tv.tv_usec = tv.tv_usec * d_flag / 100;
425*6a54128fSAndroid Build Coastguard Worker if (tv.tv_usec > 1000000) {
426*6a54128fSAndroid Build Coastguard Worker tv.tv_sec += tv.tv_usec / 1000000;
427*6a54128fSAndroid Build Coastguard Worker tv.tv_usec %= 1000000;
428*6a54128fSAndroid Build Coastguard Worker }
429*6a54128fSAndroid Build Coastguard Worker if (tv.tv_sec)
430*6a54128fSAndroid Build Coastguard Worker sleep(tv.tv_sec);
431*6a54128fSAndroid Build Coastguard Worker if (tv.tv_usec)
432*6a54128fSAndroid Build Coastguard Worker usleep(tv.tv_usec);
433*6a54128fSAndroid Build Coastguard Worker #endif
434*6a54128fSAndroid Build Coastguard Worker #endif
435*6a54128fSAndroid Build Coastguard Worker }
436*6a54128fSAndroid Build Coastguard Worker return got;
437*6a54128fSAndroid Build Coastguard Worker }
438*6a54128fSAndroid Build Coastguard Worker
439*6a54128fSAndroid Build Coastguard Worker /*
440*6a54128fSAndroid Build Coastguard Worker * Perform a write of a sequence of blocks; return the number of blocks
441*6a54128fSAndroid Build Coastguard Worker * successfully sequentially written.
442*6a54128fSAndroid Build Coastguard Worker */
do_write(int dev,unsigned char * buffer,int try,int block_size,unsigned long current_block)443*6a54128fSAndroid Build Coastguard Worker static int do_write(int dev, unsigned char * buffer, int try, int block_size,
444*6a54128fSAndroid Build Coastguard Worker unsigned long current_block)
445*6a54128fSAndroid Build Coastguard Worker {
446*6a54128fSAndroid Build Coastguard Worker long got;
447*6a54128fSAndroid Build Coastguard Worker
448*6a54128fSAndroid Build Coastguard Worker #if 0
449*6a54128fSAndroid Build Coastguard Worker printf("do_write: block %lu, try %d\n", current_block, try);
450*6a54128fSAndroid Build Coastguard Worker #endif
451*6a54128fSAndroid Build Coastguard Worker set_o_direct(dev, buffer, try * block_size,
452*6a54128fSAndroid Build Coastguard Worker ((ext2_loff_t) current_block) * block_size);
453*6a54128fSAndroid Build Coastguard Worker
454*6a54128fSAndroid Build Coastguard Worker if (v_flag > 1)
455*6a54128fSAndroid Build Coastguard Worker print_status();
456*6a54128fSAndroid Build Coastguard Worker
457*6a54128fSAndroid Build Coastguard Worker /* Seek to the correct loc. */
458*6a54128fSAndroid Build Coastguard Worker if (ext2fs_llseek (dev, (ext2_loff_t) current_block * block_size,
459*6a54128fSAndroid Build Coastguard Worker SEEK_SET) != (ext2_loff_t) current_block * block_size)
460*6a54128fSAndroid Build Coastguard Worker com_err (program_name, errno, "%s", _("during seek"));
461*6a54128fSAndroid Build Coastguard Worker
462*6a54128fSAndroid Build Coastguard Worker /* Try the write */
463*6a54128fSAndroid Build Coastguard Worker got = write (dev, buffer, (size_t) try * block_size);
464*6a54128fSAndroid Build Coastguard Worker if (got < 0)
465*6a54128fSAndroid Build Coastguard Worker got = 0;
466*6a54128fSAndroid Build Coastguard Worker if (got & 511)
467*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, "Weird value (%ld) in do_write\n", got);
468*6a54128fSAndroid Build Coastguard Worker got /= block_size;
469*6a54128fSAndroid Build Coastguard Worker return got;
470*6a54128fSAndroid Build Coastguard Worker }
471*6a54128fSAndroid Build Coastguard Worker
472*6a54128fSAndroid Build Coastguard Worker static int host_dev;
473*6a54128fSAndroid Build Coastguard Worker
flush_bufs(void)474*6a54128fSAndroid Build Coastguard Worker static void flush_bufs(void)
475*6a54128fSAndroid Build Coastguard Worker {
476*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
477*6a54128fSAndroid Build Coastguard Worker
478*6a54128fSAndroid Build Coastguard Worker #ifdef O_DIRECT
479*6a54128fSAndroid Build Coastguard Worker if (!use_buffered_io)
480*6a54128fSAndroid Build Coastguard Worker return;
481*6a54128fSAndroid Build Coastguard Worker #endif
482*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_sync_device(host_dev, 1);
483*6a54128fSAndroid Build Coastguard Worker if (retval)
484*6a54128fSAndroid Build Coastguard Worker com_err(program_name, retval, "%s",
485*6a54128fSAndroid Build Coastguard Worker _("during ext2fs_sync_device"));
486*6a54128fSAndroid Build Coastguard Worker }
487*6a54128fSAndroid Build Coastguard Worker
test_ro(int dev,blk_t last_block,int block_size,blk_t first_block,unsigned int blocks_at_once)488*6a54128fSAndroid Build Coastguard Worker static unsigned int test_ro (int dev, blk_t last_block,
489*6a54128fSAndroid Build Coastguard Worker int block_size, blk_t first_block,
490*6a54128fSAndroid Build Coastguard Worker unsigned int blocks_at_once)
491*6a54128fSAndroid Build Coastguard Worker {
492*6a54128fSAndroid Build Coastguard Worker unsigned char * blkbuf;
493*6a54128fSAndroid Build Coastguard Worker int try;
494*6a54128fSAndroid Build Coastguard Worker int got;
495*6a54128fSAndroid Build Coastguard Worker unsigned int bb_count = 0;
496*6a54128fSAndroid Build Coastguard Worker errcode_t errcode;
497*6a54128fSAndroid Build Coastguard Worker blk_t recover_block = ~0;
498*6a54128fSAndroid Build Coastguard Worker
499*6a54128fSAndroid Build Coastguard Worker /* set up abend handler */
500*6a54128fSAndroid Build Coastguard Worker capture_terminate(NULL);
501*6a54128fSAndroid Build Coastguard Worker
502*6a54128fSAndroid Build Coastguard Worker errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
503*6a54128fSAndroid Build Coastguard Worker if (errcode) {
504*6a54128fSAndroid Build Coastguard Worker com_err(program_name, errcode, "%s",
505*6a54128fSAndroid Build Coastguard Worker _("while beginning bad block list iteration"));
506*6a54128fSAndroid Build Coastguard Worker exit (1);
507*6a54128fSAndroid Build Coastguard Worker }
508*6a54128fSAndroid Build Coastguard Worker do {
509*6a54128fSAndroid Build Coastguard Worker ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
510*6a54128fSAndroid Build Coastguard Worker } while (next_bad && next_bad < first_block);
511*6a54128fSAndroid Build Coastguard Worker
512*6a54128fSAndroid Build Coastguard Worker if (t_flag) {
513*6a54128fSAndroid Build Coastguard Worker blkbuf = allocate_buffer(((size_t) blocks_at_once + 1) * block_size);
514*6a54128fSAndroid Build Coastguard Worker } else {
515*6a54128fSAndroid Build Coastguard Worker blkbuf = allocate_buffer((size_t) blocks_at_once * block_size);
516*6a54128fSAndroid Build Coastguard Worker }
517*6a54128fSAndroid Build Coastguard Worker if (!blkbuf)
518*6a54128fSAndroid Build Coastguard Worker {
519*6a54128fSAndroid Build Coastguard Worker com_err(program_name, ENOMEM, "%s",
520*6a54128fSAndroid Build Coastguard Worker _("while allocating buffers"));
521*6a54128fSAndroid Build Coastguard Worker exit (1);
522*6a54128fSAndroid Build Coastguard Worker }
523*6a54128fSAndroid Build Coastguard Worker if (v_flag) {
524*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, _("Checking blocks %lu to %lu\n"),
525*6a54128fSAndroid Build Coastguard Worker (unsigned long)first_block,
526*6a54128fSAndroid Build Coastguard Worker (unsigned long)last_block - 1);
527*6a54128fSAndroid Build Coastguard Worker }
528*6a54128fSAndroid Build Coastguard Worker if (t_flag) {
529*6a54128fSAndroid Build Coastguard Worker fputs(_("Checking for bad blocks in read-only mode\n"), stderr);
530*6a54128fSAndroid Build Coastguard Worker pattern_fill(blkbuf + blocks_at_once * block_size,
531*6a54128fSAndroid Build Coastguard Worker t_patts[0], block_size);
532*6a54128fSAndroid Build Coastguard Worker }
533*6a54128fSAndroid Build Coastguard Worker flush_bufs();
534*6a54128fSAndroid Build Coastguard Worker try = blocks_at_once;
535*6a54128fSAndroid Build Coastguard Worker currently_testing = first_block;
536*6a54128fSAndroid Build Coastguard Worker num_blocks = last_block - 1;
537*6a54128fSAndroid Build Coastguard Worker if (!t_flag && (s_flag || v_flag))
538*6a54128fSAndroid Build Coastguard Worker fputs(_("Checking for bad blocks (read-only test): "), stderr);
539*6a54128fSAndroid Build Coastguard Worker if (s_flag && v_flag <= 1)
540*6a54128fSAndroid Build Coastguard Worker alarm_intr(SIGALRM);
541*6a54128fSAndroid Build Coastguard Worker while (currently_testing < last_block)
542*6a54128fSAndroid Build Coastguard Worker {
543*6a54128fSAndroid Build Coastguard Worker if (bb_count >= max_bb) {
544*6a54128fSAndroid Build Coastguard Worker if (s_flag || v_flag) {
545*6a54128fSAndroid Build Coastguard Worker fputs(_("Too many bad blocks, aborting test\n"), stderr);
546*6a54128fSAndroid Build Coastguard Worker }
547*6a54128fSAndroid Build Coastguard Worker break;
548*6a54128fSAndroid Build Coastguard Worker }
549*6a54128fSAndroid Build Coastguard Worker if (next_bad) {
550*6a54128fSAndroid Build Coastguard Worker if (currently_testing == next_bad) {
551*6a54128fSAndroid Build Coastguard Worker /* fprintf (out, "%lu\n", nextbad); */
552*6a54128fSAndroid Build Coastguard Worker ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
553*6a54128fSAndroid Build Coastguard Worker currently_testing++;
554*6a54128fSAndroid Build Coastguard Worker continue;
555*6a54128fSAndroid Build Coastguard Worker }
556*6a54128fSAndroid Build Coastguard Worker else if (currently_testing + try > next_bad)
557*6a54128fSAndroid Build Coastguard Worker try = next_bad - currently_testing;
558*6a54128fSAndroid Build Coastguard Worker }
559*6a54128fSAndroid Build Coastguard Worker if (currently_testing + try > last_block)
560*6a54128fSAndroid Build Coastguard Worker try = last_block - currently_testing;
561*6a54128fSAndroid Build Coastguard Worker got = do_read (dev, blkbuf, try, block_size, currently_testing);
562*6a54128fSAndroid Build Coastguard Worker if (t_flag) {
563*6a54128fSAndroid Build Coastguard Worker /* test the comparison between all the
564*6a54128fSAndroid Build Coastguard Worker blocks successfully read */
565*6a54128fSAndroid Build Coastguard Worker int i;
566*6a54128fSAndroid Build Coastguard Worker for (i = 0; i < got; ++i)
567*6a54128fSAndroid Build Coastguard Worker if (memcmp (blkbuf+i*block_size,
568*6a54128fSAndroid Build Coastguard Worker blkbuf+blocks_at_once*block_size,
569*6a54128fSAndroid Build Coastguard Worker block_size))
570*6a54128fSAndroid Build Coastguard Worker bb_count += bb_output(currently_testing + i, CORRUPTION_ERROR);
571*6a54128fSAndroid Build Coastguard Worker }
572*6a54128fSAndroid Build Coastguard Worker if (got == 0 && try == 1)
573*6a54128fSAndroid Build Coastguard Worker bb_count += bb_output(currently_testing++, READ_ERROR);
574*6a54128fSAndroid Build Coastguard Worker currently_testing += got;
575*6a54128fSAndroid Build Coastguard Worker if (got != try) {
576*6a54128fSAndroid Build Coastguard Worker try = 1;
577*6a54128fSAndroid Build Coastguard Worker if (recover_block == ~0U)
578*6a54128fSAndroid Build Coastguard Worker recover_block = currently_testing - got +
579*6a54128fSAndroid Build Coastguard Worker blocks_at_once;
580*6a54128fSAndroid Build Coastguard Worker continue;
581*6a54128fSAndroid Build Coastguard Worker } else if (currently_testing == recover_block) {
582*6a54128fSAndroid Build Coastguard Worker try = blocks_at_once;
583*6a54128fSAndroid Build Coastguard Worker recover_block = ~0;
584*6a54128fSAndroid Build Coastguard Worker }
585*6a54128fSAndroid Build Coastguard Worker }
586*6a54128fSAndroid Build Coastguard Worker num_blocks = 0;
587*6a54128fSAndroid Build Coastguard Worker alarm(0);
588*6a54128fSAndroid Build Coastguard Worker if (s_flag || v_flag)
589*6a54128fSAndroid Build Coastguard Worker fputs(_(done_string), stderr);
590*6a54128fSAndroid Build Coastguard Worker
591*6a54128fSAndroid Build Coastguard Worker fflush (stderr);
592*6a54128fSAndroid Build Coastguard Worker free (blkbuf);
593*6a54128fSAndroid Build Coastguard Worker
594*6a54128fSAndroid Build Coastguard Worker ext2fs_badblocks_list_iterate_end(bb_iter);
595*6a54128fSAndroid Build Coastguard Worker
596*6a54128fSAndroid Build Coastguard Worker uncapture_terminate();
597*6a54128fSAndroid Build Coastguard Worker
598*6a54128fSAndroid Build Coastguard Worker return bb_count;
599*6a54128fSAndroid Build Coastguard Worker }
600*6a54128fSAndroid Build Coastguard Worker
test_rw(int dev,blk_t last_block,int block_size,blk_t first_block,unsigned int blocks_at_once)601*6a54128fSAndroid Build Coastguard Worker static unsigned int test_rw (int dev, blk_t last_block,
602*6a54128fSAndroid Build Coastguard Worker int block_size, blk_t first_block,
603*6a54128fSAndroid Build Coastguard Worker unsigned int blocks_at_once)
604*6a54128fSAndroid Build Coastguard Worker {
605*6a54128fSAndroid Build Coastguard Worker unsigned char *buffer, *read_buffer;
606*6a54128fSAndroid Build Coastguard Worker const unsigned int patterns[] = {0xaa, 0x55, 0xff, 0x00};
607*6a54128fSAndroid Build Coastguard Worker const unsigned int *pattern;
608*6a54128fSAndroid Build Coastguard Worker int i, try, got, nr_pattern, pat_idx;
609*6a54128fSAndroid Build Coastguard Worker unsigned int bb_count = 0;
610*6a54128fSAndroid Build Coastguard Worker blk_t recover_block = ~0;
611*6a54128fSAndroid Build Coastguard Worker
612*6a54128fSAndroid Build Coastguard Worker /* set up abend handler */
613*6a54128fSAndroid Build Coastguard Worker capture_terminate(NULL);
614*6a54128fSAndroid Build Coastguard Worker
615*6a54128fSAndroid Build Coastguard Worker buffer = allocate_buffer((size_t) 2 * blocks_at_once * block_size);
616*6a54128fSAndroid Build Coastguard Worker read_buffer = buffer + blocks_at_once * block_size;
617*6a54128fSAndroid Build Coastguard Worker
618*6a54128fSAndroid Build Coastguard Worker if (!buffer) {
619*6a54128fSAndroid Build Coastguard Worker com_err(program_name, ENOMEM, "%s",
620*6a54128fSAndroid Build Coastguard Worker _("while allocating buffers"));
621*6a54128fSAndroid Build Coastguard Worker exit (1);
622*6a54128fSAndroid Build Coastguard Worker }
623*6a54128fSAndroid Build Coastguard Worker
624*6a54128fSAndroid Build Coastguard Worker flush_bufs();
625*6a54128fSAndroid Build Coastguard Worker
626*6a54128fSAndroid Build Coastguard Worker if (v_flag) {
627*6a54128fSAndroid Build Coastguard Worker fputs(_("Checking for bad blocks in read-write mode\n"),
628*6a54128fSAndroid Build Coastguard Worker stderr);
629*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, _("From block %lu to %lu\n"),
630*6a54128fSAndroid Build Coastguard Worker (unsigned long) first_block,
631*6a54128fSAndroid Build Coastguard Worker (unsigned long) last_block - 1);
632*6a54128fSAndroid Build Coastguard Worker }
633*6a54128fSAndroid Build Coastguard Worker if (t_flag) {
634*6a54128fSAndroid Build Coastguard Worker pattern = t_patts;
635*6a54128fSAndroid Build Coastguard Worker nr_pattern = t_flag;
636*6a54128fSAndroid Build Coastguard Worker } else {
637*6a54128fSAndroid Build Coastguard Worker pattern = patterns;
638*6a54128fSAndroid Build Coastguard Worker nr_pattern = sizeof(patterns) / sizeof(patterns[0]);
639*6a54128fSAndroid Build Coastguard Worker }
640*6a54128fSAndroid Build Coastguard Worker for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) {
641*6a54128fSAndroid Build Coastguard Worker pattern_fill(buffer, pattern[pat_idx],
642*6a54128fSAndroid Build Coastguard Worker blocks_at_once * block_size);
643*6a54128fSAndroid Build Coastguard Worker num_blocks = last_block - 1;
644*6a54128fSAndroid Build Coastguard Worker currently_testing = first_block;
645*6a54128fSAndroid Build Coastguard Worker if (s_flag && v_flag <= 1)
646*6a54128fSAndroid Build Coastguard Worker alarm_intr(SIGALRM);
647*6a54128fSAndroid Build Coastguard Worker
648*6a54128fSAndroid Build Coastguard Worker try = blocks_at_once;
649*6a54128fSAndroid Build Coastguard Worker while (currently_testing < last_block) {
650*6a54128fSAndroid Build Coastguard Worker if (bb_count >= max_bb) {
651*6a54128fSAndroid Build Coastguard Worker if (s_flag || v_flag) {
652*6a54128fSAndroid Build Coastguard Worker fputs(_("Too many bad blocks, aborting test\n"), stderr);
653*6a54128fSAndroid Build Coastguard Worker }
654*6a54128fSAndroid Build Coastguard Worker break;
655*6a54128fSAndroid Build Coastguard Worker }
656*6a54128fSAndroid Build Coastguard Worker if (currently_testing + try > last_block)
657*6a54128fSAndroid Build Coastguard Worker try = last_block - currently_testing;
658*6a54128fSAndroid Build Coastguard Worker got = do_write(dev, buffer, try, block_size,
659*6a54128fSAndroid Build Coastguard Worker currently_testing);
660*6a54128fSAndroid Build Coastguard Worker if (v_flag > 1)
661*6a54128fSAndroid Build Coastguard Worker print_status();
662*6a54128fSAndroid Build Coastguard Worker
663*6a54128fSAndroid Build Coastguard Worker if (got == 0 && try == 1)
664*6a54128fSAndroid Build Coastguard Worker bb_count += bb_output(currently_testing++, WRITE_ERROR);
665*6a54128fSAndroid Build Coastguard Worker currently_testing += got;
666*6a54128fSAndroid Build Coastguard Worker if (got != try) {
667*6a54128fSAndroid Build Coastguard Worker try = 1;
668*6a54128fSAndroid Build Coastguard Worker if (recover_block == ~0U)
669*6a54128fSAndroid Build Coastguard Worker recover_block = currently_testing -
670*6a54128fSAndroid Build Coastguard Worker got + blocks_at_once;
671*6a54128fSAndroid Build Coastguard Worker continue;
672*6a54128fSAndroid Build Coastguard Worker } else if (currently_testing == recover_block) {
673*6a54128fSAndroid Build Coastguard Worker try = blocks_at_once;
674*6a54128fSAndroid Build Coastguard Worker recover_block = ~0;
675*6a54128fSAndroid Build Coastguard Worker }
676*6a54128fSAndroid Build Coastguard Worker }
677*6a54128fSAndroid Build Coastguard Worker
678*6a54128fSAndroid Build Coastguard Worker num_blocks = 0;
679*6a54128fSAndroid Build Coastguard Worker alarm (0);
680*6a54128fSAndroid Build Coastguard Worker if (s_flag | v_flag)
681*6a54128fSAndroid Build Coastguard Worker fputs(_(done_string), stderr);
682*6a54128fSAndroid Build Coastguard Worker flush_bufs();
683*6a54128fSAndroid Build Coastguard Worker if (s_flag | v_flag)
684*6a54128fSAndroid Build Coastguard Worker fputs(_("Reading and comparing: "), stderr);
685*6a54128fSAndroid Build Coastguard Worker num_blocks = last_block;
686*6a54128fSAndroid Build Coastguard Worker currently_testing = first_block;
687*6a54128fSAndroid Build Coastguard Worker if (s_flag && v_flag <= 1)
688*6a54128fSAndroid Build Coastguard Worker alarm_intr(SIGALRM);
689*6a54128fSAndroid Build Coastguard Worker
690*6a54128fSAndroid Build Coastguard Worker try = blocks_at_once;
691*6a54128fSAndroid Build Coastguard Worker while (currently_testing < last_block) {
692*6a54128fSAndroid Build Coastguard Worker if (bb_count >= max_bb) {
693*6a54128fSAndroid Build Coastguard Worker if (s_flag || v_flag) {
694*6a54128fSAndroid Build Coastguard Worker fputs(_("Too many bad blocks, aborting test\n"), stderr);
695*6a54128fSAndroid Build Coastguard Worker }
696*6a54128fSAndroid Build Coastguard Worker break;
697*6a54128fSAndroid Build Coastguard Worker }
698*6a54128fSAndroid Build Coastguard Worker if (currently_testing + try > last_block)
699*6a54128fSAndroid Build Coastguard Worker try = last_block - currently_testing;
700*6a54128fSAndroid Build Coastguard Worker got = do_read (dev, read_buffer, try, block_size,
701*6a54128fSAndroid Build Coastguard Worker currently_testing);
702*6a54128fSAndroid Build Coastguard Worker if (got == 0 && try == 1)
703*6a54128fSAndroid Build Coastguard Worker bb_count += bb_output(currently_testing++, READ_ERROR);
704*6a54128fSAndroid Build Coastguard Worker currently_testing += got;
705*6a54128fSAndroid Build Coastguard Worker if (got != try) {
706*6a54128fSAndroid Build Coastguard Worker try = 1;
707*6a54128fSAndroid Build Coastguard Worker if (recover_block == ~0U)
708*6a54128fSAndroid Build Coastguard Worker recover_block = currently_testing -
709*6a54128fSAndroid Build Coastguard Worker got + blocks_at_once;
710*6a54128fSAndroid Build Coastguard Worker continue;
711*6a54128fSAndroid Build Coastguard Worker } else if (currently_testing == recover_block) {
712*6a54128fSAndroid Build Coastguard Worker try = blocks_at_once;
713*6a54128fSAndroid Build Coastguard Worker recover_block = ~0U;
714*6a54128fSAndroid Build Coastguard Worker }
715*6a54128fSAndroid Build Coastguard Worker for (i=0; i < got; i++) {
716*6a54128fSAndroid Build Coastguard Worker if (memcmp(read_buffer + i * block_size,
717*6a54128fSAndroid Build Coastguard Worker buffer + i * block_size,
718*6a54128fSAndroid Build Coastguard Worker block_size))
719*6a54128fSAndroid Build Coastguard Worker bb_count += bb_output(currently_testing+i, CORRUPTION_ERROR);
720*6a54128fSAndroid Build Coastguard Worker }
721*6a54128fSAndroid Build Coastguard Worker if (v_flag > 1)
722*6a54128fSAndroid Build Coastguard Worker print_status();
723*6a54128fSAndroid Build Coastguard Worker }
724*6a54128fSAndroid Build Coastguard Worker
725*6a54128fSAndroid Build Coastguard Worker num_blocks = 0;
726*6a54128fSAndroid Build Coastguard Worker alarm (0);
727*6a54128fSAndroid Build Coastguard Worker if (s_flag | v_flag)
728*6a54128fSAndroid Build Coastguard Worker fputs(_(done_string), stderr);
729*6a54128fSAndroid Build Coastguard Worker flush_bufs();
730*6a54128fSAndroid Build Coastguard Worker }
731*6a54128fSAndroid Build Coastguard Worker uncapture_terminate();
732*6a54128fSAndroid Build Coastguard Worker free(buffer);
733*6a54128fSAndroid Build Coastguard Worker return bb_count;
734*6a54128fSAndroid Build Coastguard Worker }
735*6a54128fSAndroid Build Coastguard Worker
736*6a54128fSAndroid Build Coastguard Worker struct saved_blk_record {
737*6a54128fSAndroid Build Coastguard Worker blk_t block;
738*6a54128fSAndroid Build Coastguard Worker int num;
739*6a54128fSAndroid Build Coastguard Worker };
740*6a54128fSAndroid Build Coastguard Worker
test_nd(int dev,blk_t last_block,int block_size,blk_t first_block,unsigned int blocks_at_once)741*6a54128fSAndroid Build Coastguard Worker static unsigned int test_nd (int dev, blk_t last_block,
742*6a54128fSAndroid Build Coastguard Worker int block_size, blk_t first_block,
743*6a54128fSAndroid Build Coastguard Worker unsigned int blocks_at_once)
744*6a54128fSAndroid Build Coastguard Worker {
745*6a54128fSAndroid Build Coastguard Worker unsigned char *blkbuf, *save_ptr, *test_ptr, *read_ptr;
746*6a54128fSAndroid Build Coastguard Worker unsigned char *test_base, *save_base, *read_base;
747*6a54128fSAndroid Build Coastguard Worker int try, i;
748*6a54128fSAndroid Build Coastguard Worker const unsigned int patterns[] = { ~0 };
749*6a54128fSAndroid Build Coastguard Worker const unsigned int *pattern;
750*6a54128fSAndroid Build Coastguard Worker int nr_pattern, pat_idx;
751*6a54128fSAndroid Build Coastguard Worker int got, used2, written;
752*6a54128fSAndroid Build Coastguard Worker blk_t save_currently_testing;
753*6a54128fSAndroid Build Coastguard Worker struct saved_blk_record *test_record;
754*6a54128fSAndroid Build Coastguard Worker /* This is static to prevent being clobbered by the longjmp */
755*6a54128fSAndroid Build Coastguard Worker static int num_saved;
756*6a54128fSAndroid Build Coastguard Worker jmp_buf terminate_env;
757*6a54128fSAndroid Build Coastguard Worker errcode_t errcode;
758*6a54128fSAndroid Build Coastguard Worker unsigned long buf_used;
759*6a54128fSAndroid Build Coastguard Worker static unsigned int bb_count;
760*6a54128fSAndroid Build Coastguard Worker unsigned int granularity = blocks_at_once;
761*6a54128fSAndroid Build Coastguard Worker blk_t recover_block = ~0U;
762*6a54128fSAndroid Build Coastguard Worker
763*6a54128fSAndroid Build Coastguard Worker bb_count = 0;
764*6a54128fSAndroid Build Coastguard Worker errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
765*6a54128fSAndroid Build Coastguard Worker if (errcode) {
766*6a54128fSAndroid Build Coastguard Worker com_err(program_name, errcode, "%s",
767*6a54128fSAndroid Build Coastguard Worker _("while beginning bad block list iteration"));
768*6a54128fSAndroid Build Coastguard Worker exit (1);
769*6a54128fSAndroid Build Coastguard Worker }
770*6a54128fSAndroid Build Coastguard Worker do {
771*6a54128fSAndroid Build Coastguard Worker ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
772*6a54128fSAndroid Build Coastguard Worker } while (next_bad && next_bad < first_block);
773*6a54128fSAndroid Build Coastguard Worker
774*6a54128fSAndroid Build Coastguard Worker blkbuf = allocate_buffer((size_t) 3 * blocks_at_once * block_size);
775*6a54128fSAndroid Build Coastguard Worker test_record = malloc(blocks_at_once * sizeof(struct saved_blk_record));
776*6a54128fSAndroid Build Coastguard Worker if (!blkbuf || !test_record) {
777*6a54128fSAndroid Build Coastguard Worker com_err(program_name, ENOMEM, "%s",
778*6a54128fSAndroid Build Coastguard Worker _("while allocating buffers"));
779*6a54128fSAndroid Build Coastguard Worker exit (1);
780*6a54128fSAndroid Build Coastguard Worker }
781*6a54128fSAndroid Build Coastguard Worker
782*6a54128fSAndroid Build Coastguard Worker save_base = blkbuf;
783*6a54128fSAndroid Build Coastguard Worker test_base = blkbuf + (blocks_at_once * block_size);
784*6a54128fSAndroid Build Coastguard Worker read_base = blkbuf + (2 * blocks_at_once * block_size);
785*6a54128fSAndroid Build Coastguard Worker
786*6a54128fSAndroid Build Coastguard Worker num_saved = 0;
787*6a54128fSAndroid Build Coastguard Worker
788*6a54128fSAndroid Build Coastguard Worker flush_bufs();
789*6a54128fSAndroid Build Coastguard Worker if (v_flag) {
790*6a54128fSAndroid Build Coastguard Worker fputs(_("Checking for bad blocks in non-destructive read-write mode\n"), stderr);
791*6a54128fSAndroid Build Coastguard Worker fprintf (stderr, _("From block %lu to %lu\n"),
792*6a54128fSAndroid Build Coastguard Worker (unsigned long) first_block,
793*6a54128fSAndroid Build Coastguard Worker (unsigned long) last_block - 1);
794*6a54128fSAndroid Build Coastguard Worker }
795*6a54128fSAndroid Build Coastguard Worker if (s_flag || v_flag > 1) {
796*6a54128fSAndroid Build Coastguard Worker fputs(_("Checking for bad blocks (non-destructive read-write test)\n"), stderr);
797*6a54128fSAndroid Build Coastguard Worker }
798*6a54128fSAndroid Build Coastguard Worker if (setjmp(terminate_env)) {
799*6a54128fSAndroid Build Coastguard Worker /*
800*6a54128fSAndroid Build Coastguard Worker * Abnormal termination by a signal is handled here.
801*6a54128fSAndroid Build Coastguard Worker */
802*6a54128fSAndroid Build Coastguard Worker signal (SIGALRM, SIG_IGN);
803*6a54128fSAndroid Build Coastguard Worker fputs(_("\nInterrupt caught, cleaning up\n"), stderr);
804*6a54128fSAndroid Build Coastguard Worker
805*6a54128fSAndroid Build Coastguard Worker save_ptr = save_base;
806*6a54128fSAndroid Build Coastguard Worker for (i=0; i < num_saved; i++) {
807*6a54128fSAndroid Build Coastguard Worker do_write(dev, save_ptr, test_record[i].num,
808*6a54128fSAndroid Build Coastguard Worker block_size, test_record[i].block);
809*6a54128fSAndroid Build Coastguard Worker save_ptr += test_record[i].num * block_size;
810*6a54128fSAndroid Build Coastguard Worker }
811*6a54128fSAndroid Build Coastguard Worker fflush (out);
812*6a54128fSAndroid Build Coastguard Worker exit(1);
813*6a54128fSAndroid Build Coastguard Worker }
814*6a54128fSAndroid Build Coastguard Worker
815*6a54128fSAndroid Build Coastguard Worker /* set up abend handler */
816*6a54128fSAndroid Build Coastguard Worker capture_terminate(terminate_env);
817*6a54128fSAndroid Build Coastguard Worker
818*6a54128fSAndroid Build Coastguard Worker if (t_flag) {
819*6a54128fSAndroid Build Coastguard Worker pattern = t_patts;
820*6a54128fSAndroid Build Coastguard Worker nr_pattern = t_flag;
821*6a54128fSAndroid Build Coastguard Worker } else {
822*6a54128fSAndroid Build Coastguard Worker pattern = patterns;
823*6a54128fSAndroid Build Coastguard Worker nr_pattern = sizeof(patterns) / sizeof(patterns[0]);
824*6a54128fSAndroid Build Coastguard Worker }
825*6a54128fSAndroid Build Coastguard Worker for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) {
826*6a54128fSAndroid Build Coastguard Worker pattern_fill(test_base, pattern[pat_idx],
827*6a54128fSAndroid Build Coastguard Worker blocks_at_once * block_size);
828*6a54128fSAndroid Build Coastguard Worker
829*6a54128fSAndroid Build Coastguard Worker buf_used = 0;
830*6a54128fSAndroid Build Coastguard Worker bb_count = 0;
831*6a54128fSAndroid Build Coastguard Worker save_ptr = save_base;
832*6a54128fSAndroid Build Coastguard Worker test_ptr = test_base;
833*6a54128fSAndroid Build Coastguard Worker currently_testing = first_block;
834*6a54128fSAndroid Build Coastguard Worker num_blocks = last_block - 1;
835*6a54128fSAndroid Build Coastguard Worker if (s_flag && v_flag <= 1)
836*6a54128fSAndroid Build Coastguard Worker alarm_intr(SIGALRM);
837*6a54128fSAndroid Build Coastguard Worker
838*6a54128fSAndroid Build Coastguard Worker while (currently_testing < last_block) {
839*6a54128fSAndroid Build Coastguard Worker if (bb_count >= max_bb) {
840*6a54128fSAndroid Build Coastguard Worker if (s_flag || v_flag) {
841*6a54128fSAndroid Build Coastguard Worker fputs(_("Too many bad blocks, aborting test\n"), stderr);
842*6a54128fSAndroid Build Coastguard Worker }
843*6a54128fSAndroid Build Coastguard Worker break;
844*6a54128fSAndroid Build Coastguard Worker }
845*6a54128fSAndroid Build Coastguard Worker got = try = granularity - buf_used;
846*6a54128fSAndroid Build Coastguard Worker if (next_bad) {
847*6a54128fSAndroid Build Coastguard Worker if (currently_testing == next_bad) {
848*6a54128fSAndroid Build Coastguard Worker /* fprintf (out, "%lu\n", nextbad); */
849*6a54128fSAndroid Build Coastguard Worker ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
850*6a54128fSAndroid Build Coastguard Worker currently_testing++;
851*6a54128fSAndroid Build Coastguard Worker goto check_for_more;
852*6a54128fSAndroid Build Coastguard Worker }
853*6a54128fSAndroid Build Coastguard Worker else if (currently_testing + try > next_bad)
854*6a54128fSAndroid Build Coastguard Worker try = next_bad - currently_testing;
855*6a54128fSAndroid Build Coastguard Worker }
856*6a54128fSAndroid Build Coastguard Worker if (currently_testing + try > last_block)
857*6a54128fSAndroid Build Coastguard Worker try = last_block - currently_testing;
858*6a54128fSAndroid Build Coastguard Worker got = do_read (dev, save_ptr, try, block_size,
859*6a54128fSAndroid Build Coastguard Worker currently_testing);
860*6a54128fSAndroid Build Coastguard Worker if (got == 0) {
861*6a54128fSAndroid Build Coastguard Worker if (recover_block == ~0U)
862*6a54128fSAndroid Build Coastguard Worker recover_block = currently_testing +
863*6a54128fSAndroid Build Coastguard Worker blocks_at_once;
864*6a54128fSAndroid Build Coastguard Worker if (granularity != 1) {
865*6a54128fSAndroid Build Coastguard Worker granularity = 1;
866*6a54128fSAndroid Build Coastguard Worker continue;
867*6a54128fSAndroid Build Coastguard Worker }
868*6a54128fSAndroid Build Coastguard Worker /* First block must have been bad. */
869*6a54128fSAndroid Build Coastguard Worker bb_count += bb_output(currently_testing++, READ_ERROR);
870*6a54128fSAndroid Build Coastguard Worker goto check_for_more;
871*6a54128fSAndroid Build Coastguard Worker }
872*6a54128fSAndroid Build Coastguard Worker
873*6a54128fSAndroid Build Coastguard Worker /*
874*6a54128fSAndroid Build Coastguard Worker * Note the fact that we've saved this much data
875*6a54128fSAndroid Build Coastguard Worker * *before* we overwrite it with test data
876*6a54128fSAndroid Build Coastguard Worker */
877*6a54128fSAndroid Build Coastguard Worker test_record[num_saved].block = currently_testing;
878*6a54128fSAndroid Build Coastguard Worker test_record[num_saved].num = got;
879*6a54128fSAndroid Build Coastguard Worker num_saved++;
880*6a54128fSAndroid Build Coastguard Worker
881*6a54128fSAndroid Build Coastguard Worker /* Write the test data */
882*6a54128fSAndroid Build Coastguard Worker written = do_write (dev, test_ptr, got, block_size,
883*6a54128fSAndroid Build Coastguard Worker currently_testing);
884*6a54128fSAndroid Build Coastguard Worker if (written != got)
885*6a54128fSAndroid Build Coastguard Worker com_err (program_name, errno,
886*6a54128fSAndroid Build Coastguard Worker _("during test data write, block %lu"),
887*6a54128fSAndroid Build Coastguard Worker (unsigned long) currently_testing +
888*6a54128fSAndroid Build Coastguard Worker written);
889*6a54128fSAndroid Build Coastguard Worker
890*6a54128fSAndroid Build Coastguard Worker buf_used += got;
891*6a54128fSAndroid Build Coastguard Worker save_ptr += got * block_size;
892*6a54128fSAndroid Build Coastguard Worker test_ptr += got * block_size;
893*6a54128fSAndroid Build Coastguard Worker currently_testing += got;
894*6a54128fSAndroid Build Coastguard Worker if (got != try) {
895*6a54128fSAndroid Build Coastguard Worker if (recover_block == ~0U)
896*6a54128fSAndroid Build Coastguard Worker recover_block = currently_testing -
897*6a54128fSAndroid Build Coastguard Worker got + blocks_at_once;
898*6a54128fSAndroid Build Coastguard Worker continue;
899*6a54128fSAndroid Build Coastguard Worker }
900*6a54128fSAndroid Build Coastguard Worker
901*6a54128fSAndroid Build Coastguard Worker check_for_more:
902*6a54128fSAndroid Build Coastguard Worker /*
903*6a54128fSAndroid Build Coastguard Worker * If there's room for more blocks to be tested this
904*6a54128fSAndroid Build Coastguard Worker * around, and we're not done yet testing the disk, go
905*6a54128fSAndroid Build Coastguard Worker * back and get some more blocks.
906*6a54128fSAndroid Build Coastguard Worker */
907*6a54128fSAndroid Build Coastguard Worker if ((buf_used != granularity) &&
908*6a54128fSAndroid Build Coastguard Worker (currently_testing < last_block))
909*6a54128fSAndroid Build Coastguard Worker continue;
910*6a54128fSAndroid Build Coastguard Worker
911*6a54128fSAndroid Build Coastguard Worker if (currently_testing >= recover_block) {
912*6a54128fSAndroid Build Coastguard Worker granularity = blocks_at_once;
913*6a54128fSAndroid Build Coastguard Worker recover_block = ~0;
914*6a54128fSAndroid Build Coastguard Worker }
915*6a54128fSAndroid Build Coastguard Worker
916*6a54128fSAndroid Build Coastguard Worker flush_bufs();
917*6a54128fSAndroid Build Coastguard Worker save_currently_testing = currently_testing;
918*6a54128fSAndroid Build Coastguard Worker
919*6a54128fSAndroid Build Coastguard Worker /*
920*6a54128fSAndroid Build Coastguard Worker * for each contiguous block that we read into the
921*6a54128fSAndroid Build Coastguard Worker * buffer (and wrote test data into afterwards), read
922*6a54128fSAndroid Build Coastguard Worker * it back (looping if necessary, to get past newly
923*6a54128fSAndroid Build Coastguard Worker * discovered unreadable blocks, of which there should
924*6a54128fSAndroid Build Coastguard Worker * be none, but with a hard drive which is unreliable,
925*6a54128fSAndroid Build Coastguard Worker * it has happened), and compare with the test data
926*6a54128fSAndroid Build Coastguard Worker * that was written; output to the bad block list if
927*6a54128fSAndroid Build Coastguard Worker * it doesn't match.
928*6a54128fSAndroid Build Coastguard Worker */
929*6a54128fSAndroid Build Coastguard Worker used2 = 0;
930*6a54128fSAndroid Build Coastguard Worker save_ptr = save_base;
931*6a54128fSAndroid Build Coastguard Worker test_ptr = test_base;
932*6a54128fSAndroid Build Coastguard Worker read_ptr = read_base;
933*6a54128fSAndroid Build Coastguard Worker try = 0;
934*6a54128fSAndroid Build Coastguard Worker
935*6a54128fSAndroid Build Coastguard Worker while (1) {
936*6a54128fSAndroid Build Coastguard Worker if (try == 0) {
937*6a54128fSAndroid Build Coastguard Worker if (used2 >= num_saved)
938*6a54128fSAndroid Build Coastguard Worker break;
939*6a54128fSAndroid Build Coastguard Worker currently_testing = test_record[used2].block;
940*6a54128fSAndroid Build Coastguard Worker try = test_record[used2].num;
941*6a54128fSAndroid Build Coastguard Worker used2++;
942*6a54128fSAndroid Build Coastguard Worker }
943*6a54128fSAndroid Build Coastguard Worker
944*6a54128fSAndroid Build Coastguard Worker got = do_read (dev, read_ptr, try,
945*6a54128fSAndroid Build Coastguard Worker block_size, currently_testing);
946*6a54128fSAndroid Build Coastguard Worker
947*6a54128fSAndroid Build Coastguard Worker /* test the comparison between all the
948*6a54128fSAndroid Build Coastguard Worker blocks successfully read */
949*6a54128fSAndroid Build Coastguard Worker for (i = 0; i < got; ++i)
950*6a54128fSAndroid Build Coastguard Worker if (memcmp (test_ptr+i*block_size,
951*6a54128fSAndroid Build Coastguard Worker read_ptr+i*block_size, block_size))
952*6a54128fSAndroid Build Coastguard Worker bb_count += bb_output(currently_testing + i, CORRUPTION_ERROR);
953*6a54128fSAndroid Build Coastguard Worker if (got < try) {
954*6a54128fSAndroid Build Coastguard Worker bb_count += bb_output(currently_testing + got, READ_ERROR);
955*6a54128fSAndroid Build Coastguard Worker got++;
956*6a54128fSAndroid Build Coastguard Worker }
957*6a54128fSAndroid Build Coastguard Worker
958*6a54128fSAndroid Build Coastguard Worker /* write back original data */
959*6a54128fSAndroid Build Coastguard Worker do_write (dev, save_ptr, got,
960*6a54128fSAndroid Build Coastguard Worker block_size, currently_testing);
961*6a54128fSAndroid Build Coastguard Worker save_ptr += got * block_size;
962*6a54128fSAndroid Build Coastguard Worker
963*6a54128fSAndroid Build Coastguard Worker currently_testing += got;
964*6a54128fSAndroid Build Coastguard Worker test_ptr += got * block_size;
965*6a54128fSAndroid Build Coastguard Worker read_ptr += got * block_size;
966*6a54128fSAndroid Build Coastguard Worker try -= got;
967*6a54128fSAndroid Build Coastguard Worker }
968*6a54128fSAndroid Build Coastguard Worker
969*6a54128fSAndroid Build Coastguard Worker /* empty the buffer so it can be reused */
970*6a54128fSAndroid Build Coastguard Worker num_saved = 0;
971*6a54128fSAndroid Build Coastguard Worker buf_used = 0;
972*6a54128fSAndroid Build Coastguard Worker save_ptr = save_base;
973*6a54128fSAndroid Build Coastguard Worker test_ptr = test_base;
974*6a54128fSAndroid Build Coastguard Worker currently_testing = save_currently_testing;
975*6a54128fSAndroid Build Coastguard Worker }
976*6a54128fSAndroid Build Coastguard Worker num_blocks = 0;
977*6a54128fSAndroid Build Coastguard Worker alarm(0);
978*6a54128fSAndroid Build Coastguard Worker if (s_flag || v_flag > 1)
979*6a54128fSAndroid Build Coastguard Worker fputs(_(done_string), stderr);
980*6a54128fSAndroid Build Coastguard Worker
981*6a54128fSAndroid Build Coastguard Worker flush_bufs();
982*6a54128fSAndroid Build Coastguard Worker }
983*6a54128fSAndroid Build Coastguard Worker uncapture_terminate();
984*6a54128fSAndroid Build Coastguard Worker fflush(stderr);
985*6a54128fSAndroid Build Coastguard Worker free(blkbuf);
986*6a54128fSAndroid Build Coastguard Worker free(test_record);
987*6a54128fSAndroid Build Coastguard Worker
988*6a54128fSAndroid Build Coastguard Worker ext2fs_badblocks_list_iterate_end(bb_iter);
989*6a54128fSAndroid Build Coastguard Worker
990*6a54128fSAndroid Build Coastguard Worker return bb_count;
991*6a54128fSAndroid Build Coastguard Worker }
992*6a54128fSAndroid Build Coastguard Worker
check_mount(char * device_name)993*6a54128fSAndroid Build Coastguard Worker static void check_mount(char *device_name)
994*6a54128fSAndroid Build Coastguard Worker {
995*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
996*6a54128fSAndroid Build Coastguard Worker int mount_flags;
997*6a54128fSAndroid Build Coastguard Worker
998*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_check_if_mounted(device_name, &mount_flags);
999*6a54128fSAndroid Build Coastguard Worker if (retval) {
1000*6a54128fSAndroid Build Coastguard Worker com_err("ext2fs_check_if_mount", retval,
1001*6a54128fSAndroid Build Coastguard Worker _("while determining whether %s is mounted."),
1002*6a54128fSAndroid Build Coastguard Worker device_name);
1003*6a54128fSAndroid Build Coastguard Worker return;
1004*6a54128fSAndroid Build Coastguard Worker }
1005*6a54128fSAndroid Build Coastguard Worker if (mount_flags & EXT2_MF_MOUNTED) {
1006*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, _("%s is mounted; "), device_name);
1007*6a54128fSAndroid Build Coastguard Worker if (force) {
1008*6a54128fSAndroid Build Coastguard Worker fputs(_("badblocks forced anyway. "
1009*6a54128fSAndroid Build Coastguard Worker "Hope /etc/mtab is incorrect.\n"), stderr);
1010*6a54128fSAndroid Build Coastguard Worker return;
1011*6a54128fSAndroid Build Coastguard Worker }
1012*6a54128fSAndroid Build Coastguard Worker abort_badblocks:
1013*6a54128fSAndroid Build Coastguard Worker fputs(_("it's not safe to run badblocks!\n"), stderr);
1014*6a54128fSAndroid Build Coastguard Worker exit(1);
1015*6a54128fSAndroid Build Coastguard Worker }
1016*6a54128fSAndroid Build Coastguard Worker
1017*6a54128fSAndroid Build Coastguard Worker if ((mount_flags & EXT2_MF_BUSY) && !exclusive_ok) {
1018*6a54128fSAndroid Build Coastguard Worker fprintf(stderr, _("%s is apparently in use by the system; "),
1019*6a54128fSAndroid Build Coastguard Worker device_name);
1020*6a54128fSAndroid Build Coastguard Worker if (force)
1021*6a54128fSAndroid Build Coastguard Worker fputs(_("badblocks forced anyway.\n"), stderr);
1022*6a54128fSAndroid Build Coastguard Worker else
1023*6a54128fSAndroid Build Coastguard Worker goto abort_badblocks;
1024*6a54128fSAndroid Build Coastguard Worker }
1025*6a54128fSAndroid Build Coastguard Worker
1026*6a54128fSAndroid Build Coastguard Worker }
1027*6a54128fSAndroid Build Coastguard Worker
1028*6a54128fSAndroid Build Coastguard Worker /*
1029*6a54128fSAndroid Build Coastguard Worker * This function will convert a string to an unsigned long, printing
1030*6a54128fSAndroid Build Coastguard Worker * an error message if it fails, and returning success or failure in err.
1031*6a54128fSAndroid Build Coastguard Worker */
parse_uint(const char * str,const char * descr)1032*6a54128fSAndroid Build Coastguard Worker static unsigned int parse_uint(const char *str, const char *descr)
1033*6a54128fSAndroid Build Coastguard Worker {
1034*6a54128fSAndroid Build Coastguard Worker char *tmp;
1035*6a54128fSAndroid Build Coastguard Worker unsigned long ret;
1036*6a54128fSAndroid Build Coastguard Worker
1037*6a54128fSAndroid Build Coastguard Worker errno = 0;
1038*6a54128fSAndroid Build Coastguard Worker ret = strtoul(str, &tmp, 0);
1039*6a54128fSAndroid Build Coastguard Worker if (*tmp || errno) {
1040*6a54128fSAndroid Build Coastguard Worker com_err (program_name, 0, _("invalid %s - %s"), descr, str);
1041*6a54128fSAndroid Build Coastguard Worker exit (1);
1042*6a54128fSAndroid Build Coastguard Worker } else if ((ret > UINT_MAX) ||
1043*6a54128fSAndroid Build Coastguard Worker (ret == ULONG_MAX && errno == ERANGE)) {
1044*6a54128fSAndroid Build Coastguard Worker com_err (program_name, 0, _("%s too large - %lu"), descr, ret);
1045*6a54128fSAndroid Build Coastguard Worker exit (1);
1046*6a54128fSAndroid Build Coastguard Worker }
1047*6a54128fSAndroid Build Coastguard Worker return ret;
1048*6a54128fSAndroid Build Coastguard Worker }
1049*6a54128fSAndroid Build Coastguard Worker
main(int argc,char ** argv)1050*6a54128fSAndroid Build Coastguard Worker int main (int argc, char ** argv)
1051*6a54128fSAndroid Build Coastguard Worker {
1052*6a54128fSAndroid Build Coastguard Worker int c;
1053*6a54128fSAndroid Build Coastguard Worker char * device_name;
1054*6a54128fSAndroid Build Coastguard Worker char * host_device_name = NULL;
1055*6a54128fSAndroid Build Coastguard Worker char * input_file = NULL;
1056*6a54128fSAndroid Build Coastguard Worker char * output_file = NULL;
1057*6a54128fSAndroid Build Coastguard Worker FILE * in = NULL;
1058*6a54128fSAndroid Build Coastguard Worker unsigned int block_size = 1024;
1059*6a54128fSAndroid Build Coastguard Worker unsigned int blocks_at_once = 64;
1060*6a54128fSAndroid Build Coastguard Worker blk64_t last_block, first_block;
1061*6a54128fSAndroid Build Coastguard Worker int num_passes = 0;
1062*6a54128fSAndroid Build Coastguard Worker int passes_clean = 0;
1063*6a54128fSAndroid Build Coastguard Worker int dev;
1064*6a54128fSAndroid Build Coastguard Worker errcode_t errcode;
1065*6a54128fSAndroid Build Coastguard Worker unsigned int pattern;
1066*6a54128fSAndroid Build Coastguard Worker unsigned int (*test_func)(int, blk_t,
1067*6a54128fSAndroid Build Coastguard Worker int, blk_t,
1068*6a54128fSAndroid Build Coastguard Worker unsigned int);
1069*6a54128fSAndroid Build Coastguard Worker int open_flag;
1070*6a54128fSAndroid Build Coastguard Worker long sysval;
1071*6a54128fSAndroid Build Coastguard Worker unsigned long long inblk;
1072*6a54128fSAndroid Build Coastguard Worker
1073*6a54128fSAndroid Build Coastguard Worker setbuf(stdout, NULL);
1074*6a54128fSAndroid Build Coastguard Worker setbuf(stderr, NULL);
1075*6a54128fSAndroid Build Coastguard Worker #ifdef ENABLE_NLS
1076*6a54128fSAndroid Build Coastguard Worker setlocale(LC_MESSAGES, "");
1077*6a54128fSAndroid Build Coastguard Worker setlocale(LC_CTYPE, "");
1078*6a54128fSAndroid Build Coastguard Worker bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
1079*6a54128fSAndroid Build Coastguard Worker textdomain(NLS_CAT_NAME);
1080*6a54128fSAndroid Build Coastguard Worker set_com_err_gettext(gettext);
1081*6a54128fSAndroid Build Coastguard Worker #endif
1082*6a54128fSAndroid Build Coastguard Worker srandom((unsigned int)time(NULL)); /* simple randomness is enough */
1083*6a54128fSAndroid Build Coastguard Worker test_func = test_ro;
1084*6a54128fSAndroid Build Coastguard Worker
1085*6a54128fSAndroid Build Coastguard Worker /* Determine the system page size if possible */
1086*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_SYSCONF
1087*6a54128fSAndroid Build Coastguard Worker #if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
1088*6a54128fSAndroid Build Coastguard Worker #define _SC_PAGESIZE _SC_PAGE_SIZE
1089*6a54128fSAndroid Build Coastguard Worker #endif
1090*6a54128fSAndroid Build Coastguard Worker #ifdef _SC_PAGESIZE
1091*6a54128fSAndroid Build Coastguard Worker sysval = sysconf(_SC_PAGESIZE);
1092*6a54128fSAndroid Build Coastguard Worker if (sysval > 0)
1093*6a54128fSAndroid Build Coastguard Worker sys_page_size = sysval;
1094*6a54128fSAndroid Build Coastguard Worker #endif /* _SC_PAGESIZE */
1095*6a54128fSAndroid Build Coastguard Worker #endif /* HAVE_SYSCONF */
1096*6a54128fSAndroid Build Coastguard Worker
1097*6a54128fSAndroid Build Coastguard Worker if (argc && *argv)
1098*6a54128fSAndroid Build Coastguard Worker program_name = *argv;
1099*6a54128fSAndroid Build Coastguard Worker else
1100*6a54128fSAndroid Build Coastguard Worker usage();
1101*6a54128fSAndroid Build Coastguard Worker while ((c = getopt (argc, argv, "b:d:e:fi:o:svwnc:p:h:t:BX")) != EOF) {
1102*6a54128fSAndroid Build Coastguard Worker switch (c) {
1103*6a54128fSAndroid Build Coastguard Worker case 'b':
1104*6a54128fSAndroid Build Coastguard Worker block_size = parse_uint(optarg, "block size");
1105*6a54128fSAndroid Build Coastguard Worker break;
1106*6a54128fSAndroid Build Coastguard Worker case 'f':
1107*6a54128fSAndroid Build Coastguard Worker force++;
1108*6a54128fSAndroid Build Coastguard Worker break;
1109*6a54128fSAndroid Build Coastguard Worker case 'i':
1110*6a54128fSAndroid Build Coastguard Worker input_file = optarg;
1111*6a54128fSAndroid Build Coastguard Worker break;
1112*6a54128fSAndroid Build Coastguard Worker case 'o':
1113*6a54128fSAndroid Build Coastguard Worker output_file = optarg;
1114*6a54128fSAndroid Build Coastguard Worker break;
1115*6a54128fSAndroid Build Coastguard Worker case 's':
1116*6a54128fSAndroid Build Coastguard Worker s_flag = 1;
1117*6a54128fSAndroid Build Coastguard Worker break;
1118*6a54128fSAndroid Build Coastguard Worker case 'v':
1119*6a54128fSAndroid Build Coastguard Worker v_flag++;
1120*6a54128fSAndroid Build Coastguard Worker break;
1121*6a54128fSAndroid Build Coastguard Worker case 'w':
1122*6a54128fSAndroid Build Coastguard Worker if (w_flag)
1123*6a54128fSAndroid Build Coastguard Worker exclusive_usage();
1124*6a54128fSAndroid Build Coastguard Worker test_func = test_rw;
1125*6a54128fSAndroid Build Coastguard Worker w_flag = 1;
1126*6a54128fSAndroid Build Coastguard Worker break;
1127*6a54128fSAndroid Build Coastguard Worker case 'n':
1128*6a54128fSAndroid Build Coastguard Worker if (w_flag)
1129*6a54128fSAndroid Build Coastguard Worker exclusive_usage();
1130*6a54128fSAndroid Build Coastguard Worker test_func = test_nd;
1131*6a54128fSAndroid Build Coastguard Worker w_flag = 2;
1132*6a54128fSAndroid Build Coastguard Worker break;
1133*6a54128fSAndroid Build Coastguard Worker case 'c':
1134*6a54128fSAndroid Build Coastguard Worker blocks_at_once = parse_uint(optarg, "blocks at once");
1135*6a54128fSAndroid Build Coastguard Worker break;
1136*6a54128fSAndroid Build Coastguard Worker case 'e':
1137*6a54128fSAndroid Build Coastguard Worker max_bb = parse_uint(optarg, "max bad block count");
1138*6a54128fSAndroid Build Coastguard Worker if (max_bb > MAX_BAD_BLOCKS) {
1139*6a54128fSAndroid Build Coastguard Worker com_err (program_name, 0,
1140*6a54128fSAndroid Build Coastguard Worker _("Too big max bad blocks count %u - "
1141*6a54128fSAndroid Build Coastguard Worker "maximum is %u"), max_bb,
1142*6a54128fSAndroid Build Coastguard Worker MAX_BAD_BLOCKS);
1143*6a54128fSAndroid Build Coastguard Worker exit (1);
1144*6a54128fSAndroid Build Coastguard Worker }
1145*6a54128fSAndroid Build Coastguard Worker /* 0 really means unlimited but we cannot do that much... */
1146*6a54128fSAndroid Build Coastguard Worker if (max_bb == 0)
1147*6a54128fSAndroid Build Coastguard Worker max_bb = MAX_BAD_BLOCKS;
1148*6a54128fSAndroid Build Coastguard Worker break;
1149*6a54128fSAndroid Build Coastguard Worker case 'd':
1150*6a54128fSAndroid Build Coastguard Worker d_flag = parse_uint(optarg, "read delay factor");
1151*6a54128fSAndroid Build Coastguard Worker break;
1152*6a54128fSAndroid Build Coastguard Worker case 'p':
1153*6a54128fSAndroid Build Coastguard Worker num_passes = parse_uint(optarg,
1154*6a54128fSAndroid Build Coastguard Worker "number of clean passes");
1155*6a54128fSAndroid Build Coastguard Worker break;
1156*6a54128fSAndroid Build Coastguard Worker case 'h':
1157*6a54128fSAndroid Build Coastguard Worker host_device_name = optarg;
1158*6a54128fSAndroid Build Coastguard Worker break;
1159*6a54128fSAndroid Build Coastguard Worker case 't':
1160*6a54128fSAndroid Build Coastguard Worker if (t_flag + 1 > t_max) {
1161*6a54128fSAndroid Build Coastguard Worker unsigned int *t_patts_new;
1162*6a54128fSAndroid Build Coastguard Worker
1163*6a54128fSAndroid Build Coastguard Worker t_patts_new = realloc(t_patts, sizeof(int) *
1164*6a54128fSAndroid Build Coastguard Worker (t_max + T_INC));
1165*6a54128fSAndroid Build Coastguard Worker if (!t_patts_new) {
1166*6a54128fSAndroid Build Coastguard Worker com_err(program_name, ENOMEM,
1167*6a54128fSAndroid Build Coastguard Worker _("can't allocate memory for "
1168*6a54128fSAndroid Build Coastguard Worker "test_pattern - %s"),
1169*6a54128fSAndroid Build Coastguard Worker optarg);
1170*6a54128fSAndroid Build Coastguard Worker exit(1);
1171*6a54128fSAndroid Build Coastguard Worker }
1172*6a54128fSAndroid Build Coastguard Worker t_patts = t_patts_new;
1173*6a54128fSAndroid Build Coastguard Worker t_max += T_INC;
1174*6a54128fSAndroid Build Coastguard Worker }
1175*6a54128fSAndroid Build Coastguard Worker if (!strcmp(optarg, "r") || !strcmp(optarg,"random")) {
1176*6a54128fSAndroid Build Coastguard Worker t_patts[t_flag++] = ~0;
1177*6a54128fSAndroid Build Coastguard Worker } else {
1178*6a54128fSAndroid Build Coastguard Worker pattern = parse_uint(optarg, "test pattern");
1179*6a54128fSAndroid Build Coastguard Worker if (pattern == (unsigned int) ~0)
1180*6a54128fSAndroid Build Coastguard Worker pattern = 0xffff;
1181*6a54128fSAndroid Build Coastguard Worker t_patts[t_flag++] = pattern;
1182*6a54128fSAndroid Build Coastguard Worker }
1183*6a54128fSAndroid Build Coastguard Worker break;
1184*6a54128fSAndroid Build Coastguard Worker case 'B':
1185*6a54128fSAndroid Build Coastguard Worker use_buffered_io = 1;
1186*6a54128fSAndroid Build Coastguard Worker break;
1187*6a54128fSAndroid Build Coastguard Worker case 'X':
1188*6a54128fSAndroid Build Coastguard Worker exclusive_ok++;
1189*6a54128fSAndroid Build Coastguard Worker break;
1190*6a54128fSAndroid Build Coastguard Worker default:
1191*6a54128fSAndroid Build Coastguard Worker usage();
1192*6a54128fSAndroid Build Coastguard Worker }
1193*6a54128fSAndroid Build Coastguard Worker }
1194*6a54128fSAndroid Build Coastguard Worker if (!w_flag) {
1195*6a54128fSAndroid Build Coastguard Worker if (t_flag > 1) {
1196*6a54128fSAndroid Build Coastguard Worker com_err(program_name, 0, "%s",
1197*6a54128fSAndroid Build Coastguard Worker _("Maximum of one test_pattern may be "
1198*6a54128fSAndroid Build Coastguard Worker "specified in read-only mode"));
1199*6a54128fSAndroid Build Coastguard Worker exit(1);
1200*6a54128fSAndroid Build Coastguard Worker }
1201*6a54128fSAndroid Build Coastguard Worker if (t_patts && (t_patts[0] == (unsigned int) ~0)) {
1202*6a54128fSAndroid Build Coastguard Worker com_err(program_name, 0, "%s",
1203*6a54128fSAndroid Build Coastguard Worker _("Random test_pattern is not allowed "
1204*6a54128fSAndroid Build Coastguard Worker "in read-only mode"));
1205*6a54128fSAndroid Build Coastguard Worker exit(1);
1206*6a54128fSAndroid Build Coastguard Worker }
1207*6a54128fSAndroid Build Coastguard Worker }
1208*6a54128fSAndroid Build Coastguard Worker if ((block_size == 0) || (block_size > (1 << 24)) ||
1209*6a54128fSAndroid Build Coastguard Worker (block_size & (block_size - 1))) {
1210*6a54128fSAndroid Build Coastguard Worker com_err(program_name, 0, _("Invalid block size: %u\n"),
1211*6a54128fSAndroid Build Coastguard Worker block_size);
1212*6a54128fSAndroid Build Coastguard Worker exit(1);
1213*6a54128fSAndroid Build Coastguard Worker }
1214*6a54128fSAndroid Build Coastguard Worker if (blocks_at_once == 0) {
1215*6a54128fSAndroid Build Coastguard Worker com_err(program_name, 0, _("Invalid number of blocks: %d\n"),
1216*6a54128fSAndroid Build Coastguard Worker blocks_at_once);
1217*6a54128fSAndroid Build Coastguard Worker exit(1);
1218*6a54128fSAndroid Build Coastguard Worker } else if (((size_t) block_size * blocks_at_once) > SIZE_MAX / 3) {
1219*6a54128fSAndroid Build Coastguard Worker /* maximum usage is in test_nd() */
1220*6a54128fSAndroid Build Coastguard Worker com_err(program_name, 0, _("For block size %d, number of blocks too large: %d\n"),
1221*6a54128fSAndroid Build Coastguard Worker block_size, blocks_at_once);
1222*6a54128fSAndroid Build Coastguard Worker exit(1);
1223*6a54128fSAndroid Build Coastguard Worker }
1224*6a54128fSAndroid Build Coastguard Worker
1225*6a54128fSAndroid Build Coastguard Worker if (optind > argc - 1)
1226*6a54128fSAndroid Build Coastguard Worker usage();
1227*6a54128fSAndroid Build Coastguard Worker device_name = argv[optind++];
1228*6a54128fSAndroid Build Coastguard Worker if (optind > argc - 1) {
1229*6a54128fSAndroid Build Coastguard Worker errcode = ext2fs_get_device_size2(device_name,
1230*6a54128fSAndroid Build Coastguard Worker (int) block_size,
1231*6a54128fSAndroid Build Coastguard Worker &last_block);
1232*6a54128fSAndroid Build Coastguard Worker if (errcode == EXT2_ET_UNIMPLEMENTED) {
1233*6a54128fSAndroid Build Coastguard Worker com_err(program_name, 0, "%s",
1234*6a54128fSAndroid Build Coastguard Worker _("Couldn't determine device size; you "
1235*6a54128fSAndroid Build Coastguard Worker "must specify\nthe size manually\n"));
1236*6a54128fSAndroid Build Coastguard Worker exit(1);
1237*6a54128fSAndroid Build Coastguard Worker }
1238*6a54128fSAndroid Build Coastguard Worker if (errcode) {
1239*6a54128fSAndroid Build Coastguard Worker com_err(program_name, errcode, "%s",
1240*6a54128fSAndroid Build Coastguard Worker _("while trying to determine device size"));
1241*6a54128fSAndroid Build Coastguard Worker exit(1);
1242*6a54128fSAndroid Build Coastguard Worker }
1243*6a54128fSAndroid Build Coastguard Worker } else {
1244*6a54128fSAndroid Build Coastguard Worker errno = 0;
1245*6a54128fSAndroid Build Coastguard Worker last_block = parse_uint(argv[optind], _("last block"));
1246*6a54128fSAndroid Build Coastguard Worker last_block++;
1247*6a54128fSAndroid Build Coastguard Worker optind++;
1248*6a54128fSAndroid Build Coastguard Worker }
1249*6a54128fSAndroid Build Coastguard Worker if (optind <= argc-1) {
1250*6a54128fSAndroid Build Coastguard Worker errno = 0;
1251*6a54128fSAndroid Build Coastguard Worker first_block = parse_uint(argv[optind], _("first block"));
1252*6a54128fSAndroid Build Coastguard Worker } else first_block = 0;
1253*6a54128fSAndroid Build Coastguard Worker if (first_block >= last_block) {
1254*6a54128fSAndroid Build Coastguard Worker com_err (program_name, 0, _("invalid starting block (%llu): must be less than %llu"),
1255*6a54128fSAndroid Build Coastguard Worker (unsigned long long) first_block,
1256*6a54128fSAndroid Build Coastguard Worker (unsigned long long) last_block);
1257*6a54128fSAndroid Build Coastguard Worker exit (1);
1258*6a54128fSAndroid Build Coastguard Worker }
1259*6a54128fSAndroid Build Coastguard Worker /* ext2 badblocks file can't handle large values */
1260*6a54128fSAndroid Build Coastguard Worker if (last_block >> 32) {
1261*6a54128fSAndroid Build Coastguard Worker com_err(program_name, EOVERFLOW,
1262*6a54128fSAndroid Build Coastguard Worker _("invalid end block (%llu): must be 32-bit value"),
1263*6a54128fSAndroid Build Coastguard Worker (unsigned long long) last_block);
1264*6a54128fSAndroid Build Coastguard Worker exit(1);
1265*6a54128fSAndroid Build Coastguard Worker }
1266*6a54128fSAndroid Build Coastguard Worker if (w_flag)
1267*6a54128fSAndroid Build Coastguard Worker check_mount(device_name);
1268*6a54128fSAndroid Build Coastguard Worker
1269*6a54128fSAndroid Build Coastguard Worker gettimeofday(&time_start, 0);
1270*6a54128fSAndroid Build Coastguard Worker open_flag = O_LARGEFILE | (w_flag ? O_RDWR : O_RDONLY);
1271*6a54128fSAndroid Build Coastguard Worker dev = open (device_name, open_flag);
1272*6a54128fSAndroid Build Coastguard Worker if (dev == -1) {
1273*6a54128fSAndroid Build Coastguard Worker com_err (program_name, errno, _("while trying to open %s"),
1274*6a54128fSAndroid Build Coastguard Worker device_name);
1275*6a54128fSAndroid Build Coastguard Worker exit (1);
1276*6a54128fSAndroid Build Coastguard Worker }
1277*6a54128fSAndroid Build Coastguard Worker if (host_device_name) {
1278*6a54128fSAndroid Build Coastguard Worker host_dev = open (host_device_name, open_flag);
1279*6a54128fSAndroid Build Coastguard Worker if (host_dev == -1) {
1280*6a54128fSAndroid Build Coastguard Worker com_err (program_name, errno,
1281*6a54128fSAndroid Build Coastguard Worker _("while trying to open %s"),
1282*6a54128fSAndroid Build Coastguard Worker host_device_name);
1283*6a54128fSAndroid Build Coastguard Worker exit (1);
1284*6a54128fSAndroid Build Coastguard Worker }
1285*6a54128fSAndroid Build Coastguard Worker } else
1286*6a54128fSAndroid Build Coastguard Worker host_dev = dev;
1287*6a54128fSAndroid Build Coastguard Worker if (input_file) {
1288*6a54128fSAndroid Build Coastguard Worker if (strcmp (input_file, "-") == 0)
1289*6a54128fSAndroid Build Coastguard Worker in = stdin;
1290*6a54128fSAndroid Build Coastguard Worker else {
1291*6a54128fSAndroid Build Coastguard Worker in = fopen (input_file, "r");
1292*6a54128fSAndroid Build Coastguard Worker if (in == NULL)
1293*6a54128fSAndroid Build Coastguard Worker {
1294*6a54128fSAndroid Build Coastguard Worker com_err (program_name, errno,
1295*6a54128fSAndroid Build Coastguard Worker _("while trying to open %s"),
1296*6a54128fSAndroid Build Coastguard Worker input_file);
1297*6a54128fSAndroid Build Coastguard Worker exit (1);
1298*6a54128fSAndroid Build Coastguard Worker }
1299*6a54128fSAndroid Build Coastguard Worker }
1300*6a54128fSAndroid Build Coastguard Worker }
1301*6a54128fSAndroid Build Coastguard Worker if (output_file && strcmp (output_file, "-") != 0)
1302*6a54128fSAndroid Build Coastguard Worker {
1303*6a54128fSAndroid Build Coastguard Worker out = fopen (output_file, "w");
1304*6a54128fSAndroid Build Coastguard Worker if (out == NULL)
1305*6a54128fSAndroid Build Coastguard Worker {
1306*6a54128fSAndroid Build Coastguard Worker com_err (program_name, errno,
1307*6a54128fSAndroid Build Coastguard Worker _("while trying to open %s"),
1308*6a54128fSAndroid Build Coastguard Worker output_file);
1309*6a54128fSAndroid Build Coastguard Worker exit (1);
1310*6a54128fSAndroid Build Coastguard Worker }
1311*6a54128fSAndroid Build Coastguard Worker }
1312*6a54128fSAndroid Build Coastguard Worker else
1313*6a54128fSAndroid Build Coastguard Worker out = stdout;
1314*6a54128fSAndroid Build Coastguard Worker
1315*6a54128fSAndroid Build Coastguard Worker errcode = ext2fs_badblocks_list_create(&bb_list,0);
1316*6a54128fSAndroid Build Coastguard Worker if (errcode) {
1317*6a54128fSAndroid Build Coastguard Worker com_err(program_name, errcode, "%s",
1318*6a54128fSAndroid Build Coastguard Worker _("while creating in-memory bad blocks list"));
1319*6a54128fSAndroid Build Coastguard Worker exit (1);
1320*6a54128fSAndroid Build Coastguard Worker }
1321*6a54128fSAndroid Build Coastguard Worker
1322*6a54128fSAndroid Build Coastguard Worker if (in) {
1323*6a54128fSAndroid Build Coastguard Worker for(;;) {
1324*6a54128fSAndroid Build Coastguard Worker switch (fscanf(in, "%llu\n", &inblk)) {
1325*6a54128fSAndroid Build Coastguard Worker case 0:
1326*6a54128fSAndroid Build Coastguard Worker com_err(program_name, 0, "%s",
1327*6a54128fSAndroid Build Coastguard Worker _("input file - bad format"));
1328*6a54128fSAndroid Build Coastguard Worker exit (1);
1329*6a54128fSAndroid Build Coastguard Worker case EOF:
1330*6a54128fSAndroid Build Coastguard Worker break;
1331*6a54128fSAndroid Build Coastguard Worker default:
1332*6a54128fSAndroid Build Coastguard Worker if (inblk >> 32) {
1333*6a54128fSAndroid Build Coastguard Worker com_err(program_name,
1334*6a54128fSAndroid Build Coastguard Worker EOVERFLOW, "%s",
1335*6a54128fSAndroid Build Coastguard Worker _("while adding to in-memory "
1336*6a54128fSAndroid Build Coastguard Worker "bad block list"));
1337*6a54128fSAndroid Build Coastguard Worker exit(1);
1338*6a54128fSAndroid Build Coastguard Worker }
1339*6a54128fSAndroid Build Coastguard Worker next_bad = inblk;
1340*6a54128fSAndroid Build Coastguard Worker errcode = ext2fs_badblocks_list_add(bb_list,next_bad);
1341*6a54128fSAndroid Build Coastguard Worker if (errcode) {
1342*6a54128fSAndroid Build Coastguard Worker com_err(program_name, errcode,
1343*6a54128fSAndroid Build Coastguard Worker "%s",
1344*6a54128fSAndroid Build Coastguard Worker _("while adding to in-memory "
1345*6a54128fSAndroid Build Coastguard Worker "bad block list"));
1346*6a54128fSAndroid Build Coastguard Worker exit (1);
1347*6a54128fSAndroid Build Coastguard Worker }
1348*6a54128fSAndroid Build Coastguard Worker continue;
1349*6a54128fSAndroid Build Coastguard Worker }
1350*6a54128fSAndroid Build Coastguard Worker break;
1351*6a54128fSAndroid Build Coastguard Worker }
1352*6a54128fSAndroid Build Coastguard Worker
1353*6a54128fSAndroid Build Coastguard Worker if (in != stdin)
1354*6a54128fSAndroid Build Coastguard Worker fclose (in);
1355*6a54128fSAndroid Build Coastguard Worker }
1356*6a54128fSAndroid Build Coastguard Worker
1357*6a54128fSAndroid Build Coastguard Worker do {
1358*6a54128fSAndroid Build Coastguard Worker unsigned int bb_count;
1359*6a54128fSAndroid Build Coastguard Worker
1360*6a54128fSAndroid Build Coastguard Worker bb_count = test_func(dev, last_block, (int) block_size,
1361*6a54128fSAndroid Build Coastguard Worker first_block, blocks_at_once);
1362*6a54128fSAndroid Build Coastguard Worker if (bb_count)
1363*6a54128fSAndroid Build Coastguard Worker passes_clean = 0;
1364*6a54128fSAndroid Build Coastguard Worker else
1365*6a54128fSAndroid Build Coastguard Worker ++passes_clean;
1366*6a54128fSAndroid Build Coastguard Worker
1367*6a54128fSAndroid Build Coastguard Worker if (v_flag)
1368*6a54128fSAndroid Build Coastguard Worker fprintf(stderr,
1369*6a54128fSAndroid Build Coastguard Worker _("Pass completed, %u bad blocks found. (%d/%d/%d errors)\n"),
1370*6a54128fSAndroid Build Coastguard Worker bb_count, num_read_errors, num_write_errors, num_corruption_errors);
1371*6a54128fSAndroid Build Coastguard Worker
1372*6a54128fSAndroid Build Coastguard Worker } while (passes_clean < num_passes);
1373*6a54128fSAndroid Build Coastguard Worker
1374*6a54128fSAndroid Build Coastguard Worker close (dev);
1375*6a54128fSAndroid Build Coastguard Worker if (out != stdout)
1376*6a54128fSAndroid Build Coastguard Worker fclose (out);
1377*6a54128fSAndroid Build Coastguard Worker free(t_patts);
1378*6a54128fSAndroid Build Coastguard Worker return 0;
1379*6a54128fSAndroid Build Coastguard Worker }
1380