btrfs: test btrfs filesystem usage command on missing seed device
[xfstests-dev.git] / tools / db-walk
1 #!/usr/bin/perl -w
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
4 #
5 # use db to try to traverse the entire filesystem starting at the root
6 #
7 my $device;
8 my $rootino;
9 my $agcount;
10 my $versionnum;
11 my $dir_version;
12 my @dir_inodes;
13 my @bmap_blocks;
14 my @block_inodes;
15 my $mode;
16
17 sub db($)
18 {
19     my ($args)=@_;
20     my ($ret);
21     
22     $ret=`xfs_db -r $args $device 2> /dev/null`;
23     die "ERROR executing xfs_db -r $args $device" if ($?);
24     
25     return $ret;
26 }
27
28 sub fmt($)
29 {
30     my ($text)=@_;
31     my $c=0;
32     print "        ";
33     foreach (split("\n",$text)) {
34         s/^core\.//;
35         
36         if ($c+length($_) >= 70) {
37             $c=0;
38             print ",\n        ";
39         }
40         if ($c) {
41             print ", ";
42             $c+=2;
43         }
44         print "$_";
45         $c+=length($_)+2;
46     }
47     print "\n";
48 }
49
50 sub inode($)
51 {
52     my ($num)=@_;
53     my ($t);
54     
55     @dir_inodes=();
56     
57     $t=db("-c \"inode $num\" -c \"print\"");
58     print "    *** Inode $num\n";
59     fmt($t);
60     
61     ($mode)= $t=~ /^core.mode = (\d+)$/m;
62     
63     if ($t=~ /a\.bmx/m) {
64         bmap("inode $num","attr");
65         foreach (@bmap_blocks) {
66             attr_block($_);
67         }
68     }
69     if (eval "$mode & 040000") {
70         if ( $t=~ /sfdir/m) {
71             while ($t=~ /inumber(?:\.i[48])? = (\d+)$/mg) {
72                 push(@dir_inodes,$1);
73             }
74         }
75         if ( $t=~ /u\.bmx/m) {
76             bmap("inode $num","dir");
77             foreach (@bmap_blocks) {
78                 dir_block($_);
79                 push(@dir_inodes,@block_inodes);
80             }
81         }
82     } else {
83         bmap("inode $num","file") if ( $t=~ /u\.bmx/m);
84     }
85 }
86
87 sub bmap($$)
88 {
89     my ($cmd,$type)=@_;
90     my ($t);
91     
92     @bmap_blocks=();
93     
94     $flag=($type eq "attr")?"-a":"";
95     
96     $t=db("-c \"$cmd\" -c \"bmap $flag\"");
97     print "    *** bmap $type $cmd\n";
98     fmt($t);
99     
100     if ($type eq "dir" || $type eq "attr") {
101         while ($t=~ /startblock (\d+) \(.+\) count (\d+)/mg) {
102             for ($b=$1;$b<$1+$2;$b++) {
103                 push(@bmap_blocks,$b);
104             }
105         }
106     }
107 }
108
109 sub dir_block($)
110 {
111     my ($num)=@_;
112     my ($t);
113     
114     @block_inodes=();
115     
116     $type=($dir_version==2)?"dir2":"dir";
117     
118     $t=db("-c \"fsblock $num\" -c \"type $type\" -c \"print\"");
119     print "    *** $type block $num\n";
120     # need to drop . and ..
121     ($self)= $t=~ /\[(\d+)\].name = \"\.\"/m;
122     ($parent)= $t=~ /\[(\d+)\].name = \"\.\.\"/m;
123     fmt($t);
124     
125     
126     while ($t=~ /\[(\d+)\].inumber = (\d+)/mg) {
127         next if (defined $self && $1 == $self);
128         next if (defined $parent && $1 == $parent);
129         push(@block_inodes, $2);
130     }
131 }
132
133 sub attr_block($)
134 {
135     my ($num)=@_;
136     my ($t);
137     
138     $t=db("-c \"fsblock $num\" -c \"type attr\" -c \"print\"");
139     print "    *** attr block $num\n";
140
141     fmt($t);
142 }
143
144 sub sb($)
145 {
146     my ($num)=@_;
147     my ($t);
148     
149     $t=db("-c \"sb $num\" -c \"print\"");
150     print "    *** SB $num\n";
151     fmt($t);
152     
153     ($rootino)= $t=~ /^rootino = (\d+)$/m;
154     ($agcount)= $t=~ /^agcount = (\d+)$/m;
155     ($versionnum)= $t=~ /^versionnum = (0x[\da-f]+)$/m;
156     $dir_version = (eval "$versionnum & 0x2000")?2:1;
157 }
158
159 die "Usage: $0 <XFS device>\n" unless (@ARGV == 1);
160
161 $device=shift @ARGV;
162 die "can't read $device\n" unless (-r $device);
163 die "$device is not a block device\n" unless (-b _);
164
165 chomp($HOST = `hostname -s`);
166
167 print "*** db-walk host $HOST device $device\n";
168
169 sb(0);
170 for ($ag=1;$ag<$agcount;$ag++) {
171     sb($ag);
172 }
173
174 @inodes=($rootino);
175 while ($_ = shift @inodes) {
176     inode($_);
177     push(@inodes,@dir_inodes);
178 }