]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - io/fiemap.c
xfsprogs: make static things static
[thirdparty/xfsprogs-dev.git] / io / fiemap.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
8f0e0912
CH
2/*
3 * Copyright (c) 2010 Red Hat, Inc.
4 * All Rights Reserved.
8f0e0912
CH
5 */
6
dcabd4e7 7#include "platform_defs.h"
6b803e5a 8#include "command.h"
fb2bfcdf 9#include "input.h"
8f0e0912 10#include <linux/fiemap.h>
8f0e0912
CH
11#include "init.h"
12#include "io.h"
13
cb404e20
NB
14#define EXTENT_BATCH 32
15
8f0e0912 16static cmdinfo_t fiemap_cmd;
e7eaacef 17static int max_extents = -1;
8f0e0912
CH
18
19static void
20fiemap_help(void)
21{
22 printf(_(
23"\n"
24" prints the block mapping for a file's data or attribute forks"
25"\n"
26" Example:\n"
27" 'fiemap -v' - tabular format verbose map\n"
28"\n"
29" fiemap prints the map of disk blocks used by the current file.\n"
30" The map lists each extent used by the file, as well as regions in the\n"
31" file that do not have any corresponding blocks (holes).\n"
32" By default, each line of the listing takes the following form:\n"
33" extent: [startoffset..endoffset]: startblock..endblock\n"
34" Holes are marked by replacing the startblock..endblock with 'hole'.\n"
35" All the file offsets and disk blocks are in units of 512-byte blocks.\n"
36" -a -- prints the attribute fork map instead of the data fork.\n"
37" -l -- also displays the length of each extent in 512-byte blocks.\n"
38" -n -- query n extents.\n"
39" -v -- Verbose information\n"
7c18973b
NB
40" offset is the starting offset to map, and is optional. If offset is\n"
41" specified, mapping length may (optionally) be specified as well."
8f0e0912
CH
42"\n"));
43}
44
abd0c766
NB
45static void
46print_hole(
47 int foff_w,
48 int boff_w,
49 int tot_w,
50 int cur_extent,
51 int lflag,
52 bool plain,
53 __u64 llast,
54 __u64 lstart)
55{
56 char lbuf[48];
57
58 if (plain) {
59 printf("\t%d: [%llu..%llu]: hole", cur_extent,
51073f86 60 (unsigned long long)llast, lstart - 1ULL);
abd0c766 61 if (lflag)
51073f86
DW
62 printf(_(" %llu blocks\n"),
63 (unsigned long long)lstart - llast);
abd0c766
NB
64 else
65 printf("\n");
66 } else {
51073f86
DW
67 snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:",
68 (unsigned long long)llast, lstart - 1ULL);
abd0c766 69 printf("%4d: %-*s %-*s %*llu\n", cur_extent, foff_w, lbuf,
51073f86
DW
70 boff_w, _("hole"), tot_w,
71 (unsigned long long)lstart - llast);
abd0c766
NB
72 }
73
74
75}
76
997bfca5 77static int
8f0e0912
CH
78print_verbose(
79 struct fiemap_extent *extent,
8f0e0912
CH
80 int foff_w,
81 int boff_w,
82 int tot_w,
83 int flg_w,
997bfca5
NB
84 int cur_extent,
85 __u64 last_logical)
8f0e0912
CH
86{
87 __u64 lstart;
ef45fa5e 88 __u64 llast;
8f0e0912
CH
89 __u64 len;
90 __u64 block;
91 char lbuf[48];
92 char bbuf[48];
93 char flgbuf[16];
7c18973b 94 int num_printed = 0;
8f0e0912 95
997bfca5 96 llast = BTOBBT(last_logical);
3d12c088
NB
97 lstart = BTOBBT(extent->fe_logical);
98 len = BTOBBT(extent->fe_length);
99 block = BTOBBT(extent->fe_physical);
8f0e0912
CH
100
101 memset(lbuf, 0, sizeof(lbuf));
102 memset(bbuf, 0, sizeof(bbuf));
103
997bfca5 104 if (cur_extent == 0) {
b3a5164e
ES
105 printf("%4s: %-*s %-*s %*s %*s\n", _("EXT"),
106 foff_w, _("FILE-OFFSET"),
107 boff_w, _("BLOCK-RANGE"),
108 tot_w, _("TOTAL"),
109 flg_w, _("FLAGS"));
110 }
111
7c18973b 112 if (lstart > llast) {
abd0c766
NB
113 print_hole(foff_w, boff_w, tot_w, cur_extent, 0, false, llast,
114 lstart);
997bfca5 115 cur_extent++;
7c18973b 116 num_printed++;
8f0e0912
CH
117 }
118
e7eaacef 119 if (cur_extent == max_extents)
7c18973b 120 return num_printed;
8f0e0912 121
51073f86
DW
122 snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:",
123 (unsigned long long)lstart, lstart + len - 1ULL);
124 snprintf(bbuf, sizeof(bbuf), "%llu..%llu",
125 (unsigned long long)block, block + len - 1ULL);
8f0e0912 126 snprintf(flgbuf, sizeof(flgbuf), "0x%x", extent->fe_flags);
997bfca5 127 printf("%4d: %-*s %-*s %*llu %*s\n", cur_extent, foff_w, lbuf,
51073f86 128 boff_w, bbuf, tot_w, (unsigned long long)len, flg_w, flgbuf);
8f0e0912 129
7c18973b
NB
130 num_printed++;
131
132 return num_printed;
8f0e0912
CH
133}
134
997bfca5 135static int
8f0e0912
CH
136print_plain(
137 struct fiemap_extent *extent,
138 int lflag,
997bfca5
NB
139 int cur_extent,
140 __u64 last_logical)
8f0e0912
CH
141{
142 __u64 lstart;
ef45fa5e 143 __u64 llast;
8f0e0912
CH
144 __u64 block;
145 __u64 len;
7c18973b 146 int num_printed = 0;
8f0e0912 147
997bfca5 148 llast = BTOBBT(last_logical);
3d12c088
NB
149 lstart = BTOBBT(extent->fe_logical);
150 len = BTOBBT(extent->fe_length);
151 block = BTOBBT(extent->fe_physical);
8f0e0912 152
7c18973b 153 if (lstart > llast) {
abd0c766 154 print_hole(0, 0, 0, cur_extent, lflag, true, llast, lstart);
997bfca5 155 cur_extent++;
7c18973b 156 num_printed++;
8f0e0912
CH
157 }
158
e7eaacef 159 if (cur_extent == max_extents)
7c18973b 160 return num_printed;
8f0e0912 161
997bfca5 162 printf("\t%d: [%llu..%llu]: %llu..%llu", cur_extent,
51073f86
DW
163 (unsigned long long)lstart, lstart + len - 1ULL,
164 (unsigned long long)block, block + len - 1ULL);
8f0e0912 165
7c18973b
NB
166 num_printed++;
167
8f0e0912 168 if (lflag)
51073f86 169 printf(_(" %llu blocks\n"), (unsigned long long)len);
8f0e0912
CH
170 else
171 printf("\n");
7c18973b 172 return num_printed;
8f0e0912
CH
173}
174
b3a5164e
ES
175/*
176 * Calculate the proper extent table format based on first
177 * set of extents
178 */
179static void
180calc_print_format(
181 struct fiemap *fiemap,
b3a5164e
ES
182 int *foff_w,
183 int *boff_w,
184 int *tot_w,
185 int *flg_w)
186{
3d12c088 187 int i;
b3a5164e
ES
188 char lbuf[32];
189 char bbuf[32];
190 __u64 logical;
191 __u64 block;
192 __u64 len;
193 struct fiemap_extent *extent;
194
195 for (i = 0; i < fiemap->fm_mapped_extents; i++) {
196
197 extent = &fiemap->fm_extents[i];
3d12c088
NB
198 logical = BTOBBT(extent->fe_logical);
199 len = BTOBBT(extent->fe_length);
200 block = BTOBBT(extent->fe_physical);
b3a5164e 201
51073f86
DW
202 snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]",
203 (unsigned long long)logical,
204 (unsigned long long)logical + len - 1);
205 snprintf(bbuf, sizeof(bbuf), "%llu..%llu",
206 (unsigned long long)block,
207 (unsigned long long)block + len - 1);
b3a5164e
ES
208 *foff_w = max(*foff_w, strlen(lbuf));
209 *boff_w = max(*boff_w, strlen(bbuf));
210 *tot_w = max(*tot_w, numlen(len, 10));
211 *flg_w = max(*flg_w, numlen(extent->fe_flags, 16));
212 if (extent->fe_flags & FIEMAP_EXTENT_LAST)
213 break;
214 }
215}
216
00ff2b10 217static int
8f0e0912
CH
218fiemap_f(
219 int argc,
220 char **argv)
221{
222 struct fiemap *fiemap;
7c18973b 223 int done = 0;
8f0e0912
CH
224 int lflag = 0;
225 int vflag = 0;
226 int fiemap_flags = FIEMAP_FLAG_SYNC;
227 int c;
228 int i;
229 int map_size;
230 int ret;
231 int cur_extent = 0;
232 int foff_w = 16; /* 16 just for a good minimum range */
233 int boff_w = 16;
234 int tot_w = 5; /* 5 since its just one number */
235 int flg_w = 5;
7c18973b
NB
236 __u64 last_logical = 0; /* last extent offset handled */
237 off64_t start_offset = 0; /* mapping start */
238 off64_t length = -1LL; /* mapping length */
239 off64_t range_end = -1LL; /* mapping end*/
240 size_t fsblocksize, fssectsize;
8f0e0912
CH
241 struct stat st;
242
7c18973b
NB
243 init_cvtnum(&fsblocksize, &fssectsize);
244
8f0e0912
CH
245 while ((c = getopt(argc, argv, "aln:v")) != EOF) {
246 switch (c) {
247 case 'a':
248 fiemap_flags |= FIEMAP_FLAG_XATTR;
249 break;
250 case 'l':
251 lflag = 1;
252 break;
253 case 'n':
254 max_extents = atoi(optarg);
8f0e0912
CH
255 break;
256 case 'v':
257 vflag++;
258 break;
259 default:
260 return command_usage(&fiemap_cmd);
261 }
262 }
263
7c18973b
NB
264 /* Range start (optional) */
265 if (optind < argc) {
266 start_offset = cvtnum(fsblocksize, fssectsize, argv[optind]);
267 if (start_offset < 0) {
268 printf("non-numeric offset argument -- %s\n", argv[optind]);
269 return 0;
270 }
271 last_logical = start_offset;
272 optind++;
273 }
274
275 /* Range length (optional if range start was specified) */
276 if (optind < argc) {
277 length = cvtnum(fsblocksize, fssectsize, argv[optind]);
278 if (length < 0) {
279 printf("non-numeric len argument -- %s\n", argv[optind]);
280 return 0;
281 }
282 range_end = start_offset + length;
283 }
284
8f0e0912 285 map_size = sizeof(struct fiemap) +
cb404e20 286 (EXTENT_BATCH * sizeof(struct fiemap_extent));
8f0e0912
CH
287 fiemap = malloc(map_size);
288 if (!fiemap) {
289 fprintf(stderr, _("%s: malloc of %d bytes failed.\n"),
290 progname, map_size);
291 exitcode = 1;
292 return 0;
293 }
294
295 printf("%s:\n", file->name);
296
7c18973b 297 while (!done) {
8f0e0912
CH
298 memset(fiemap, 0, map_size);
299 fiemap->fm_flags = fiemap_flags;
300 fiemap->fm_start = last_logical;
7c18973b 301 fiemap->fm_length = range_end - last_logical;
cb404e20 302 fiemap->fm_extent_count = EXTENT_BATCH;
8f0e0912
CH
303
304 ret = ioctl(file->fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
305 if (ret < 0) {
306 fprintf(stderr, "%s: ioctl(FS_IOC_FIEMAP) [\"%s\"]: "
307 "%s\n", progname, file->name, strerror(errno));
308 free(fiemap);
309 exitcode = 1;
310 return 0;
311 }
312
313 /* No more extents to map, exit */
314 if (!fiemap->fm_mapped_extents)
315 break;
316
317 for (i = 0; i < fiemap->fm_mapped_extents; i++) {
318 struct fiemap_extent *extent;
997bfca5 319 int num_printed = 0;
8f0e0912
CH
320
321 extent = &fiemap->fm_extents[i];
b3a5164e
ES
322 if (vflag) {
323 if (cur_extent == 0) {
3d12c088
NB
324 calc_print_format(fiemap, &foff_w,
325 &boff_w, &tot_w,
326 &flg_w);
b3a5164e 327 }
f8149110 328
997bfca5
NB
329 num_printed = print_verbose(extent, foff_w,
330 boff_w, tot_w,
331 flg_w, cur_extent,
332 last_logical);
b3a5164e 333 } else
997bfca5
NB
334 num_printed = print_plain(extent, lflag,
335 cur_extent,
336 last_logical);
337
338 cur_extent += num_printed;
339 last_logical = extent->fe_logical + extent->fe_length;
ef45fa5e 340
7c18973b 341 /* Kernel has told us there are no more extents */
8f0e0912 342 if (extent->fe_flags & FIEMAP_EXTENT_LAST) {
7c18973b
NB
343 done = 1;
344 break;
345 }
346
347 /* We have exhausted the requested range */
348 if (last_logical >= range_end) {
349 done = 1;
8f0e0912
CH
350 break;
351 }
352
7c18973b
NB
353 /* We have printed requested nr of extents */
354 if (cur_extent == max_extents) {
355 done = 1;
8f0e0912 356 break;
7c18973b 357 }
8f0e0912
CH
358 }
359 }
360
e7eaacef 361 if (cur_extent == max_extents)
8f0e0912
CH
362 goto out;
363
364 memset(&st, 0, sizeof(st));
365 if (fstat(file->fd, &st)) {
366 fprintf(stderr, "%s: fstat failed: %s\n", progname,
367 strerror(errno));
368 free(fiemap);
369 exitcode = 1;
370 return 0;
371 }
372
7c18973b
NB
373 /* Print last hole to EOF or to end of requested range */
374 range_end = min((uint64_t)range_end, st.st_size);
375
376 if (cur_extent && last_logical < range_end)
abd0c766 377 print_hole(foff_w, boff_w, tot_w, cur_extent, lflag, !vflag,
7c18973b 378 BTOBBT(last_logical), BTOBBT(range_end));
8f0e0912
CH
379
380out:
381 free(fiemap);
382 return 0;
383}
384
385void
386fiemap_init(void)
387{
388 fiemap_cmd.name = "fiemap";
389 fiemap_cmd.cfunc = fiemap_f;
390 fiemap_cmd.argmin = 0;
391 fiemap_cmd.argmax = -1;
392 fiemap_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
7c18973b 393 fiemap_cmd.args = _("[-alv] [-n nx] [offset [len]]");
8f0e0912
CH
394 fiemap_cmd.oneline = _("print block mapping for a file");
395 fiemap_cmd.help = fiemap_help;
396
397 add_command(&fiemap_cmd);
398}