]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - bmap/xfs_bmap.c
2 * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
34 * Bmap display utility for xfs.
39 #include <sys/ioctl.h>
42 int aflag
= 0; /* Attribute fork. */
43 int lflag
= 0; /* list number of blocks with each extent */
44 int nflag
= 0; /* number of extents specified */
45 int vflag
= 0; /* Verbose output */
46 int bmv_iflags
= 0; /* Input flags for XFS_IOC_GETBMAPX */
50 __off64_t
file_size(int fd
, char * fname
);
51 int numlen(__off64_t
);
54 main(int argc
, char **argv
)
60 progname
= basename(argv
[0]);
61 while ((option
= getopt(argc
, argv
, "adln:pvV")) != EOF
) {
64 bmv_iflags
|= BMV_IF_ATTRFORK
;
74 /* do not recall possibly offline DMAPI files */
75 bmv_iflags
|= BMV_IF_NO_DMAPI_READ
;
78 /* report unwritten preallocated blocks */
79 bmv_iflags
|= BMV_IF_PREALLOC
;
85 printf("%s version %s\n", progname
, VERSION
);
88 fprintf(stderr
, "Usage: %s [-adlpV] [-n nx] file...\n",
94 bmv_iflags
&= ~(BMV_IF_PREALLOC
|BMV_IF_NO_DMAPI_READ
);
95 while (optind
< argc
) {
104 file_size(int fd
, char *fname
)
110 errno_save
= errno
; /* in case fstat64 fails */
111 i
= fstat64(fd
, &st
);
113 fprintf(stderr
, "%s: fstat64 failed for %s: %s\n",
114 progname
, fname
, strerror(errno
));
129 struct getbmapx
*map
;
132 xfs_fsop_geom_t fsgeo
;
134 fd
= open(fname
, O_RDONLY
);
136 fprintf(stderr
, "%s: cannot open \"%s\": %s\n",
137 progname
, fname
, strerror(errno
));
141 if (buf
.f_type
!= XFS_SUPER_MAGIC
) {
142 fprintf(stderr
, "%s: "
143 "specified file [\"%s\"] is not on an XFS filesystem\n",
150 if (ioctl(fd
, XFS_IOC_FSGEOMETRY
, &fsgeo
) < 0) {
151 fprintf(stderr
, "%s: can't get geometry [\"%s\"]: %s\n",
152 progname
, fname
, strerror(errno
));
159 "xfs_bmap: fsgeo.agblocks=%u, fsgeo.blocksize=%u, fsgeo.agcount=%u\n",
160 fsgeo
.agblocks
, fsgeo
.blocksize
,
163 if ((ioctl(fd
, XFS_IOC_FSGETXATTR
, &fsx
)) < 0) {
164 fprintf(stderr
, "%s: cannot read attrs on \"%s\": %s\n",
165 progname
, fname
, strerror(errno
));
172 "xfs_bmap: fsx.dsx_xflags=%u, fsx.fsx_extsize=%u, fsx.fsx_nextents=%u\n",
173 fsx
.fsx_xflags
, fsx
.fsx_extsize
,
176 if (fsx
.fsx_xflags
== XFS_XFLAG_REALTIME
) {
178 * ag info not applicable to rt, continue
185 map_size
= nflag
? nflag
+1 : 32; /* initial guess - 256 for checkin KCM */
186 map
= malloc(map_size
*sizeof(*map
));
188 fprintf(stderr
, "%s: malloc of %d bytes failed.\n",
189 progname
, (int)(map_size
* sizeof(*map
)));
195 /* Try the ioctl(XFS_IOC_GETBMAPX) for the number of extents specified by
196 * nflag, or the initial guess number of extents (256).
198 * If there are more extents than we guessed, use ioctl
199 * (XFS_IOC_FSGETXATTR[A]) to get the extent count, realloc some more
200 * space based on this count, and try again.
202 * If the initial FGETBMAPX attempt returns EINVAL, this may mean
203 * that we tried the FGETBMAPX on a zero length file. If we get
204 * EINVAL, check the length with fstat() and return "no extents"
205 * if the length == 0.
207 * Why not do the ioctl(XFS_IOC_FSGETXATTR[A]) first? Two reasons:
208 * (1) The extent count may be wrong for a file with delayed
209 * allocation blocks. The XFS_IOC_GETBMAPX forces the real
210 * allocation and fixes up the extent count.
211 * (2) For XFS_IOC_GETBMAP[X] on a DMAPI file that has been moved
212 * offline by a DMAPI application (e.g., DMF) the
213 * XFS_IOC_FSGETXATTR only reflects the extents actually online.
214 * Doing XFS_IOC_GETBMAPX call first forces that data blocks online
215 * and then everything proceeds normally (see PV #545725).
217 * If you don't want this behavior on a DMAPI offline file,
218 * try the "-d" option which sets the BMV_IF_NO_DMAPI_READ
219 * iflag for XFS_IOC_GETBMAPX.
222 do { /* loop a miximum of two times */
224 bzero(map
, sizeof(*map
)); /* zero header */
226 map
->bmv_length
= -1;
227 map
->bmv_count
= map_size
;
228 map
->bmv_iflags
= bmv_iflags
;
230 i
= ioctl(fd
, XFS_IOC_GETBMAPX
, map
);
234 "xfs_bmap: i=%d map.bmv_offset=%lld, map.bmv_block=%lld, "
235 "map.bmv_length=%lld, map.bmv_count=%d, map.bmv_entries=%d\n",
236 i
, (long long)map
->bmv_offset
,
237 (long long)map
->bmv_block
,
238 (long long)map
->bmv_length
,
239 map
->bmv_count
, map
->bmv_entries
);
242 && !aflag
&& file_size(fd
, fname
) == 0) {
245 fprintf(stderr
, "%s: ioctl(XFS_IOC_GETBMAPX) "
246 "iflags=0x%x [\"%s\"]: %s\n",
247 progname
, map
->bmv_iflags
, fname
,
256 if (map
->bmv_entries
< map
->bmv_count
-1)
258 /* Get number of extents from ioctl XFS_IOC_FSGETXATTR[A]
261 i
= ioctl(fd
, aflag
? XFS_IOC_FSGETXATTRA
: XFS_IOC_FSGETXATTR
, &fsx
);
263 fprintf(stderr
, "%s: ioctl(XFS_IOC_FSGETXATTR%s) "
264 "[\"%s\"]: %s\n", progname
, aflag
? "A" : "",
265 fname
, strerror(errno
));
270 if (fsx
.fsx_nextents
>= map_size
-1) {
271 map_size
= 2*(fsx
.fsx_nextents
+1);
272 map
= realloc(map
, map_size
*sizeof(*map
));
274 fprintf(stderr
, "%s: cannot realloc %d bytes\n",
275 progname
, (int)(map_size
*sizeof(*map
)));
280 } while (++loop
< 2);
282 if (map
->bmv_entries
<= 0) {
283 printf("%s: no extents\n", fname
);
290 printf("%s:\n", fname
);
292 for (i
= 0; i
< map
->bmv_entries
; i
++) {
293 printf("\t%d: [%lld..%lld]: ", i
,
294 (long long) map
[i
+ 1].bmv_offset
,
295 (long long)(map
[i
+ 1].bmv_offset
+
296 map
[i
+ 1].bmv_length
- 1LL));
297 if (map
[i
+ 1].bmv_block
== -1)
301 (long long) map
[i
+ 1].bmv_block
,
302 (long long)(map
[i
+ 1].bmv_block
+
303 map
[i
+ 1].bmv_length
- 1LL));
307 printf(" %lld blocks\n", (long long)map
[i
+1].bmv_length
);
313 * Verbose mode displays:
314 * extent: [startoffset..endoffset]: startblock..endblock \
315 * ag# (agoffset..agendoffset) totalbbs
317 #define MINRANGE_WIDTH 16
318 #define MINAG_WIDTH 2
319 #define MINTOT_WIDTH 5
320 #define max(a,b) (a > b ? a : b)
322 __off64_t agoff
, bbperag
;
323 int foff_w
, boff_w
, aoff_w
, tot_w
, agno_w
;
324 char rbuf
[32], bbuf
[32], abuf
[32];
326 foff_w
= boff_w
= aoff_w
= MINRANGE_WIDTH
;
327 tot_w
= MINTOT_WIDTH
;
328 bbperag
= (__off64_t
)fsgeo
.agblocks
*
329 (__off64_t
)fsgeo
.blocksize
/ BBSIZE
;
332 * Go through the extents and figure out the width
333 * needed for all columns.
335 for (i
= 0; i
< map
->bmv_entries
; i
++) {
336 snprintf(rbuf
, sizeof(rbuf
), "[%lld..%lld]:",
337 (long long) map
[i
+ 1].bmv_offset
,
338 (long long)(map
[i
+ 1].bmv_offset
+
339 map
[i
+ 1].bmv_length
- 1LL));
340 if (map
[i
+ 1].bmv_block
== -1) {
341 foff_w
= max(foff_w
, strlen(rbuf
));
343 numlen(map
[i
+1].bmv_length
));
345 snprintf(bbuf
, sizeof(bbuf
), "%lld..%lld",
346 (long long) map
[i
+ 1].bmv_block
,
347 (long long)(map
[i
+ 1].bmv_block
+
348 map
[i
+ 1].bmv_length
- 1LL));
349 agno
= map
[i
+ 1].bmv_block
/ bbperag
;
350 agoff
= map
[i
+ 1].bmv_block
- (agno
* bbperag
);
351 snprintf(abuf
, sizeof(abuf
), "(%lld..%lld)",
352 (long long)agoff
, (long long)
353 (agoff
+ map
[i
+ 1].bmv_length
- 1LL));
354 foff_w
= max(foff_w
, strlen(rbuf
));
355 boff_w
= max(boff_w
, strlen(bbuf
));
356 aoff_w
= max(aoff_w
, strlen(abuf
));
358 numlen(map
[i
+1].bmv_length
));
361 agno_w
= max(MINAG_WIDTH
, numlen(fsgeo
.agcount
));
362 printf("%4s: %-*s %-*s %*s %-*s %*s\n",
364 foff_w
, "FILE-OFFSET",
365 boff_w
, "BLOCK-RANGE",
369 for (i
= 0; i
< map
->bmv_entries
; i
++) {
370 snprintf(rbuf
, sizeof(rbuf
), "[%lld..%lld]:",
371 (long long) map
[i
+ 1].bmv_offset
,
372 (long long)(map
[i
+ 1].bmv_offset
+
373 map
[i
+ 1].bmv_length
- 1LL));
374 if (map
[i
+ 1].bmv_block
== -1) {
375 printf("%4d: %-*s %-*s %*s %-*s %*lld\n",
381 tot_w
, (long long)map
[i
+1].bmv_length
);
383 snprintf(bbuf
, sizeof(bbuf
), "%lld..%lld",
384 (long long) map
[i
+ 1].bmv_block
,
385 (long long)(map
[i
+ 1].bmv_block
+
386 map
[i
+ 1].bmv_length
- 1LL));
387 agno
= map
[i
+ 1].bmv_block
/ bbperag
;
388 agoff
= map
[i
+ 1].bmv_block
- (agno
* bbperag
);
389 snprintf(abuf
, sizeof(abuf
), "(%lld..%lld)",
390 (long long)agoff
, (long long)
391 (agoff
+ map
[i
+ 1].bmv_length
- 1LL));
392 printf("%4d: %-*s %-*s %*d %-*s %*lld\n",
398 tot_w
, (long long)map
[i
+1].bmv_length
);
407 numlen( __off64_t val
)
412 for (len
=0, tmp
=val
; tmp
> 0; tmp
=tmp
/10) len
++;
413 return(len
== 0 ? 1 : len
);