1/*
2 * zap.c --- zap block
3 *
4 * Copyright (C) 2012 Theodore Ts'o.  This file may be redistributed
5 * under the terms of the GNU Public License.
6 */
7
8#include <stdio.h>
9#include <unistd.h>
10#include <stdlib.h>
11#include <ctype.h>
12#include <string.h>
13#include <time.h>
14#ifdef HAVE_ERRNO_H
15#include <errno.h>
16#endif
17#include <sys/types.h>
18#ifdef HAVE_GETOPT_H
19#include <getopt.h>
20#else
21extern int optind;
22extern char *optarg;
23#endif
24
25#include "debugfs.h"
26
27void do_zap_block(int argc, char *argv[])
28{
29	unsigned long	pattern = 0;
30	unsigned char	*buf;
31	ext2_ino_t	inode;
32	errcode_t	errcode;
33	blk64_t		block;
34	char		*file = NULL;
35	int		c, err;
36	int		offset = -1;
37	int		length = -1;
38	int		bit = -1;
39
40	if (check_fs_open(argv[0]))
41		return;
42	if (check_fs_read_write(argv[0]))
43		return;
44
45	reset_getopt();
46	while ((c = getopt (argc, argv, "b:f:l:o:p:")) != EOF) {
47		switch (c) {
48		case 'f':
49			file = optarg;
50			break;
51		case 'b':
52			bit = parse_ulong(optarg, argv[0],
53					  "bit", &err);
54			if (err)
55				return;
56			if (bit >= (int) current_fs->blocksize * 8) {
57				com_err(argv[0], 0, "The bit to flip "
58					"must be within a %d block\n",
59					current_fs->blocksize);
60				return;
61			}
62			break;
63		case 'p':
64			pattern = parse_ulong(optarg, argv[0],
65					      "pattern", &err);
66			if (err)
67				return;
68			if (pattern >= 256) {
69				com_err(argv[0], 0, "The fill pattern must "
70					"be an 8-bit value\n");
71				return;
72			}
73			break;
74		case 'o':
75			offset = parse_ulong(optarg, argv[0],
76					     "offset", &err);
77			if (err)
78				return;
79			if (offset >= (int) current_fs->blocksize) {
80				com_err(argv[0], 0, "The offset must be "
81					"within a %d block\n",
82					current_fs->blocksize);
83				return;
84			}
85			break;
86
87			break;
88		case 'l':
89			length = parse_ulong(optarg, argv[0],
90					     "length", &err);
91			if (err)
92				return;
93			break;
94		default:
95			goto print_usage;
96		}
97	}
98
99	if (bit > 0 && offset > 0) {
100		com_err(argv[0], 0, "The -o and -b options can not be mixed.");
101		return;
102	}
103
104	if (offset < 0)
105		offset = 0;
106	if (length < 0)
107		length = current_fs->blocksize - offset;
108	if ((offset + length) > (int) current_fs->blocksize) {
109		com_err(argv[0], 0, "The specified length is too bug\n");
110		return;
111	}
112
113	if (argc != optind+1) {
114	print_usage:
115		com_err(0, 0, "Usage:\tzap_block [-f file] [-o offset] "
116			"[-l length] [-p pattern] block_num");
117		com_err(0, 0, "\tzap_block [-f file] [-b bit] "
118			"block_num");
119		return;
120	}
121
122	block = parse_ulonglong(argv[optind], argv[0], "block", &err);
123	if (err)
124		return;
125
126	if (file) {
127		inode = string_to_inode(file);
128		if (!inode)
129			return;
130		errcode = ext2fs_bmap2(current_fs, inode, 0, 0, 0,
131				       block, 0, &block);
132		if (errcode) {
133			com_err(argv[0], errcode,
134				"while mapping logical block %llu\n", block);
135			return;
136		}
137	}
138
139	buf = malloc(current_fs->blocksize);
140	if (!buf) {
141		com_err(argv[0], 0, "Couldn't allocate block buffer");
142		return;
143	}
144
145	errcode = io_channel_read_blk64(current_fs->io, block, 1, buf);
146	if (errcode) {
147		com_err(argv[0], errcode,
148			"while reading block %llu\n", block);
149		goto errout;
150	}
151
152	if (bit >= 0)
153		buf[bit >> 3] ^= 1 << (bit & 7);
154	else
155		memset(buf+offset, pattern, length);
156
157	errcode = io_channel_write_blk64(current_fs->io, block, 1, buf);
158	if (errcode) {
159		com_err(argv[0], errcode,
160			"while write block %llu\n", block);
161		goto errout;
162	}
163
164errout:
165	free(buf);
166	return;
167}
168
169void do_block_dump(int argc, char *argv[])
170{
171	unsigned char	*buf;
172	ext2_ino_t	inode;
173	errcode_t	errcode;
174	blk64_t		block;
175	char		*file = NULL;
176	unsigned int	i, j;
177	int		c, err;
178	int		suppress = -1;
179
180	if (check_fs_open(argv[0]))
181		return;
182
183	reset_getopt();
184	while ((c = getopt (argc, argv, "f:")) != EOF) {
185		switch (c) {
186		case 'f':
187			file = optarg;
188			break;
189
190		default:
191			goto print_usage;
192		}
193	}
194
195	if (argc != optind + 1) {
196	print_usage:
197		com_err(0, 0, "Usage: block_dump [-f inode] block_num");
198		return;
199	}
200
201	block = parse_ulonglong(argv[optind], argv[0], "block", &err);
202	if (err)
203		return;
204
205	if (file) {
206		inode = string_to_inode(file);
207		if (!inode)
208			return;
209		errcode = ext2fs_bmap2(current_fs, inode, 0, 0, 0,
210				       block, 0, &block);
211		if (errcode) {
212			com_err(argv[0], errcode,
213				"while mapping logical block %llu\n", block);
214			return;
215		}
216	}
217
218	buf = malloc(current_fs->blocksize);
219	if (!buf) {
220		com_err(argv[0], 0, "Couldn't allocate block buffer");
221		return;
222	}
223
224	errcode = io_channel_read_blk64(current_fs->io, block, 1, buf);
225	if (errcode) {
226		com_err(argv[0], errcode,
227			"while reading block %llu\n", block);
228		goto errout;
229	}
230
231	for (i=0; i < current_fs->blocksize; i += 16) {
232		if (suppress < 0) {
233			if (i && memcmp(buf + i, buf + i - 16, 16) == 0) {
234				suppress = i;
235				printf("*\n");
236				continue;
237			}
238		} else {
239			if (memcmp(buf + i, buf + suppress, 16) == 0)
240				continue;
241			suppress = -1;
242		}
243		printf("%04o  ", i);
244		for (j = 0; j < 16; j++) {
245			printf("%02x", buf[i+j]);
246			if ((j % 2) == 1)
247				putchar(' ');
248		}
249		putchar(' ');
250		for (j = 0; j < 16; j++)
251			printf("%c", isprint(buf[i+j]) ? buf[i+j] : '.');
252		putchar('\n');
253	}
254	putchar('\n');
255
256errout:
257	free(buf);
258	return;
259}
260