btrfs-progs: fix fd leak in cmd_subvol_set_default
[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         memset(fspath, 0, sizeof(*fspath));
48         ipa.inum = inum;
49         ipa.size = 4096;
50         ipa.fspath = (uintptr_t)fspath;
51
52         ret = ioctl(fd, BTRFS_IOC_INO_PATHS, &ipa);
53         if (ret) {
54                 printf("ioctl ret=%d, error: %s\n", ret, strerror(errno));
55                 goto out;
56         }
57
58         if (verbose)
59                 printf("ioctl ret=%d, bytes_left=%lu, bytes_missing=%lu, "
60                         "cnt=%d, missed=%d\n", ret,
61                         (unsigned long)fspath->bytes_left,
62                         (unsigned long)fspath->bytes_missing,
63                         fspath->elem_cnt, fspath->elem_missed);
64
65         for (i = 0; i < fspath->elem_cnt; ++i) {
66                 u64 ptr;
67                 char *str;
68                 ptr = (u64)(unsigned long)fspath->val;
69                 ptr += fspath->val[i];
70                 str = (char *)(unsigned long)ptr;
71                 if (prepend)
72                         printf("%s/%s\n", prepend, str);
73                 else
74                         printf("%s\n", str);
75         }
76
77 out:
78         free(fspath);
79         return ret;
80 }
81
82 static const char * const cmd_inode_resolve_usage[] = {
83         "btrfs inspect-internal inode-resolve [-v] <inode> <path>",
84         "Get file system paths for the given inode",
85         NULL
86 };
87
88 static int cmd_inode_resolve(int argc, char **argv)
89 {
90         int fd;
91         int verbose = 0;
92         int ret;
93
94         optind = 1;
95         while (1) {
96                 int c = getopt(argc, argv, "v");
97                 if (c < 0)
98                         break;
99
100                 switch (c) {
101                 case 'v':
102                         verbose = 1;
103                         break;
104                 default:
105                         usage(cmd_inode_resolve_usage);
106                 }
107         }
108
109         if (check_argc_exact(argc - optind, 2))
110                 usage(cmd_inode_resolve_usage);
111
112         fd = open_file_or_dir(argv[optind+1]);
113         if (fd < 0) {
114                 fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind+1]);
115                 return 12;
116         }
117
118         ret = __ino_to_path_fd(atoll(argv[optind]), fd, verbose,
119                                argv[optind+1]);
120         close(fd);
121         return ret;
122
123 }
124
125 static const char * const cmd_logical_resolve_usage[] = {
126         "btrfs inspect-internal logical-resolve [-Pv] [-s bufsize] <logical> <path>",
127         "Get file system paths for the given logical address",
128         "-P          skip the path resolving and print the inodes instead",
129         "-v          verbose mode",
130         "-s bufsize  set inode container's size. This is used to increase inode",
131         "            container's size in case it is not enough to read all the ",
132         "            resolved results. The max value one can set is 64k",
133         NULL
134 };
135
136 static int cmd_logical_resolve(int argc, char **argv)
137 {
138         int ret;
139         int fd;
140         int i;
141         int verbose = 0;
142         int getpath = 1;
143         int bytes_left;
144         struct btrfs_ioctl_logical_ino_args loi;
145         struct btrfs_data_container *inodes;
146         u64 size = 4096;
147         char full_path[4096];
148         char *path_ptr;
149
150         optind = 1;
151         while (1) {
152                 int c = getopt(argc, argv, "Pvs:");
153                 if (c < 0)
154                         break;
155
156                 switch (c) {
157                 case 'P':
158                         getpath = 0;
159                         break;
160                 case 'v':
161                         verbose = 1;
162                         break;
163                 case 's':
164                         size = atoll(optarg);
165                         break;
166                 default:
167                         usage(cmd_logical_resolve_usage);
168                 }
169         }
170
171         if (check_argc_exact(argc - optind, 2))
172                 usage(cmd_logical_resolve_usage);
173
174         size = min(size, (u64)64 * 1024);
175         inodes = malloc(size);
176         if (!inodes)
177                 return 1;
178
179         memset(inodes, 0, sizeof(*inodes));
180         loi.logical = atoll(argv[optind]);
181         loi.size = size;
182         loi.inodes = (uintptr_t)inodes;
183
184         fd = open_file_or_dir(argv[optind+1]);
185         if (fd < 0) {
186                 fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind+1]);
187                 ret = 12;
188                 goto out;
189         }
190
191         ret = ioctl(fd, BTRFS_IOC_LOGICAL_INO, &loi);
192         if (ret) {
193                 printf("ioctl ret=%d, error: %s\n", ret, strerror(errno));
194                 goto out;
195         }
196
197         if (verbose)
198                 printf("ioctl ret=%d, total_size=%llu, bytes_left=%lu, "
199                         "bytes_missing=%lu, cnt=%d, missed=%d\n",
200                         ret, size,
201                         (unsigned long)inodes->bytes_left,
202                         (unsigned long)inodes->bytes_missing,
203                         inodes->elem_cnt, inodes->elem_missed);
204
205         bytes_left = sizeof(full_path);
206         ret = snprintf(full_path, bytes_left, "%s/", argv[optind+1]);
207         path_ptr = full_path + ret;
208         bytes_left -= ret + 1;
209         BUG_ON(bytes_left < 0);
210
211         for (i = 0; i < inodes->elem_cnt; i += 3) {
212                 u64 inum = inodes->val[i];
213                 u64 offset = inodes->val[i+1];
214                 u64 root = inodes->val[i+2];
215                 int path_fd;
216                 char *name;
217
218                 if (getpath) {
219                         name = btrfs_list_path_for_root(fd, root);
220                         if (IS_ERR(name)) {
221                                 ret = PTR_ERR(name);
222                                 goto out;
223                         }
224                         if (!name) {
225                                 path_ptr[-1] = '\0';
226                                 path_fd = fd;
227                         } else {
228                                 path_ptr[-1] = '/';
229                                 ret = snprintf(path_ptr, bytes_left, "%s",
230                                                 name);
231                                 BUG_ON(ret >= bytes_left);
232                                 free(name);
233                                 path_fd = open_file_or_dir(full_path);
234                                 if (path_fd < 0) {
235                                         fprintf(stderr, "ERROR: can't access "
236                                                 "'%s'\n", full_path);
237                                         goto out;
238                                 }
239                         }
240                         __ino_to_path_fd(inum, path_fd, verbose, full_path);
241                         if (path_fd != fd)
242                                 close(path_fd);
243                 } else {
244                         printf("inode %llu offset %llu root %llu\n", inum,
245                                 offset, root);
246                 }
247         }
248
249 out:
250         if (fd >= 0)
251                 close(fd);
252         free(inodes);
253         return ret;
254 }
255
256 const struct cmd_group inspect_cmd_group = {
257         inspect_cmd_group_usage, NULL, {
258                 { "inode-resolve", cmd_inode_resolve, cmd_inode_resolve_usage,
259                         NULL, 0 },
260                 { "logical-resolve", cmd_logical_resolve,
261                         cmd_logical_resolve_usage, NULL, 0 },
262                 { 0, 0, 0, 0, 0 }
263         }
264 };
265
266 int cmd_inspect(int argc, char **argv)
267 {
268         return handle_command_group(&inspect_cmd_group, argc, argv);
269 }