1 1.1 perseant #!/usr/pkg/bin/perl 2 1.1 perseant 3 1.1 perseant # 4 1.1 perseant # Use dumplfs to find all locations of the Ifile inode on a given disk. 5 1.1 perseant # Order these by serial number and call fsck_lfs on the raw disk for each. 6 1.1 perseant # If any fsck gives errors (lines containing "!", with a few exceptions) 7 1.1 perseant # print an error code with the daddr of the failing Ifile inode location. 8 1.1 perseant # 9 1.1 perseant 10 1.1 perseant $rdev = $ARGV[0]; 11 1.1 perseant $sstart = $ARGV[1]; 12 1.1 perseant $rollid = 0; 13 1.1 perseant open(DUMPLFS, "dumplfs $rdev |"); 14 1.1 perseant 15 1.1 perseant # Look for "roll_id" so we don't use garbage 16 1.1 perseant while (<DUMPLFS>) { 17 1.1 perseant if (m/roll_id *([x0-9a-f]*)/) { 18 1.1 perseant $rollid = $1; 19 1.1 perseant last; 20 1.1 perseant } 21 1.1 perseant } 22 1.1 perseant 23 1.1 perseant # Now look for inodes and segment summaries. Build a hash table of these 24 1.1 perseant # based on serial number. Ignore any with serial numbers lower than $sstart. 25 1.1 perseant 26 1.1 perseant %iloc = (); 27 1.1 perseant while (<DUMPLFS>) { 28 1.1 perseant if (m/roll_id *([0-9a-f]*)/) { 29 1.1 perseant # print "rollid $1\n"; 30 1.1 perseant if ("0x$1" ne $rollid) { 31 1.1 perseant # Skip the rest of this segment 32 1.1 perseant while(<DUMPLFS>) { 33 1.1 perseant last if m/SEGMENT/; 34 1.1 perseant } 35 1.1 perseant next; 36 1.1 perseant } 37 1.1 perseant } 38 1.1 perseant if (m/serial *([0-9]*)/) { 39 1.1 perseant $serno = $1; 40 1.1 perseant # print "serno $serno\n"; 41 1.1 perseant if ($serno < $sstart) { 42 1.1 perseant # Skip the rest of this partial segment 43 1.1 perseant while(<DUMPLFS>) { 44 1.1 perseant last if m/Segment Summary/; 45 1.1 perseant } 46 1.1 perseant next; 47 1.1 perseant } 48 1.1 perseant } 49 1.1 perseant if (m/0x([0-9a-f]*)/) { 50 1.1 perseant foreach $ss (split "0x", $_) { 51 1.1 perseant if ($ss =~ m/^([0-9a-f][0-9a-f]*)/) { 52 1.1 perseant # print "iblk 0x$1\n"; 53 1.1 perseant $daddr = $1; 54 1.1 perseant if (m/[^0-9]1v1/) { 55 1.1 perseant # print "** ifblk 0x$daddr\n"; 56 1.1 perseant $iloc{$serno} = $daddr; 57 1.1 perseant } 58 1.1 perseant } 59 1.1 perseant } 60 1.1 perseant } 61 1.1 perseant if (m/SEGMENT/) { 62 1.1 perseant print; 63 1.1 perseant } 64 1.1 perseant } 65 1.1 perseant close(DUMPLFS); 66 1.1 perseant 67 1.1 perseant # 68 1.1 perseant # Now fsck each checkpoint in turn, beginning with $sstart. 69 1.1 perseant # Look for lines containing only caps or "!", but ignore known 70 1.1 perseant # false positives. 71 1.1 perseant # 72 1.1 perseant $error = 0; 73 1.1 perseant open(LOG, ">>check-all.log"); 74 1.1 perseant foreach $k (sort { $a <=> $b } keys %iloc) { 75 1.1 perseant $a = $iloc{$k}; 76 1.1 perseant print "fsck_lfs -n -f -i 0x$a $ARGV[0]\n"; 77 1.1 perseant open(FSCK, "fsck_lfs -n -f -i 0x$a $ARGV[0] |"); 78 1.1 perseant while(<FSCK>) { 79 1.1 perseant print LOG; 80 1.1 perseant chomp; 81 1.1 perseant 82 1.1 perseant # Known false positives (mismatch between sb and ifile, 83 1.1 perseant # which should be expected given we're using an arbitrarily 84 1.1 perseant # old version fo the ifile) 85 1.1 perseant if (m/AVAIL GIVEN/ || 86 1.1 perseant m/BFREE GIVEN/ || 87 1.1 perseant m/DMETA GIVEN/ || 88 1.1 perseant m/NCLEAN GIVEN/) { 89 1.1 perseant next; 90 1.1 perseant } 91 1.1 perseant 92 1.1 perseant # Fsck reports errors in ALL CAPS 93 1.1 perseant # But don't count hex numbers as "lowercase". 94 1.1 perseant s/0x[0-9a-f]*//g; 95 1.1 perseant if (m/[A-Z]/ && ! m/[a-z]/) { 96 1.1 perseant $error = 1; 97 1.1 perseant last; 98 1.1 perseant } 99 1.1 perseant } 100 1.1 perseant close(FSCK); 101 1.1 perseant print "$error $k 0x$a\n"; 102 1.1 perseant last if $error; 103 1.1 perseant } 104 1.1 perseant 105 1.1 perseant # If there were no checkpoints, print *something* 106 1.1 perseant if ($#iloc == 0) { 107 1.1 perseant print "0 $sstart 0\n"; 108 1.1 perseant } 109