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
21 extern int optind;
22 extern char *optarg;
23 #endif
24 
25 #include "debugfs.h"
26 
do_zap_block(int argc,char * argv[])27 void 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 
164 errout:
165 	free(buf);
166 	return;
167 }
168 
do_block_dump(int argc,char * argv[])169 void 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 
256 errout:
257 	free(buf);
258 	return;
259 }
260