xref: /aosp_15_r20/external/e2fsprogs/misc/e2fuzz.c (revision 6a54128f25917bfc36a8a6e9d722c04a0b4641b6)
1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker  * e2fuzz.c -- Fuzz an ext4 image, for testing purposes.
3*6a54128fSAndroid Build Coastguard Worker  *
4*6a54128fSAndroid Build Coastguard Worker  * Copyright (C) 2014 Oracle.
5*6a54128fSAndroid Build Coastguard Worker  *
6*6a54128fSAndroid Build Coastguard Worker  * %Begin-Header%
7*6a54128fSAndroid Build Coastguard Worker  * This file may be redistributed under the terms of the GNU Library
8*6a54128fSAndroid Build Coastguard Worker  * General Public License, version 2.
9*6a54128fSAndroid Build Coastguard Worker  * %End-Header%
10*6a54128fSAndroid Build Coastguard Worker  */
11*6a54128fSAndroid Build Coastguard Worker #define _XOPEN_SOURCE		600
12*6a54128fSAndroid Build Coastguard Worker #define _FILE_OFFSET_BITS       64
13*6a54128fSAndroid Build Coastguard Worker #define _LARGEFILE64_SOURCE     1
14*6a54128fSAndroid Build Coastguard Worker #define _GNU_SOURCE		1
15*6a54128fSAndroid Build Coastguard Worker 
16*6a54128fSAndroid Build Coastguard Worker #include "config.h"
17*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
18*6a54128fSAndroid Build Coastguard Worker #include <sys/stat.h>
19*6a54128fSAndroid Build Coastguard Worker #include <fcntl.h>
20*6a54128fSAndroid Build Coastguard Worker #include <stdint.h>
21*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
22*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_GETOPT_H
23*6a54128fSAndroid Build Coastguard Worker #include <getopt.h>
24*6a54128fSAndroid Build Coastguard Worker #endif
25*6a54128fSAndroid Build Coastguard Worker 
26*6a54128fSAndroid Build Coastguard Worker #include "ext2fs/ext2_fs.h"
27*6a54128fSAndroid Build Coastguard Worker #include "ext2fs/ext2fs.h"
28*6a54128fSAndroid Build Coastguard Worker 
29*6a54128fSAndroid Build Coastguard Worker static int dryrun = 0;
30*6a54128fSAndroid Build Coastguard Worker static int verbose = 0;
31*6a54128fSAndroid Build Coastguard Worker static int metadata_only = 1;
32*6a54128fSAndroid Build Coastguard Worker static unsigned long long user_corrupt_bytes = 0;
33*6a54128fSAndroid Build Coastguard Worker static double user_corrupt_pct = 0.0;
34*6a54128fSAndroid Build Coastguard Worker 
35*6a54128fSAndroid Build Coastguard Worker #if !defined HAVE_PWRITE64 && !defined HAVE_PWRITE
my_pwrite(int fd,const void * buf,size_t count,ext2_loff_t offset)36*6a54128fSAndroid Build Coastguard Worker static ssize_t my_pwrite(int fd, const void *buf, size_t count,
37*6a54128fSAndroid Build Coastguard Worker 			 ext2_loff_t offset)
38*6a54128fSAndroid Build Coastguard Worker {
39*6a54128fSAndroid Build Coastguard Worker 	if (ext2fs_llseek(fd, offset, SEEK_SET) < 0)
40*6a54128fSAndroid Build Coastguard Worker 		return 0;
41*6a54128fSAndroid Build Coastguard Worker 
42*6a54128fSAndroid Build Coastguard Worker 	return write(fd, buf, count);
43*6a54128fSAndroid Build Coastguard Worker }
44*6a54128fSAndroid Build Coastguard Worker #endif /* !defined HAVE_PWRITE64 && !defined HAVE_PWRITE */
45*6a54128fSAndroid Build Coastguard Worker 
getseed(void)46*6a54128fSAndroid Build Coastguard Worker static int getseed(void)
47*6a54128fSAndroid Build Coastguard Worker {
48*6a54128fSAndroid Build Coastguard Worker 	int r;
49*6a54128fSAndroid Build Coastguard Worker 	int fd;
50*6a54128fSAndroid Build Coastguard Worker 
51*6a54128fSAndroid Build Coastguard Worker 	fd = open("/dev/urandom", O_RDONLY);
52*6a54128fSAndroid Build Coastguard Worker 	if (fd < 0) {
53*6a54128fSAndroid Build Coastguard Worker 		perror("open");
54*6a54128fSAndroid Build Coastguard Worker 		exit(0);
55*6a54128fSAndroid Build Coastguard Worker 	}
56*6a54128fSAndroid Build Coastguard Worker 	if (read(fd, &r, sizeof(r)) != sizeof(r))
57*6a54128fSAndroid Build Coastguard Worker 		printf("Unable to read random seed!\n");
58*6a54128fSAndroid Build Coastguard Worker 	close(fd);
59*6a54128fSAndroid Build Coastguard Worker 	return r;
60*6a54128fSAndroid Build Coastguard Worker }
61*6a54128fSAndroid Build Coastguard Worker 
62*6a54128fSAndroid Build Coastguard Worker struct find_block {
63*6a54128fSAndroid Build Coastguard Worker 	ext2_ino_t ino;
64*6a54128fSAndroid Build Coastguard Worker 	ext2fs_block_bitmap bmap;
65*6a54128fSAndroid Build Coastguard Worker 	struct ext2_inode *inode;
66*6a54128fSAndroid Build Coastguard Worker 	blk64_t corrupt_blocks;
67*6a54128fSAndroid Build Coastguard Worker };
68*6a54128fSAndroid Build Coastguard Worker 
find_block_helper(ext2_filsys fs EXT2FS_ATTR ((unused)),blk64_t * blocknr,e2_blkcnt_t blockcnt,blk64_t ref_blk EXT2FS_ATTR ((unused)),int ref_offset EXT2FS_ATTR ((unused)),void * priv_data)69*6a54128fSAndroid Build Coastguard Worker static int find_block_helper(ext2_filsys fs EXT2FS_ATTR((unused)),
70*6a54128fSAndroid Build Coastguard Worker 			     blk64_t *blocknr, e2_blkcnt_t blockcnt,
71*6a54128fSAndroid Build Coastguard Worker 			     blk64_t ref_blk EXT2FS_ATTR((unused)),
72*6a54128fSAndroid Build Coastguard Worker 			     int ref_offset EXT2FS_ATTR((unused)),
73*6a54128fSAndroid Build Coastguard Worker 			     void *priv_data)
74*6a54128fSAndroid Build Coastguard Worker {
75*6a54128fSAndroid Build Coastguard Worker 	struct find_block *fb = (struct find_block *)priv_data;
76*6a54128fSAndroid Build Coastguard Worker 
77*6a54128fSAndroid Build Coastguard Worker 	if (S_ISDIR(fb->inode->i_mode) || !metadata_only || blockcnt < 0) {
78*6a54128fSAndroid Build Coastguard Worker 		ext2fs_mark_block_bitmap2(fb->bmap, *blocknr);
79*6a54128fSAndroid Build Coastguard Worker 		fb->corrupt_blocks++;
80*6a54128fSAndroid Build Coastguard Worker 	}
81*6a54128fSAndroid Build Coastguard Worker 
82*6a54128fSAndroid Build Coastguard Worker 	return 0;
83*6a54128fSAndroid Build Coastguard Worker }
84*6a54128fSAndroid Build Coastguard Worker 
find_metadata_blocks(ext2_filsys fs,ext2fs_block_bitmap bmap,ext2_loff_t * corrupt_bytes)85*6a54128fSAndroid Build Coastguard Worker static errcode_t find_metadata_blocks(ext2_filsys fs, ext2fs_block_bitmap bmap,
86*6a54128fSAndroid Build Coastguard Worker 				      ext2_loff_t *corrupt_bytes)
87*6a54128fSAndroid Build Coastguard Worker {
88*6a54128fSAndroid Build Coastguard Worker 	dgrp_t i;
89*6a54128fSAndroid Build Coastguard Worker 	blk64_t b, c;
90*6a54128fSAndroid Build Coastguard Worker 	ext2_inode_scan scan;
91*6a54128fSAndroid Build Coastguard Worker 	ext2_ino_t ino;
92*6a54128fSAndroid Build Coastguard Worker 	struct ext2_inode inode;
93*6a54128fSAndroid Build Coastguard Worker 	struct find_block fb;
94*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval;
95*6a54128fSAndroid Build Coastguard Worker 
96*6a54128fSAndroid Build Coastguard Worker 	*corrupt_bytes = 0;
97*6a54128fSAndroid Build Coastguard Worker 	fb.corrupt_blocks = 0;
98*6a54128fSAndroid Build Coastguard Worker 
99*6a54128fSAndroid Build Coastguard Worker 	/* Construct bitmaps of super/descriptor blocks */
100*6a54128fSAndroid Build Coastguard Worker 	for (i = 0; i < fs->group_desc_count; i++) {
101*6a54128fSAndroid Build Coastguard Worker 		ext2fs_reserve_super_and_bgd(fs, i, bmap);
102*6a54128fSAndroid Build Coastguard Worker 
103*6a54128fSAndroid Build Coastguard Worker 		/* bitmaps and inode table */
104*6a54128fSAndroid Build Coastguard Worker 		b = ext2fs_block_bitmap_loc(fs, i);
105*6a54128fSAndroid Build Coastguard Worker 		ext2fs_mark_block_bitmap2(bmap, b);
106*6a54128fSAndroid Build Coastguard Worker 		fb.corrupt_blocks++;
107*6a54128fSAndroid Build Coastguard Worker 
108*6a54128fSAndroid Build Coastguard Worker 		b = ext2fs_inode_bitmap_loc(fs, i);
109*6a54128fSAndroid Build Coastguard Worker 		ext2fs_mark_block_bitmap2(bmap, b);
110*6a54128fSAndroid Build Coastguard Worker 		fb.corrupt_blocks++;
111*6a54128fSAndroid Build Coastguard Worker 
112*6a54128fSAndroid Build Coastguard Worker 		c = ext2fs_inode_table_loc(fs, i);
113*6a54128fSAndroid Build Coastguard Worker 		ext2fs_mark_block_bitmap_range2(bmap, c,
114*6a54128fSAndroid Build Coastguard Worker 						fs->inode_blocks_per_group);
115*6a54128fSAndroid Build Coastguard Worker 		fb.corrupt_blocks += fs->inode_blocks_per_group;
116*6a54128fSAndroid Build Coastguard Worker 	}
117*6a54128fSAndroid Build Coastguard Worker 
118*6a54128fSAndroid Build Coastguard Worker 	/* Scan inodes */
119*6a54128fSAndroid Build Coastguard Worker 	fb.bmap = bmap;
120*6a54128fSAndroid Build Coastguard Worker 	fb.inode = &inode;
121*6a54128fSAndroid Build Coastguard Worker 	memset(&inode, 0, sizeof(inode));
122*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_open_inode_scan(fs, 0, &scan);
123*6a54128fSAndroid Build Coastguard Worker 	if (retval)
124*6a54128fSAndroid Build Coastguard Worker 		goto out;
125*6a54128fSAndroid Build Coastguard Worker 
126*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_get_next_inode_full(scan, &ino, &inode, sizeof(inode));
127*6a54128fSAndroid Build Coastguard Worker 	if (retval)
128*6a54128fSAndroid Build Coastguard Worker 		goto out2;
129*6a54128fSAndroid Build Coastguard Worker 	while (ino) {
130*6a54128fSAndroid Build Coastguard Worker 		if (inode.i_links_count == 0)
131*6a54128fSAndroid Build Coastguard Worker 			goto next_loop;
132*6a54128fSAndroid Build Coastguard Worker 
133*6a54128fSAndroid Build Coastguard Worker 		b = ext2fs_file_acl_block(fs, &inode);
134*6a54128fSAndroid Build Coastguard Worker 		if (b) {
135*6a54128fSAndroid Build Coastguard Worker 			ext2fs_mark_block_bitmap2(bmap, b);
136*6a54128fSAndroid Build Coastguard Worker 			fb.corrupt_blocks++;
137*6a54128fSAndroid Build Coastguard Worker 		}
138*6a54128fSAndroid Build Coastguard Worker 
139*6a54128fSAndroid Build Coastguard Worker 		/*
140*6a54128fSAndroid Build Coastguard Worker 		 * Inline data, sockets, devices, and symlinks have
141*6a54128fSAndroid Build Coastguard Worker 		 * no blocks to iterate.
142*6a54128fSAndroid Build Coastguard Worker 		 */
143*6a54128fSAndroid Build Coastguard Worker 		if ((inode.i_flags & EXT4_INLINE_DATA_FL) ||
144*6a54128fSAndroid Build Coastguard Worker 		    S_ISLNK(inode.i_mode) || S_ISFIFO(inode.i_mode) ||
145*6a54128fSAndroid Build Coastguard Worker 		    S_ISCHR(inode.i_mode) || S_ISBLK(inode.i_mode) ||
146*6a54128fSAndroid Build Coastguard Worker 		    S_ISSOCK(inode.i_mode))
147*6a54128fSAndroid Build Coastguard Worker 			goto next_loop;
148*6a54128fSAndroid Build Coastguard Worker 		fb.ino = ino;
149*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_block_iterate3(fs, ino, BLOCK_FLAG_READ_ONLY,
150*6a54128fSAndroid Build Coastguard Worker 					       NULL, find_block_helper, &fb);
151*6a54128fSAndroid Build Coastguard Worker 		if (retval)
152*6a54128fSAndroid Build Coastguard Worker 			goto out2;
153*6a54128fSAndroid Build Coastguard Worker next_loop:
154*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_get_next_inode_full(scan, &ino, &inode,
155*6a54128fSAndroid Build Coastguard Worker 						    sizeof(inode));
156*6a54128fSAndroid Build Coastguard Worker 		if (retval)
157*6a54128fSAndroid Build Coastguard Worker 			goto out2;
158*6a54128fSAndroid Build Coastguard Worker 	}
159*6a54128fSAndroid Build Coastguard Worker out2:
160*6a54128fSAndroid Build Coastguard Worker 	ext2fs_close_inode_scan(scan);
161*6a54128fSAndroid Build Coastguard Worker out:
162*6a54128fSAndroid Build Coastguard Worker 	if (!retval)
163*6a54128fSAndroid Build Coastguard Worker 		*corrupt_bytes = fb.corrupt_blocks * fs->blocksize;
164*6a54128fSAndroid Build Coastguard Worker 	return retval;
165*6a54128fSAndroid Build Coastguard Worker }
166*6a54128fSAndroid Build Coastguard Worker 
rand_num(uint64_t min,uint64_t max)167*6a54128fSAndroid Build Coastguard Worker static uint64_t rand_num(uint64_t min, uint64_t max)
168*6a54128fSAndroid Build Coastguard Worker {
169*6a54128fSAndroid Build Coastguard Worker 	uint64_t x;
170*6a54128fSAndroid Build Coastguard Worker 	unsigned int i;
171*6a54128fSAndroid Build Coastguard Worker 	uint8_t *px = (uint8_t *)&x;
172*6a54128fSAndroid Build Coastguard Worker 
173*6a54128fSAndroid Build Coastguard Worker 	for (i = 0; i < sizeof(x); i++)
174*6a54128fSAndroid Build Coastguard Worker 		px[i] = random();
175*6a54128fSAndroid Build Coastguard Worker 
176*6a54128fSAndroid Build Coastguard Worker 	return min + (uint64_t)((double)(max - min) *
177*6a54128fSAndroid Build Coastguard Worker 				(x / ((double) UINT64_MAX + 1.0)));
178*6a54128fSAndroid Build Coastguard Worker }
179*6a54128fSAndroid Build Coastguard Worker 
process_fs(const char * fsname)180*6a54128fSAndroid Build Coastguard Worker static int process_fs(const char *fsname)
181*6a54128fSAndroid Build Coastguard Worker {
182*6a54128fSAndroid Build Coastguard Worker 	errcode_t ret;
183*6a54128fSAndroid Build Coastguard Worker 	int flags, fd;
184*6a54128fSAndroid Build Coastguard Worker 	ext2_filsys fs = NULL;
185*6a54128fSAndroid Build Coastguard Worker 	ext2fs_block_bitmap corrupt_map;
186*6a54128fSAndroid Build Coastguard Worker 	ext2_loff_t hsize, count, off, offset, corrupt_bytes, i;
187*6a54128fSAndroid Build Coastguard Worker 	unsigned char c;
188*6a54128fSAndroid Build Coastguard Worker 
189*6a54128fSAndroid Build Coastguard Worker 	/* If mounted rw, force dryrun mode */
190*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_check_if_mounted(fsname, &flags);
191*6a54128fSAndroid Build Coastguard Worker 	if (ret) {
192*6a54128fSAndroid Build Coastguard Worker 		fprintf(stderr, "%s: failed to determine filesystem mount "
193*6a54128fSAndroid Build Coastguard Worker 			"state.\n", fsname);
194*6a54128fSAndroid Build Coastguard Worker 		return 1;
195*6a54128fSAndroid Build Coastguard Worker 	}
196*6a54128fSAndroid Build Coastguard Worker 
197*6a54128fSAndroid Build Coastguard Worker 	if (!dryrun && (flags & EXT2_MF_MOUNTED) &&
198*6a54128fSAndroid Build Coastguard Worker 	    !(flags & EXT2_MF_READONLY)) {
199*6a54128fSAndroid Build Coastguard Worker 		fprintf(stderr, "%s: is mounted rw, performing dry run.\n",
200*6a54128fSAndroid Build Coastguard Worker 			fsname);
201*6a54128fSAndroid Build Coastguard Worker 		dryrun = 1;
202*6a54128fSAndroid Build Coastguard Worker 	}
203*6a54128fSAndroid Build Coastguard Worker 
204*6a54128fSAndroid Build Coastguard Worker 	/* Ensure the fs is clean and does not have errors */
205*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_open(fsname, EXT2_FLAG_64BITS | EXT2_FLAG_THREADS,
206*6a54128fSAndroid Build Coastguard Worker 			  0, 0, unix_io_manager, &fs);
207*6a54128fSAndroid Build Coastguard Worker 	if (ret) {
208*6a54128fSAndroid Build Coastguard Worker 		fprintf(stderr, "%s: failed to open filesystem.\n",
209*6a54128fSAndroid Build Coastguard Worker 			fsname);
210*6a54128fSAndroid Build Coastguard Worker 		return 1;
211*6a54128fSAndroid Build Coastguard Worker 	}
212*6a54128fSAndroid Build Coastguard Worker 
213*6a54128fSAndroid Build Coastguard Worker 	if ((fs->super->s_state & EXT2_ERROR_FS)) {
214*6a54128fSAndroid Build Coastguard Worker 		fprintf(stderr, "%s: errors detected, run fsck.\n",
215*6a54128fSAndroid Build Coastguard Worker 			fsname);
216*6a54128fSAndroid Build Coastguard Worker 		goto fail;
217*6a54128fSAndroid Build Coastguard Worker 	}
218*6a54128fSAndroid Build Coastguard Worker 
219*6a54128fSAndroid Build Coastguard Worker 	if (!dryrun && (fs->super->s_state & EXT2_VALID_FS) == 0) {
220*6a54128fSAndroid Build Coastguard Worker 		fprintf(stderr, "%s: unclean shutdown, performing dry run.\n",
221*6a54128fSAndroid Build Coastguard Worker 			fsname);
222*6a54128fSAndroid Build Coastguard Worker 		dryrun = 1;
223*6a54128fSAndroid Build Coastguard Worker 	}
224*6a54128fSAndroid Build Coastguard Worker 
225*6a54128fSAndroid Build Coastguard Worker 	/* Construct a bitmap of whatever we're corrupting */
226*6a54128fSAndroid Build Coastguard Worker 	if (!metadata_only) {
227*6a54128fSAndroid Build Coastguard Worker 		/* Load block bitmap */
228*6a54128fSAndroid Build Coastguard Worker 		ret = ext2fs_read_block_bitmap(fs);
229*6a54128fSAndroid Build Coastguard Worker 		if (ret) {
230*6a54128fSAndroid Build Coastguard Worker 			fprintf(stderr, "%s: error while reading block bitmap\n",
231*6a54128fSAndroid Build Coastguard Worker 				fsname);
232*6a54128fSAndroid Build Coastguard Worker 			goto fail;
233*6a54128fSAndroid Build Coastguard Worker 		}
234*6a54128fSAndroid Build Coastguard Worker 		corrupt_map = fs->block_map;
235*6a54128fSAndroid Build Coastguard Worker 		corrupt_bytes = (ext2fs_blocks_count(fs->super) -
236*6a54128fSAndroid Build Coastguard Worker 				 ext2fs_free_blocks_count(fs->super)) *
237*6a54128fSAndroid Build Coastguard Worker 				fs->blocksize;
238*6a54128fSAndroid Build Coastguard Worker 	} else {
239*6a54128fSAndroid Build Coastguard Worker 		ret = ext2fs_allocate_block_bitmap(fs, "metadata block map",
240*6a54128fSAndroid Build Coastguard Worker 						   &corrupt_map);
241*6a54128fSAndroid Build Coastguard Worker 		if (ret) {
242*6a54128fSAndroid Build Coastguard Worker 			fprintf(stderr, "%s: unable to create block bitmap\n",
243*6a54128fSAndroid Build Coastguard Worker 				fsname);
244*6a54128fSAndroid Build Coastguard Worker 			goto fail;
245*6a54128fSAndroid Build Coastguard Worker 		}
246*6a54128fSAndroid Build Coastguard Worker 
247*6a54128fSAndroid Build Coastguard Worker 		/* Iterate everything... */
248*6a54128fSAndroid Build Coastguard Worker 		ret = find_metadata_blocks(fs, corrupt_map, &corrupt_bytes);
249*6a54128fSAndroid Build Coastguard Worker 		if (ret) {
250*6a54128fSAndroid Build Coastguard Worker 			fprintf(stderr, "%s: while finding metadata\n",
251*6a54128fSAndroid Build Coastguard Worker 				fsname);
252*6a54128fSAndroid Build Coastguard Worker 			goto fail;
253*6a54128fSAndroid Build Coastguard Worker 		}
254*6a54128fSAndroid Build Coastguard Worker 	}
255*6a54128fSAndroid Build Coastguard Worker 
256*6a54128fSAndroid Build Coastguard Worker 	/* Run around corrupting things */
257*6a54128fSAndroid Build Coastguard Worker 	fd = open(fsname, O_RDWR);
258*6a54128fSAndroid Build Coastguard Worker 	if (fd < 0) {
259*6a54128fSAndroid Build Coastguard Worker 		perror(fsname);
260*6a54128fSAndroid Build Coastguard Worker 		goto fail;
261*6a54128fSAndroid Build Coastguard Worker 	}
262*6a54128fSAndroid Build Coastguard Worker 	srandom(getseed());
263*6a54128fSAndroid Build Coastguard Worker 	hsize = fs->blocksize * ext2fs_blocks_count(fs->super);
264*6a54128fSAndroid Build Coastguard Worker 	if (user_corrupt_bytes > 0)
265*6a54128fSAndroid Build Coastguard Worker 		count = user_corrupt_bytes;
266*6a54128fSAndroid Build Coastguard Worker 	else if (user_corrupt_pct > 0.0)
267*6a54128fSAndroid Build Coastguard Worker 		count = user_corrupt_pct * corrupt_bytes / 100;
268*6a54128fSAndroid Build Coastguard Worker 	else
269*6a54128fSAndroid Build Coastguard Worker 		count = rand_num(0, corrupt_bytes / 100);
270*6a54128fSAndroid Build Coastguard Worker 	offset = 4096; /* never corrupt superblock */
271*6a54128fSAndroid Build Coastguard Worker 	for (i = 0; i < count; i++) {
272*6a54128fSAndroid Build Coastguard Worker 		do
273*6a54128fSAndroid Build Coastguard Worker 			off = rand_num(offset, hsize);
274*6a54128fSAndroid Build Coastguard Worker 		while (!ext2fs_test_block_bitmap2(corrupt_map,
275*6a54128fSAndroid Build Coastguard Worker 						    off / fs->blocksize));
276*6a54128fSAndroid Build Coastguard Worker 		c = rand() % 256;
277*6a54128fSAndroid Build Coastguard Worker 		if ((rand() % 2) && c < 128)
278*6a54128fSAndroid Build Coastguard Worker 			c |= 0x80;
279*6a54128fSAndroid Build Coastguard Worker 		if (verbose)
280*6a54128fSAndroid Build Coastguard Worker 			printf("Corrupting byte %lld in block %lld to 0x%x\n",
281*6a54128fSAndroid Build Coastguard Worker 			       off % fs->blocksize,
282*6a54128fSAndroid Build Coastguard Worker 			       off / fs->blocksize, c);
283*6a54128fSAndroid Build Coastguard Worker 		if (dryrun)
284*6a54128fSAndroid Build Coastguard Worker 			continue;
285*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_PWRITE64
286*6a54128fSAndroid Build Coastguard Worker 		if (pwrite64(fd, &c, sizeof(c), off) != sizeof(c)) {
287*6a54128fSAndroid Build Coastguard Worker 			perror(fsname);
288*6a54128fSAndroid Build Coastguard Worker 			goto fail3;
289*6a54128fSAndroid Build Coastguard Worker 		}
290*6a54128fSAndroid Build Coastguard Worker #elif HAVE_PWRITE
291*6a54128fSAndroid Build Coastguard Worker 		if (pwrite(fd, &c, sizeof(c), off) != sizeof(c)) {
292*6a54128fSAndroid Build Coastguard Worker 			perror(fsname);
293*6a54128fSAndroid Build Coastguard Worker 			goto fail3;
294*6a54128fSAndroid Build Coastguard Worker 		}
295*6a54128fSAndroid Build Coastguard Worker #else
296*6a54128fSAndroid Build Coastguard Worker 		if (my_pwrite(fd, &c, sizeof(c), off) != sizeof(c)) {
297*6a54128fSAndroid Build Coastguard Worker 			perror(fsname);
298*6a54128fSAndroid Build Coastguard Worker 			goto fail3;
299*6a54128fSAndroid Build Coastguard Worker 		}
300*6a54128fSAndroid Build Coastguard Worker #endif
301*6a54128fSAndroid Build Coastguard Worker 	}
302*6a54128fSAndroid Build Coastguard Worker 	close(fd);
303*6a54128fSAndroid Build Coastguard Worker 
304*6a54128fSAndroid Build Coastguard Worker 	/* Clean up */
305*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_close_free(&fs);
306*6a54128fSAndroid Build Coastguard Worker 	if (ret) {
307*6a54128fSAndroid Build Coastguard Worker 		fprintf(stderr, "%s: error while closing filesystem\n",
308*6a54128fSAndroid Build Coastguard Worker 			fsname);
309*6a54128fSAndroid Build Coastguard Worker 		return 1;
310*6a54128fSAndroid Build Coastguard Worker 	}
311*6a54128fSAndroid Build Coastguard Worker 
312*6a54128fSAndroid Build Coastguard Worker 	return 0;
313*6a54128fSAndroid Build Coastguard Worker fail3:
314*6a54128fSAndroid Build Coastguard Worker 	close(fd);
315*6a54128fSAndroid Build Coastguard Worker 	if (corrupt_map != fs->block_map)
316*6a54128fSAndroid Build Coastguard Worker 		ext2fs_free_block_bitmap(corrupt_map);
317*6a54128fSAndroid Build Coastguard Worker fail:
318*6a54128fSAndroid Build Coastguard Worker 	ext2fs_close_free(&fs);
319*6a54128fSAndroid Build Coastguard Worker 	return 1;
320*6a54128fSAndroid Build Coastguard Worker }
321*6a54128fSAndroid Build Coastguard Worker 
print_help(const char * progname)322*6a54128fSAndroid Build Coastguard Worker static void print_help(const char *progname)
323*6a54128fSAndroid Build Coastguard Worker {
324*6a54128fSAndroid Build Coastguard Worker 	printf("Usage: %s OPTIONS device\n", progname);
325*6a54128fSAndroid Build Coastguard Worker 	printf("-b:	Corrupt this many bytes.\n");
326*6a54128fSAndroid Build Coastguard Worker 	printf("-d:	Fuzz data blocks too.\n");
327*6a54128fSAndroid Build Coastguard Worker 	printf("-n:	Dry run only.\n");
328*6a54128fSAndroid Build Coastguard Worker 	printf("-v:	Verbose output.\n");
329*6a54128fSAndroid Build Coastguard Worker 	exit(0);
330*6a54128fSAndroid Build Coastguard Worker }
331*6a54128fSAndroid Build Coastguard Worker 
main(int argc,char * argv[])332*6a54128fSAndroid Build Coastguard Worker int main(int argc, char *argv[])
333*6a54128fSAndroid Build Coastguard Worker {
334*6a54128fSAndroid Build Coastguard Worker 	int c;
335*6a54128fSAndroid Build Coastguard Worker 
336*6a54128fSAndroid Build Coastguard Worker 	while ((c = getopt(argc, argv, "b:dnv")) != -1) {
337*6a54128fSAndroid Build Coastguard Worker 		switch (c) {
338*6a54128fSAndroid Build Coastguard Worker 		case 'b':
339*6a54128fSAndroid Build Coastguard Worker 			if (optarg[strlen(optarg) - 1] == '%') {
340*6a54128fSAndroid Build Coastguard Worker 				user_corrupt_pct = strtod(optarg, NULL);
341*6a54128fSAndroid Build Coastguard Worker 				if (user_corrupt_pct > 100 ||
342*6a54128fSAndroid Build Coastguard Worker 				    user_corrupt_pct < 0) {
343*6a54128fSAndroid Build Coastguard Worker 					fprintf(stderr, "%s: Invalid percentage.\n",
344*6a54128fSAndroid Build Coastguard Worker 						optarg);
345*6a54128fSAndroid Build Coastguard Worker 					return 1;
346*6a54128fSAndroid Build Coastguard Worker 				}
347*6a54128fSAndroid Build Coastguard Worker 			} else
348*6a54128fSAndroid Build Coastguard Worker 				user_corrupt_bytes = strtoull(optarg, NULL, 0);
349*6a54128fSAndroid Build Coastguard Worker 			if (errno) {
350*6a54128fSAndroid Build Coastguard Worker 				perror(optarg);
351*6a54128fSAndroid Build Coastguard Worker 				return 1;
352*6a54128fSAndroid Build Coastguard Worker 			}
353*6a54128fSAndroid Build Coastguard Worker 			break;
354*6a54128fSAndroid Build Coastguard Worker 		case 'd':
355*6a54128fSAndroid Build Coastguard Worker 			metadata_only = 0;
356*6a54128fSAndroid Build Coastguard Worker 			break;
357*6a54128fSAndroid Build Coastguard Worker 		case 'n':
358*6a54128fSAndroid Build Coastguard Worker 			dryrun = 1;
359*6a54128fSAndroid Build Coastguard Worker 			break;
360*6a54128fSAndroid Build Coastguard Worker 		case 'v':
361*6a54128fSAndroid Build Coastguard Worker 			verbose = 1;
362*6a54128fSAndroid Build Coastguard Worker 			break;
363*6a54128fSAndroid Build Coastguard Worker 		default:
364*6a54128fSAndroid Build Coastguard Worker 			print_help(argv[0]);
365*6a54128fSAndroid Build Coastguard Worker 		}
366*6a54128fSAndroid Build Coastguard Worker 	}
367*6a54128fSAndroid Build Coastguard Worker 
368*6a54128fSAndroid Build Coastguard Worker 	for (c = optind; c < argc; c++)
369*6a54128fSAndroid Build Coastguard Worker 		if (process_fs(argv[c]))
370*6a54128fSAndroid Build Coastguard Worker 			return 1;
371*6a54128fSAndroid Build Coastguard Worker 	return 0;
372*6a54128fSAndroid Build Coastguard Worker }
373