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