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