Merge branch 'for-chris' of git://repo.or.cz/btrfs-progs-unstable/devel into raid56
[platform/upstream/btrfs-progs.git] / cmds-inspect.c
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.
5  *
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.
10  *
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.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <stdint.h>
21 #include <sys/ioctl.h>
22 #include <errno.h>
23
24 #include "kerncompat.h"
25 #include "ioctl.h"
26 #include "utils.h"
27
28 #include "commands.h"
29 #include "btrfs-list.h"
30
31 static const char * const inspect_cmd_group_usage[] = {
32         "btrfs inspect-internal <command> <args>",
33         NULL
34 };
35
36 static int __ino_to_path_fd(u64 inum, int fd, int verbose, const char *prepend)
37 {
38         int ret;
39         int i;
40         struct btrfs_ioctl_ino_path_args ipa;
41         struct btrfs_data_container *fspath;
42
43         fspath = malloc(4096);
44         if (!fspath)
45                 return 1;
46
47         ipa.inum = inum;
48         ipa.size = 4096;
49         ipa.fspath = (uintptr_t)fspath;
50
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;
55         }
56
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);
63
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]);
71         }
72
73 out:
74         free(fspath);
75         return ret;
76 }
77
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
82 };
83
84 static int cmd_inode_resolve(int argc, char **argv)
85 {
86         int fd;
87         int verbose = 0;
88
89         optind = 1;
90         while (1) {
91                 int c = getopt(argc, argv, "v");
92                 if (c < 0)
93                         break;
94
95                 switch (c) {
96                 case 'v':
97                         verbose = 1;
98                         break;
99                 default:
100                         usage(cmd_inode_resolve_usage);
101                 }
102         }
103
104         if (check_argc_exact(argc - optind, 2))
105                 usage(cmd_inode_resolve_usage);
106
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;
111         }
112
113         return __ino_to_path_fd(atoll(argv[optind]), fd, verbose,
114                                 argv[optind+1]);
115 }
116
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
126 };
127
128 static int cmd_logical_resolve(int argc, char **argv)
129 {
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;
141
142         optind = 1;
143         while (1) {
144                 int c = getopt(argc, argv, "Pvs:");
145                 if (c < 0)
146                         break;
147
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);
160                 }
161         }
162
163         if (check_argc_exact(argc - optind, 2))
164                 usage(cmd_logical_resolve_usage);
165
166         size = min(size, (u64)64 * 1024);
167         inodes = malloc(size);
168         if (!inodes)
169                 return 1;
170
171         loi.logical = atoll(argv[optind]);
172         loi.size = size;
173         loi.inodes = (uintptr_t)inodes;
174
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;
180         }
181
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;
186         }
187
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);
195
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);
201
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;
208
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;
227                                 }
228                         }
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);
233                 }
234         }
235
236 out:
237         free(inodes);
238         return ret;
239 }
240
241 const struct cmd_group inspect_cmd_group = {
242         inspect_cmd_group_usage, NULL, {
243                 { "inode-resolve", cmd_inode_resolve, cmd_inode_resolve_usage,
244                         NULL, 0 },
245                 { "logical-resolve", cmd_logical_resolve,
246                         cmd_logical_resolve_usage, NULL, 0 },
247                 { 0, 0, 0, 0, 0 }
248         }
249 };
250
251 int cmd_inspect(int argc, char **argv)
252 {
253         return handle_command_group(&inspect_cmd_group, argc, argv);
254 }