Btrfs-progs: allow multi-line command group synopsis
[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 <sys/ioctl.h>
21 #include <errno.h>
22
23 #include "kerncompat.h"
24 #include "ioctl.h"
25
26 #include "commands.h"
27
28 /* btrfs-list.c */
29 char *path_for_root(int fd, u64 root);
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 = (u64)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] <logical> <path>",
119         "Get file system paths for the given logical address",
120         NULL
121 };
122
123 static int cmd_logical_resolve(int argc, char **argv)
124 {
125         int ret;
126         int fd;
127         int i;
128         int verbose = 0;
129         int getpath = 1;
130         int bytes_left;
131         struct btrfs_ioctl_logical_ino_args loi;
132         struct btrfs_data_container *inodes;
133         char full_path[4096];
134         char *path_ptr;
135
136         optind = 1;
137         while (1) {
138                 int c = getopt(argc, argv, "Pv");
139                 if (c < 0)
140                         break;
141
142                 switch (c) {
143                 case 'P':
144                         getpath = 0;
145                         break;
146                 case 'v':
147                         verbose = 1;
148                         break;
149                 default:
150                         usage(cmd_logical_resolve_usage);
151                 }
152         }
153
154         if (check_argc_exact(argc - optind, 2))
155                 usage(cmd_logical_resolve_usage);
156
157         inodes = malloc(4096);
158         if (!inodes)
159                 return 1;
160
161         loi.logical = atoll(argv[optind]);
162         loi.size = 4096;
163         loi.inodes = (u64)inodes;
164
165         fd = open_file_or_dir(argv[optind+1]);
166         if (fd < 0) {
167                 fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind+1]);
168                 ret = 12;
169                 goto out;
170         }
171
172         ret = ioctl(fd, BTRFS_IOC_LOGICAL_INO, &loi);
173         if (ret) {
174                 printf("ioctl ret=%d, error: %s\n", ret, strerror(errno));
175                 goto out;
176         }
177
178         if (verbose)
179                 printf("ioctl ret=%d, bytes_left=%lu, bytes_missing=%lu, "
180                         "cnt=%d, missed=%d\n", ret,
181                         (unsigned long)inodes->bytes_left,
182                         (unsigned long)inodes->bytes_missing,
183                         inodes->elem_cnt, inodes->elem_missed);
184
185         bytes_left = sizeof(full_path);
186         ret = snprintf(full_path, bytes_left, "%s/", argv[optind+1]);
187         path_ptr = full_path + ret;
188         bytes_left -= ret + 1;
189         BUG_ON(bytes_left < 0);
190
191         for (i = 0; i < inodes->elem_cnt; i += 3) {
192                 u64 inum = inodes->val[i];
193                 u64 offset = inodes->val[i+1];
194                 u64 root = inodes->val[i+2];
195                 int path_fd;
196                 char *name;
197
198                 if (getpath) {
199                         name = path_for_root(fd, root);
200                         if (IS_ERR(name))
201                                 return PTR_ERR(name);
202                         if (!name) {
203                                 path_ptr[-1] = '\0';
204                                 path_fd = fd;
205                         } else {
206                                 path_ptr[-1] = '/';
207                                 ret = snprintf(path_ptr, bytes_left, "%s",
208                                                 name);
209                                 BUG_ON(ret >= bytes_left);
210                                 free(name);
211                                 path_fd = open_file_or_dir(full_path);
212                                 if (path_fd < 0) {
213                                         fprintf(stderr, "ERROR: can't access "
214                                                 "'%s'\n", full_path);
215                                         goto out;
216                                 }
217                         }
218                         __ino_to_path_fd(inum, path_fd, verbose, full_path);
219                 } else {
220                         printf("inode %llu offset %llu root %llu\n", inum,
221                                 offset, root);
222                 }
223         }
224
225 out:
226         free(inodes);
227         return ret;
228 }
229
230 const struct cmd_group inspect_cmd_group = {
231         inspect_cmd_group_usage, NULL, {
232                 { "inode-resolve", cmd_inode_resolve, cmd_inode_resolve_usage,
233                         NULL, 0 },
234                 { "logical-resolve", cmd_logical_resolve,
235                         cmd_logical_resolve_usage, NULL, 0 },
236                 { 0, 0, 0, 0, 0 }
237         }
238 };
239
240 int cmd_inspect(int argc, char **argv)
241 {
242         return handle_command_group(&inspect_cmd_group, argc, argv);
243 }