List block checksums
[btrfs-progs-unstable/devel.git] / cmds-inspect.c
blob0e341e4270f086d33734f1d81b9fc19ab8d73993
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public
4 * License v2 as published by the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 * General Public License for more details.
11 * You should have received a copy of the GNU General Public
12 * License along with this program; if not, write to the
13 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14 * Boston, MA 021110-1307, USA.
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <sys/ioctl.h>
21 #include <errno.h>
22 #include <sys/stat.h>
24 #include "kerncompat.h"
25 #include "ioctl.h"
26 #include "ctree.h"
28 #include "commands.h"
29 #include "btrfs-list.h"
31 static const char * const inspect_cmd_group_usage[] = {
32 "btrfs inspect-internal <command> <args>",
33 NULL
36 static int __ino_to_path_fd(u64 inum, int fd, int verbose, const char *prepend)
38 int ret;
39 int i;
40 struct btrfs_ioctl_ino_path_args ipa;
41 struct btrfs_data_container *fspath;
43 fspath = malloc(4096);
44 if (!fspath)
45 return 1;
47 ipa.inum = inum;
48 ipa.size = 4096;
49 ipa.fspath = (u64)fspath;
51 ret = ioctl(fd, BTRFS_IOC_INO_PATHS, &ipa);
52 if (ret) {
53 printf("ioctl ret=%d, error: %s\n", ret, strerror(errno));
54 goto out;
57 if (verbose)
58 printf("ioctl ret=%d, bytes_left=%lu, bytes_missing=%lu, "
59 "cnt=%d, missed=%d\n", ret,
60 (unsigned long)fspath->bytes_left,
61 (unsigned long)fspath->bytes_missing,
62 fspath->elem_cnt, fspath->elem_missed);
64 for (i = 0; i < fspath->elem_cnt; ++i) {
65 char **str = (char **)fspath->val;
66 str[i] += (unsigned long)fspath->val;
67 if (prepend)
68 printf("%s/%s\n", prepend, str[i]);
69 else
70 printf("%s\n", str[i]);
73 out:
74 free(fspath);
75 return ret;
78 static const char * const cmd_inode_resolve_usage[] = {
79 "btrfs inspect-internal inode-resolve [-v] <inode> <path>",
80 "Get file system paths for the given inode",
81 NULL
84 static int cmd_inode_resolve(int argc, char **argv)
86 int fd;
87 int verbose = 0;
89 optind = 1;
90 while (1) {
91 int c = getopt(argc, argv, "v");
92 if (c < 0)
93 break;
95 switch (c) {
96 case 'v':
97 verbose = 1;
98 break;
99 default:
100 usage(cmd_inode_resolve_usage);
104 if (check_argc_exact(argc - optind, 2))
105 usage(cmd_inode_resolve_usage);
107 fd = open_file_or_dir(argv[optind+1]);
108 if (fd < 0) {
109 fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind+1]);
110 return 12;
113 return __ino_to_path_fd(atoll(argv[optind]), fd, verbose,
114 argv[optind+1]);
117 static const char * const cmd_logical_resolve_usage[] = {
118 "btrfs inspect-internal logical-resolve [-Pv] [-s bufsize] <logical> <path>",
119 "Get file system paths for the given logical address",
120 "-P skip the path resolving and print the inodes instead",
121 "-v verbose mode",
122 "-s bufsize set inode container's size. This is used to increase inode",
123 " container's size in case it is not enough to read all the ",
124 " resolved results. The max value one can set is 64k",
125 NULL
128 static int cmd_logical_resolve(int argc, char **argv)
130 int ret;
131 int fd;
132 int i;
133 int verbose = 0;
134 int getpath = 1;
135 int bytes_left;
136 struct btrfs_ioctl_logical_ino_args loi;
137 struct btrfs_data_container *inodes;
138 u64 size = 4096;
139 char full_path[4096];
140 char *path_ptr;
142 optind = 1;
143 while (1) {
144 int c = getopt(argc, argv, "Pvs:");
145 if (c < 0)
146 break;
148 switch (c) {
149 case 'P':
150 getpath = 0;
151 break;
152 case 'v':
153 verbose = 1;
154 break;
155 case 's':
156 size = atoll(optarg);
157 break;
158 default:
159 usage(cmd_logical_resolve_usage);
163 if (check_argc_exact(argc - optind, 2))
164 usage(cmd_logical_resolve_usage);
166 size = min(size, (u64)64 * 1024);
167 inodes = malloc(size);
168 if (!inodes)
169 return 1;
171 loi.logical = atoll(argv[optind]);
172 loi.size = size;
173 loi.inodes = (u64)inodes;
175 fd = open_file_or_dir(argv[optind+1]);
176 if (fd < 0) {
177 fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind+1]);
178 ret = 12;
179 goto out;
182 ret = ioctl(fd, BTRFS_IOC_LOGICAL_INO, &loi);
183 if (ret) {
184 printf("ioctl ret=%d, error: %s\n", ret, strerror(errno));
185 goto out;
188 if (verbose)
189 printf("ioctl ret=%d, total_size=%llu, bytes_left=%lu, "
190 "bytes_missing=%lu, cnt=%d, missed=%d\n",
191 ret, size,
192 (unsigned long)inodes->bytes_left,
193 (unsigned long)inodes->bytes_missing,
194 inodes->elem_cnt, inodes->elem_missed);
196 bytes_left = sizeof(full_path);
197 ret = snprintf(full_path, bytes_left, "%s/", argv[optind+1]);
198 path_ptr = full_path + ret;
199 bytes_left -= ret + 1;
200 BUG_ON(bytes_left < 0);
202 for (i = 0; i < inodes->elem_cnt; i += 3) {
203 u64 inum = inodes->val[i];
204 u64 offset = inodes->val[i+1];
205 u64 root = inodes->val[i+2];
206 int path_fd;
207 char *name;
209 if (getpath) {
210 name = btrfs_list_path_for_root(fd, root);
211 if (IS_ERR(name))
212 return PTR_ERR(name);
213 if (!name) {
214 path_ptr[-1] = '\0';
215 path_fd = fd;
216 } else {
217 path_ptr[-1] = '/';
218 ret = snprintf(path_ptr, bytes_left, "%s",
219 name);
220 BUG_ON(ret >= bytes_left);
221 free(name);
222 path_fd = open_file_or_dir(full_path);
223 if (path_fd < 0) {
224 fprintf(stderr, "ERROR: can't access "
225 "'%s'\n", full_path);
226 goto out;
229 __ino_to_path_fd(inum, path_fd, verbose, full_path);
230 } else {
231 printf("inode %llu offset %llu root %llu\n", inum,
232 offset, root);
236 out:
237 free(inodes);
238 return ret;
241 static const char * const cmd_bsum_usage[] = {
242 "btrfs inspect-internal _bsum <blockno> <file>",
243 "Get file block checksum of given file",
244 NULL
247 static int csum_for_offset(int fd, u64 offset, u8 *csums, int *count)
249 struct btrfs_ioctl_search_args args;
250 struct btrfs_ioctl_search_key *sk = &args.key;
251 struct btrfs_ioctl_search_header *sh;
252 int ret = 0;
253 int i;
254 unsigned off;
255 u32 *realcsums = (u32*)csums;
257 sk->tree_id = BTRFS_CSUM_TREE_OBJECTID;
258 sk->min_objectid = BTRFS_EXTENT_CSUM_OBJECTID;
259 sk->max_objectid = BTRFS_EXTENT_CSUM_OBJECTID;
260 sk->max_type = BTRFS_EXTENT_CSUM_KEY;
261 sk->min_type = BTRFS_EXTENT_CSUM_KEY;
262 sk->min_offset = offset;
263 sk->max_offset = (u64)-1;
264 sk->max_transid = (u64)-1;
265 sk->nr_items = 1;
267 printf("Search block: %llu\n", (unsigned long long)sk->min_offset);
268 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
269 if (ret) {
270 printf("%s: search ioctl: ioctl ret=%d, error: %s\n", __func__, ret, strerror(errno));
271 ret = -1;
272 goto out;
274 if (sk->nr_items == 0) {
275 printf("no items found\n");
276 ret = -2;
277 goto out;
279 off = 0;
280 *count = 0;
281 for (i = 0; i < sk->nr_items; i++) {
282 u32 item;
283 int j;
284 int csum_size = sizeof(item);
286 sh = (struct btrfs_ioctl_search_header *)(args.buf +
287 off);
289 printf("SH: tid %llu objid %llu off %llu type %u len %u\n",
290 (unsigned long long)sh->transid,
291 (unsigned long long)sh->objectid,
292 (unsigned long long)sh->offset,
293 (unsigned)sh->type,
294 (unsigned)sh->len);
296 off += sizeof(*sh);
297 for (j = 0; j < sh->len / csum_size; j++) {
298 memcpy(&item, args.buf + off + j * csum_size, sizeof(item));
299 printf("DATA[%d]: u32 = 0x%08x\n", j, item);
300 realcsums[*count] = item;
301 *count += 1;
303 off += sh->len;
305 sk->min_objectid = sh->objectid;
306 sk->min_type = sh->type;
307 sk->min_offset = sh->offset;
309 out:
310 return ret;
313 static int extent_offset_to_physical(int fd, u64 ino, u64 offset, u64 *phys)
315 struct btrfs_ioctl_search_args args;
316 struct btrfs_ioctl_search_key *sk = &args.key;
317 struct btrfs_ioctl_search_header *sh;
318 int ret = 0;
319 unsigned off;
320 int i;
322 sk->tree_id = BTRFS_FS_TREE_OBJECTID;
323 sk->min_objectid = ino;
324 sk->max_objectid = ino;
325 sk->max_type = BTRFS_EXTENT_DATA_KEY;
326 sk->min_type = BTRFS_EXTENT_DATA_KEY;
327 sk->min_offset = offset;
328 sk->max_offset = (u64)-1;
329 sk->max_transid = (u64)-1;
330 sk->nr_items = 1;
332 printf("Search extent offset: %llu\n", (unsigned long long)sk->min_offset);
333 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
334 if (ret) {
335 printf("%s: search ioctl: ioctl ret=%d, error: %s\n", __func__, ret, strerror(errno));
336 ret = -1;
337 goto out;
339 if (sk->nr_items == 0) {
340 printf("no items found\n");
341 ret = -2;
342 goto out;
344 off = 0;
345 for (i = 0; i < sk->nr_items; i++) {
346 struct btrfs_file_extent_item fi;
348 sh = (struct btrfs_ioctl_search_header *)(args.buf +
349 off);
351 printf("SH: tid %llu objid %llu off %llu type %u len %u\n",
352 (unsigned long long)sh->transid,
353 (unsigned long long)sh->objectid,
354 (unsigned long long)sh->offset,
355 (unsigned)sh->type,
356 (unsigned)sh->len);
358 off += sizeof(*sh);
359 /* process data */
360 memcpy(&fi, args.buf + off, sizeof(fi));
361 printf("FI: disk_bytenr %llu disk_num_bytes %llu offset %llu\n",
362 (unsigned long long)fi.disk_bytenr,
363 (unsigned long long)fi.disk_num_bytes,
364 (unsigned long long)fi.offset);
365 *phys = fi.disk_bytenr;
367 off += sh->len;
369 sk->min_objectid = sh->objectid;
370 sk->min_type = sh->type;
371 sk->min_offset = sh->offset;
373 out:
374 return ret;
377 static int cmd_bsum(int argc, char **argv)
379 int fd;
380 int ret = 0;
381 int j;
382 struct stat st;
383 u8 csums[4096];
384 int count = 0;
385 u64 offset = 0;
386 u64 phys = 0;
388 optind = 1;
389 while (1) {
390 int c = getopt(argc, argv, "");
391 if (c < 0)
392 break;
394 switch (c) {
395 default:
396 usage(cmd_logical_resolve_usage);
400 if (check_argc_exact(argc - optind, 2)) {
401 usage(cmd_logical_resolve_usage);
402 return 1;
405 fd = open_file_or_dir(argv[optind+1]);
406 if (fd < 0) {
407 fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind+1]);
408 ret = 12;
409 goto out;
411 offset = atoi(argv[optind]);
412 if(fstat(fd, &st) == -1) {
413 fprintf(stderr, "ERROR: stat\n");
414 ret = 1;
415 goto out;
417 printf("Inode: %llu\n", (unsigned long long)st.st_ino);
418 printf("Offset: %llu\n", (unsigned long long)offset);
419 extent_offset_to_physical(fd, st.st_ino, offset, &phys);
420 printf("Physical: %llu\n", (unsigned long long)phys);
421 csum_for_offset(fd, phys, csums, &count);
422 for (j = 0; j < count; j++) {
423 u32 *items = (u32*)csums;
424 printf("BLOCK[%d] CSUM=0x%x\n",
425 j, items[j]);
428 out:
429 return ret;
432 const struct cmd_group inspect_cmd_group = {
433 inspect_cmd_group_usage, NULL, {
434 { "inode-resolve", cmd_inode_resolve, cmd_inode_resolve_usage,
435 NULL, 0 },
436 { "logical-resolve", cmd_logical_resolve,
437 cmd_logical_resolve_usage, NULL, 0 },
438 { "_bsum", cmd_bsum,
439 cmd_bsum_usage, NULL, 0 },
440 { 0, 0, 0, 0, 0 }
444 int cmd_inspect(int argc, char **argv)
446 return handle_command_group(&inspect_cmd_group, argc, argv);