]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/fiemap.c
xfsprogs: explicitly cast troublesome types to match printf format specifiers
[thirdparty/xfsprogs-dev.git] / io / fiemap.c
1 /*
2 * Copyright (c) 2010 Red Hat, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "platform_defs.h"
20 #include "command.h"
21 #include "input.h"
22 #include <linux/fiemap.h>
23 #include "init.h"
24 #include "io.h"
25
26 #define EXTENT_BATCH 32
27
28 static cmdinfo_t fiemap_cmd;
29 static int max_extents = -1;
30
31 static void
32 fiemap_help(void)
33 {
34 printf(_(
35 "\n"
36 " prints the block mapping for a file's data or attribute forks"
37 "\n"
38 " Example:\n"
39 " 'fiemap -v' - tabular format verbose map\n"
40 "\n"
41 " fiemap prints the map of disk blocks used by the current file.\n"
42 " The map lists each extent used by the file, as well as regions in the\n"
43 " file that do not have any corresponding blocks (holes).\n"
44 " By default, each line of the listing takes the following form:\n"
45 " extent: [startoffset..endoffset]: startblock..endblock\n"
46 " Holes are marked by replacing the startblock..endblock with 'hole'.\n"
47 " All the file offsets and disk blocks are in units of 512-byte blocks.\n"
48 " -a -- prints the attribute fork map instead of the data fork.\n"
49 " -l -- also displays the length of each extent in 512-byte blocks.\n"
50 " -n -- query n extents.\n"
51 " -v -- Verbose information\n"
52 "\n"));
53 }
54
55 static void
56 print_hole(
57 int foff_w,
58 int boff_w,
59 int tot_w,
60 int cur_extent,
61 int lflag,
62 bool plain,
63 __u64 llast,
64 __u64 lstart)
65 {
66 char lbuf[48];
67
68 if (plain) {
69 printf("\t%d: [%llu..%llu]: hole", cur_extent,
70 (unsigned long long)llast, lstart - 1ULL);
71 if (lflag)
72 printf(_(" %llu blocks\n"),
73 (unsigned long long)lstart - llast);
74 else
75 printf("\n");
76 } else {
77 snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:",
78 (unsigned long long)llast, lstart - 1ULL);
79 printf("%4d: %-*s %-*s %*llu\n", cur_extent, foff_w, lbuf,
80 boff_w, _("hole"), tot_w,
81 (unsigned long long)lstart - llast);
82 }
83
84
85 }
86
87 static int
88 print_verbose(
89 struct fiemap_extent *extent,
90 int foff_w,
91 int boff_w,
92 int tot_w,
93 int flg_w,
94 int cur_extent,
95 __u64 last_logical)
96 {
97 __u64 lstart;
98 __u64 llast;
99 __u64 len;
100 __u64 block;
101 char lbuf[48];
102 char bbuf[48];
103 char flgbuf[16];
104
105 llast = BTOBBT(last_logical);
106 lstart = BTOBBT(extent->fe_logical);
107 len = BTOBBT(extent->fe_length);
108 block = BTOBBT(extent->fe_physical);
109
110 memset(lbuf, 0, sizeof(lbuf));
111 memset(bbuf, 0, sizeof(bbuf));
112
113 if (cur_extent == 0) {
114 printf("%4s: %-*s %-*s %*s %*s\n", _("EXT"),
115 foff_w, _("FILE-OFFSET"),
116 boff_w, _("BLOCK-RANGE"),
117 tot_w, _("TOTAL"),
118 flg_w, _("FLAGS"));
119 }
120
121 if (lstart != llast) {
122 print_hole(foff_w, boff_w, tot_w, cur_extent, 0, false, llast,
123 lstart);
124 cur_extent++;
125 }
126
127 if (cur_extent == max_extents)
128 return 1;
129
130 snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:",
131 (unsigned long long)lstart, lstart + len - 1ULL);
132 snprintf(bbuf, sizeof(bbuf), "%llu..%llu",
133 (unsigned long long)block, block + len - 1ULL);
134 snprintf(flgbuf, sizeof(flgbuf), "0x%x", extent->fe_flags);
135 printf("%4d: %-*s %-*s %*llu %*s\n", cur_extent, foff_w, lbuf,
136 boff_w, bbuf, tot_w, (unsigned long long)len, flg_w, flgbuf);
137
138 return 2;
139 }
140
141 static int
142 print_plain(
143 struct fiemap_extent *extent,
144 int lflag,
145 int cur_extent,
146 __u64 last_logical)
147 {
148 __u64 lstart;
149 __u64 llast;
150 __u64 block;
151 __u64 len;
152
153 llast = BTOBBT(last_logical);
154 lstart = BTOBBT(extent->fe_logical);
155 len = BTOBBT(extent->fe_length);
156 block = BTOBBT(extent->fe_physical);
157
158 if (lstart != llast) {
159 print_hole(0, 0, 0, cur_extent, lflag, true, llast, lstart);
160 cur_extent++;
161 }
162
163 if (cur_extent == max_extents)
164 return 1;
165
166 printf("\t%d: [%llu..%llu]: %llu..%llu", cur_extent,
167 (unsigned long long)lstart, lstart + len - 1ULL,
168 (unsigned long long)block, block + len - 1ULL);
169
170 if (lflag)
171 printf(_(" %llu blocks\n"), (unsigned long long)len);
172 else
173 printf("\n");
174 return 2;
175 }
176
177 /*
178 * Calculate the proper extent table format based on first
179 * set of extents
180 */
181 static void
182 calc_print_format(
183 struct fiemap *fiemap,
184 int *foff_w,
185 int *boff_w,
186 int *tot_w,
187 int *flg_w)
188 {
189 int i;
190 char lbuf[32];
191 char bbuf[32];
192 __u64 logical;
193 __u64 block;
194 __u64 len;
195 struct fiemap_extent *extent;
196
197 for (i = 0; i < fiemap->fm_mapped_extents; i++) {
198
199 extent = &fiemap->fm_extents[i];
200 logical = BTOBBT(extent->fe_logical);
201 len = BTOBBT(extent->fe_length);
202 block = BTOBBT(extent->fe_physical);
203
204 snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]",
205 (unsigned long long)logical,
206 (unsigned long long)logical + len - 1);
207 snprintf(bbuf, sizeof(bbuf), "%llu..%llu",
208 (unsigned long long)block,
209 (unsigned long long)block + len - 1);
210 *foff_w = max(*foff_w, strlen(lbuf));
211 *boff_w = max(*boff_w, strlen(bbuf));
212 *tot_w = max(*tot_w, numlen(len, 10));
213 *flg_w = max(*flg_w, numlen(extent->fe_flags, 16));
214 if (extent->fe_flags & FIEMAP_EXTENT_LAST)
215 break;
216 }
217 }
218
219 int
220 fiemap_f(
221 int argc,
222 char **argv)
223 {
224 struct fiemap *fiemap;
225 int last = 0;
226 int lflag = 0;
227 int vflag = 0;
228 int fiemap_flags = FIEMAP_FLAG_SYNC;
229 int c;
230 int i;
231 int map_size;
232 int ret;
233 int cur_extent = 0;
234 int foff_w = 16; /* 16 just for a good minimum range */
235 int boff_w = 16;
236 int tot_w = 5; /* 5 since its just one number */
237 int flg_w = 5;
238 __u64 last_logical = 0;
239 struct stat st;
240
241 while ((c = getopt(argc, argv, "aln:v")) != EOF) {
242 switch (c) {
243 case 'a':
244 fiemap_flags |= FIEMAP_FLAG_XATTR;
245 break;
246 case 'l':
247 lflag = 1;
248 break;
249 case 'n':
250 max_extents = atoi(optarg);
251 break;
252 case 'v':
253 vflag++;
254 break;
255 default:
256 return command_usage(&fiemap_cmd);
257 }
258 }
259
260 map_size = sizeof(struct fiemap) +
261 (EXTENT_BATCH * sizeof(struct fiemap_extent));
262 fiemap = malloc(map_size);
263 if (!fiemap) {
264 fprintf(stderr, _("%s: malloc of %d bytes failed.\n"),
265 progname, map_size);
266 exitcode = 1;
267 return 0;
268 }
269
270 printf("%s:\n", file->name);
271
272 while (!last && (cur_extent != max_extents)) {
273
274 memset(fiemap, 0, map_size);
275 fiemap->fm_flags = fiemap_flags;
276 fiemap->fm_start = last_logical;
277 fiemap->fm_length = -1LL;
278 fiemap->fm_extent_count = EXTENT_BATCH;
279
280 ret = ioctl(file->fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
281 if (ret < 0) {
282 fprintf(stderr, "%s: ioctl(FS_IOC_FIEMAP) [\"%s\"]: "
283 "%s\n", progname, file->name, strerror(errno));
284 free(fiemap);
285 exitcode = 1;
286 return 0;
287 }
288
289 /* No more extents to map, exit */
290 if (!fiemap->fm_mapped_extents)
291 break;
292
293 for (i = 0; i < fiemap->fm_mapped_extents; i++) {
294 struct fiemap_extent *extent;
295 int num_printed = 0;
296
297 extent = &fiemap->fm_extents[i];
298 if (vflag) {
299 if (cur_extent == 0) {
300 calc_print_format(fiemap, &foff_w,
301 &boff_w, &tot_w,
302 &flg_w);
303 }
304
305 num_printed = print_verbose(extent, foff_w,
306 boff_w, tot_w,
307 flg_w, cur_extent,
308 last_logical);
309 } else
310 num_printed = print_plain(extent, lflag,
311 cur_extent,
312 last_logical);
313
314 cur_extent += num_printed;
315 last_logical = extent->fe_logical + extent->fe_length;
316
317 if (extent->fe_flags & FIEMAP_EXTENT_LAST) {
318 last = 1;
319 break;
320 }
321
322 if (cur_extent == max_extents)
323 break;
324 }
325 }
326
327 if (cur_extent == max_extents)
328 goto out;
329
330 memset(&st, 0, sizeof(st));
331 if (fstat(file->fd, &st)) {
332 fprintf(stderr, "%s: fstat failed: %s\n", progname,
333 strerror(errno));
334 free(fiemap);
335 exitcode = 1;
336 return 0;
337 }
338
339 if (cur_extent && last_logical < st.st_size)
340 print_hole(foff_w, boff_w, tot_w, cur_extent, lflag, !vflag,
341 BTOBBT(last_logical), BTOBBT(st.st_size));
342
343 out:
344 free(fiemap);
345 return 0;
346 }
347
348 void
349 fiemap_init(void)
350 {
351 fiemap_cmd.name = "fiemap";
352 fiemap_cmd.cfunc = fiemap_f;
353 fiemap_cmd.argmin = 0;
354 fiemap_cmd.argmax = -1;
355 fiemap_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
356 fiemap_cmd.args = _("[-alv] [-n nx]");
357 fiemap_cmd.oneline = _("print block mapping for a file");
358 fiemap_cmd.help = fiemap_help;
359
360 add_command(&fiemap_cmd);
361 }