3 # Copyright (c) 2002-2003
\r
4 # The President and Fellows of Harvard College.
\r
6 # Redistribution and use in source and binary forms, with or without
\r
7 # modification, are permitted provided that the following conditions
\r
9 # 1. Redistributions of source code must retain the above copyright
\r
10 # notice, this list of conditions and the following disclaimer.
\r
11 # 2. Redistributions in binary form must reproduce the above copyright
\r
12 # notice, this list of conditions and the following disclaimer in the
\r
13 # documentation and/or other materials provided with the distribution.
\r
14 # 3. Neither the name of the University nor the names of its contributors
\r
15 # may be used to endorse or promote products derived from this software
\r
16 # without specific prior written permission.
\r
18 # THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
\r
19 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
\r
20 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
\r
21 # ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
\r
22 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
\r
23 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
\r
24 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
\r
25 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
\r
26 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
\r
27 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
\r
30 # $Id: nfsdump.pl,v 1.5 2003/07/26 20:52:04 ellard Exp $
\r
32 # Utility for dealing with raw nfsdump records.
\r
36 # If $AllowRisky is set, then allow some optimizations that might be
\r
37 # "risky" in bizarre situations (but have never been observed to
\r
38 # actually break anything). By default, no riskiness is permitted.
\r
42 # nfsDumpParseLine -- initializes the global associative array
\r
43 # %nfsd'nfsDumpLine with information about a record from nfsdump.
\r
44 # Returns an empty list if anything goes wrong. Otherwise, returns a
\r
45 # list of the protocol (eg R2, C2, R3, C3), the name of the operation,
\r
46 # and the xid, the client host ID, the time, and for responses, the
\r
47 # status (via nfsDumpParseLineHeader). The reason for this particular
\r
48 # return list is that these are very frequently-accessed values, so it
\r
49 # can save time to avoid going through the associative array to access
\r
52 # All records begin with several fixed fields, and then are followed
\r
53 # by some number of name/value pairs, and finally some diagnostic
\r
54 # fields (which are mostly ignored by this routine-- the only
\r
55 # diagnostic this routine cares about is whether the packet as part of
\r
56 # a jumbo packet or not. If so, then 'truncated' is set.)
\r
58 sub nfsDumpParseLine {
\r
59 my ($line, $total) = @_;
\r
61 my (@rl) = &nfsDumpParseLineHeader ($line);
\r
63 if (@rl && $total) {
\r
64 &nfsDumpParseLineBody ($line);
\r
70 sub nfsDumpParseLineBody {
\r
78 # If the line doesn't start with a digit, then it's certainly
\r
79 # not properly formed, so bail out immediately.
\r
81 if (! ($line =~ /^[0-9]/)) {
\r
85 my @l = split (' ', $line);
\r
87 if ($l[$lineLen - 1] eq 'LONGPKT') {
\r
88 splice (@l, $lineLen - 1);
\r
89 $nfsDumpLine{'truncated'} = 1;
\r
93 $nfsDumpLine{'time'} = $l[0];
\r
94 $nfsDumpLine{'srchost'} = $l[1];
\r
95 $nfsDumpLine{'deshost'} = $l[2];
\r
96 $nfsDumpLine{'proto'} = $l[4];
\r
97 $nfsDumpLine{'xid'} = $l[5];
\r
98 $nfsDumpLine{'opcode'} = $l[6];
\r
99 $nfsDumpLine{'opname'} = $l[7];
\r
101 if (($l[4] eq 'R3') || ($l[4] eq 'R2')) {
\r
102 $nfsDumpLine{'status'} = $l[8];
\r
104 $client_id = $l[2];
\r
106 for ($i = 9; $i < $lineLen - 10; $i += 2) {
\r
107 if (defined $nfsDumpLine{$l[$i]}) {
\r
109 $nfsDumpLine{"$l[$i]-2"} = $l[$i + 1];
\r
112 $nfsDumpLine{$l[$i]} = $l[$i + 1];
\r
117 $client_id = $l[1];
\r
119 for ($i = 8; $i < $lineLen - 6; $i += 2) {
\r
120 if (defined $nfsDumpLine{$l[$i]}) {
\r
121 $nfsDumpLine{"$l[$i]-2"} = $l[$i + 1];
\r
125 $nfsDumpLine{$l[$i]} = $l[$i + 1];
\r
131 # Returns an empty list if anything goes wrong. Otherwise, returns a
\r
132 # list of the protocol (eg R2, C2, R3, C3), the name of the operation,
\r
133 # and the xid, the client host ID, and time, and the response status.
\r
134 # (For call messages, the status is 'na'.)
\r
136 sub nfsDumpParseLineHeader {
\r
139 # If the line doesn't start with a digit, then it's certainly
\r
140 # not properly formed, so bail out immediately.
\r
142 if (! ($line =~ /^[0-9]/)) {
\r
149 my @l = split (' ', $line, 10);
\r
152 if (($l[4] eq 'R3') || ($l[4] eq 'R2')) {
\r
153 $client_id = $l[2];
\r
157 $client_id = $l[1];
\r
161 return ($l[4], $l[7], $l[5], $client_id, $l[0], $status);
\r
165 # nfsDumpParseLineFields -- Just return a subset of the fields,
\r
166 # without parsing the entire line.
\r
168 sub nfsDumpParseLineFields {
\r
169 my ($line, @fields) = @_;
\r
172 # If the line doesn't start with a digit, then
\r
173 # it's certainly not properly formed, so bail out
\r
176 if (! ($line =~ /^[0-9]/)) {
\r
185 my @foo = split (' ', $line, 9);
\r
186 $rest = ' ' . $foo[8];
\r
191 for ($i = 0; $i < $fl; $i++) {
\r
192 my $field = $fields[$i];
\r
194 $rest =~ /\ $field\ +([^\ ]+)/;
\r
201 # nfsDumpParseLineField -- Just return ONE of the fields,
\r
202 # without parsing the entire line.
\r
204 sub nfsDumpParseLineField {
\r
205 my ($line, $field) = @_;
\r
207 # If the line doesn't start with a digit, then
\r
208 # it's certainly not properly formed, so bail out
\r
211 if (! ($line =~ /^[0-9]/)) {
\r
220 my @foo = split (' ', $line, 9);
\r
221 $rest = ' ' . $foo[8];
\r
224 $rest =~ /\ $field\ +([^\ ]+)/;
\r
228 # Returns a new file handle that has all the "useful" information as
\r
229 # the original, but requires less storage space. File handles
\r
230 # typically contain quite a bit of redundancy or unused bytes.
\r
232 # This routine only knows about the advfs and netapp formats. If
\r
233 # you're using anything else, just use anything else as the mode, and
\r
234 # the original file handle will be returned.
\r
236 # If you extend this to handle more file handles, please send the new
\r
237 # code to me (ellard@eecs.harvard.edu) so I can add it to the
\r
240 sub nfsDumpCompressFH {
\r
241 my ($mode, $fh) = @_;
\r
243 if ($mode eq 'advfs') {
\r
245 # The fh is a long hex string:
\r
246 # 8 chars: file system ID
\r
247 # 8 chars: apparently unused.
\r
250 # 8 chars: generation
\r
251 # rest of string: mount point (not interesting).
\r
252 # So all we do is pluck out the fsid, inode,
\r
253 # and generation number, and throw the rest away.
\r
255 $fh =~ /^(........)(........)(........)(........)(........)/;
\r
257 return ("$1-$4-$5");
\r
259 elsif ($mode eq 'netapp') {
\r
261 # Here's the netapp format (from Shane Owara):
\r
263 # 4 bytes mount point file inode number
\r
264 # 4 bytes mount point file generation number
\r
267 # 1 byte snapshot id
\r
270 # 4 bytes file inode number
\r
271 # 4 bytes file generation number
\r
272 # 4 bytes volume identifier
\r
274 # 4 bytes export point fileid
\r
275 # 1 byte export point snapshot id
\r
276 # 3 bytes export point snapshot generation number
\r
278 # The only parts of this that are interesting are
\r
279 # inode, generation, and volume identifier (and probably
\r
280 # a lot of the bits of the volume identifier could be
\r
281 # tossed, since we don't have many volumes...).
\r
283 $fh =~ /^(........)(........)(........)(........)(........)(........)(........)/;
\r
285 return ("$4-$5-$6-$1");
\r
287 elsif ($mode eq 'RFSNN') {
\r
289 # Here's the netapp format (from Shane Owara):
\r
291 # 4 bytes mount point file inode number
\r
292 # 4 bytes mount point file generation number
\r
295 # 1 byte snapshot id
\r
298 # 4 bytes file inode number
\r
299 # 4 bytes file generation number
\r
300 # 4 bytes volume identifier
\r
302 # 4 bytes export point fileid
\r
303 # 1 byte export point snapshot id
\r
304 # 3 bytes export point snapshot generation number
\r
306 # The only parts of this that are interesting are
\r
307 # inode, generation, and volume identifier (and probably
\r
308 # a lot of the bits of the volume identifier could be
\r
309 # tossed, since we don't have many volumes...).
\r
311 # 61890100575701002000000 0009ac710e9ea381 0d24400006189010057570100
\r
312 # 61890100575701002000000 0009ac70ed2ea381 0d24400006189010057570100
\r
313 # 61890100575701002000000 000479a1e008d782 0d24400006189010057570100
\r
314 # Ningning need only 24-39 (or 12-19 bytes)
\r
316 $fh =~ /^(........)(........)(........)(........)(........)(........)/;
\r
332 &nfsDumpParseLine ($line);
\r
338 # end of nfsdump.pl
\r