102680591Sperseant#!/usr/pkg/bin/perl 2ebaf3982Sperseant# 3*b8eed869Sperseant# $NetBSD: check-all,v 1.4 2006/07/21 00:29:23 perseant Exp $ 4ebaf3982Sperseant# 5ebaf3982Sperseant# Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc. 6ebaf3982Sperseant# All rights reserved. 7ebaf3982Sperseant# 8ebaf3982Sperseant# This code is derived from software contributed to The NetBSD Foundation 9ebaf3982Sperseant# by Konrad E. Schroder <perseant@hhhh.org>. 10ebaf3982Sperseant# 11ebaf3982Sperseant# Redistribution and use in source and binary forms, with or without 12ebaf3982Sperseant# modification, are permitted provided that the following conditions 13ebaf3982Sperseant# are met: 14ebaf3982Sperseant# 1. Redistributions of source code must retain the above copyright 15ebaf3982Sperseant# notice, this list of conditions and the following disclaimer. 16ebaf3982Sperseant# 2. Redistributions in binary form must reproduce the above copyright 17ebaf3982Sperseant# notice, this list of conditions and the following disclaimer in the 18ebaf3982Sperseant# documentation and/or other materials provided with the distribution. 19ebaf3982Sperseant# 3. All advertising materials mentioning features or use of this software 20ebaf3982Sperseant# must display the following acknowledgement: 21ebaf3982Sperseant# This product includes software developed by the NetBSD 22ebaf3982Sperseant# Foundation, Inc. and its contributors. 23ebaf3982Sperseant# 4. Neither the name of The NetBSD Foundation nor the names of its 24ebaf3982Sperseant# contributors may be used to endorse or promote products derived 25ebaf3982Sperseant# from this software without specific prior written permission. 26ebaf3982Sperseant# 27ebaf3982Sperseant# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28ebaf3982Sperseant# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29ebaf3982Sperseant# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30ebaf3982Sperseant# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31ebaf3982Sperseant# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32ebaf3982Sperseant# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33ebaf3982Sperseant# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34ebaf3982Sperseant# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35ebaf3982Sperseant# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36ebaf3982Sperseant# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37ebaf3982Sperseant# POSSIBILITY OF SUCH DAMAGE. 38ebaf3982Sperseant# 3902680591Sperseant 4002680591Sperseant# 4102680591Sperseant# Use dumplfs to find all locations of the Ifile inode on a given disk. 4202680591Sperseant# Order these by serial number and call fsck_lfs on the raw disk for each. 43ebaf3982Sperseant# If any fsck gives errors (any line of all capital letters, with a few 44ebaf3982Sperseant# exceptions) print an error code with the daddr of the failing Ifile inode 45ebaf3982Sperseant# location. 4602680591Sperseant# 4702680591Sperseant 487cd0266aSperseant$| = 1; 4902680591Sperseant$rdev = $ARGV[0]; 507cd0266aSperseant$gfile = $ARGV[1]; 517cd0266aSperseant$wfile = $ARGV[2]; 527cd0266aSperseant$sstart = $ARGV[3]; 53*b8eed869Sperseant$test_rfw = 1; # $ARGV[4]; 5402680591Sperseant$rollid = 0; 5502680591Sperseantopen(DUMPLFS, "dumplfs $rdev |"); 5602680591Sperseant 5702680591Sperseant# Look for "roll_id" so we don't use garbage 5802680591Sperseantwhile (<DUMPLFS>) { 597cd0266aSperseant if ($ssize == 0 && m/ssize *([0-9]*)/) { 607cd0266aSperseant $ssize = $1; 617cd0266aSperseant } 627cd0266aSperseant if ($fsize == 0 && m/fsize *([0-9]*)/) { 637cd0266aSperseant $fsize = $1; 647cd0266aSperseant } 6502680591Sperseant if (m/roll_id *([x0-9a-f]*)/) { 6602680591Sperseant $rollid = $1; 6702680591Sperseant last; 6802680591Sperseant } 6902680591Sperseant} 7002680591Sperseant 7102680591Sperseant# Now look for inodes and segment summaries. Build a hash table of these 7202680591Sperseant# based on serial number. Ignore any with serial numbers lower than $sstart. 7302680591Sperseant 7402680591Sperseant%iloc = (); 757cd0266aSperseant%snloc = (); 767cd0266aSperseant%sumloc = (); 777cd0266aSperseantprint "Reading segments:"; 7802680591Sperseantwhile (<DUMPLFS>) { 7902680591Sperseant if (m/roll_id *([0-9a-f]*)/) { 8002680591Sperseant # print "rollid $1\n"; 8102680591Sperseant if ("0x$1" ne $rollid) { 8202680591Sperseant # Skip the rest of this segment 83ebaf3982Sperseant print "{skip bad rollid 0x$1}"; 8402680591Sperseant while(<DUMPLFS>) { 8502680591Sperseant last if m/SEGMENT/; 8602680591Sperseant } 877cd0266aSperseant # Fall through 8802680591Sperseant } 8902680591Sperseant } 907cd0266aSperseant if (m/roll_id.*serial *([0-9]*)/) { 9102680591Sperseant $serno = $1; 927cd0266aSperseant $snloc{$serno} = $segnum; 937cd0266aSperseant $sumloc{$serno} = $sumloc; 94ebaf3982Sperseant print "($serno)"; 9502680591Sperseant if ($serno < $sstart) { 9602680591Sperseant # Skip the rest of this partial segment 97ebaf3982Sperseant #print "{skip bad serno $serno}"; 9802680591Sperseant while(<DUMPLFS>) { 997cd0266aSperseant last if m/Segment Summary/ || 1007cd0266aSperseant m/SEGMENT/; 10102680591Sperseant } 1027cd0266aSperseant # Fall through 10302680591Sperseant } 10402680591Sperseant } 1057cd0266aSperseant if (m/Segment Summary Info at 0x([0-9a-f]*)/) { 1067cd0266aSperseant $sumloc = $1; 107ebaf3982Sperseant next; 1087cd0266aSperseant } 10902680591Sperseant if (m/0x([0-9a-f]*)/) { 11002680591Sperseant foreach $ss (split "0x", $_) { 11102680591Sperseant if ($ss =~ m/^([0-9a-f][0-9a-f]*)/) { 11202680591Sperseant # print "iblk 0x$1\n"; 11302680591Sperseant $daddr = $1; 11402680591Sperseant if (m/[^0-9]1v1/) { 11502680591Sperseant # print "** ifblk 0x$daddr\n"; 11602680591Sperseant $iloc{$serno} = $daddr; 1177cd0266aSperseant $lastaddr = $daddr; 11802680591Sperseant } 11902680591Sperseant } 12002680591Sperseant } 12102680591Sperseant } 1227cd0266aSperseant if (m/SEGMENT *([0-9]*)/) { 1237cd0266aSperseant $segnum = $1; 124ebaf3982Sperseant print "[$segnum]"; 12502680591Sperseant } 12602680591Sperseant} 1277cd0266aSperseantprint "\n"; 12802680591Sperseantclose(DUMPLFS); 12902680591Sperseant 130ebaf3982Sperseant# Complain about missing partial-segments 131ebaf3982Sperseantfor ($i = $sstart; $i < $serno; ++$i) { 132ebaf3982Sperseant if (hex $sumloc{$i} == 0 && $i > 0) { 133ebaf3982Sperseant print "Oops, couldn't find pseg $i\n"; 134ebaf3982Sperseant } 135ebaf3982Sperseant} 136ebaf3982Sperseant 1377cd0266aSperseant# If there were no checkpoints, print *something* 1387cd0266aSperseantif ($#iloc == 0) { 1397cd0266aSperseant print "0 $sstart 0\n"; 1407cd0266aSperseant exit 0; 1417cd0266aSperseant} 1427cd0266aSperseant 14302680591Sperseant# 14402680591Sperseant# Now fsck each checkpoint in turn, beginning with $sstart. 1457cd0266aSperseant# Because the log wraps we will have to reconstruct the filesystem image 1467cd0266aSperseant# as it existed at each checkpoint before running fsck. 1477cd0266aSperseant# 14802680591Sperseant# Look for lines containing only caps or "!", but ignore known 14902680591Sperseant# false positives. 15002680591Sperseant# 15102680591Sperseant$error = 0; 1527cd0266aSperseant$lastgood = $sstart - 1; 15302680591Sperseantopen(LOG, ">>check-all.log"); 1547cd0266aSperseantprint "Available checkpoints:"; 1557cd0266aSperseantprint LOG "Available checkpoints:"; 15602680591Sperseantforeach $k (sort { $a <=> $b } keys %iloc) { 15702680591Sperseant $a = $iloc{$k}; 1587cd0266aSperseant print " $a"; 1597cd0266aSperseant print LOG " $a"; 1607cd0266aSperseant} 1617cd0266aSperseantprint "\n"; 1627cd0266aSperseantprint LOG "\n"; 1637cd0266aSperseant 164ebaf3982Sperseant# 165ebaf3982Sperseant# Copy the partial segments $_[0]--$_[1] from the raw device onto 166ebaf3982Sperseant# the working file. Return the next partial-segment serial number 167ebaf3982Sperseant# after the last one we copied (usually $_[1] + 1, except in case of 168ebaf3982Sperseant# an error). 169ebaf3982Sperseant# 170ebaf3982Sperseantsub copypseg 171ebaf3982Sperseant{ 172ebaf3982Sperseant my ($blstart, $blstop, $segstop, $cmd); 173ebaf3982Sperseant my ($totalstart, $totalstop); 174ebaf3982Sperseant 175ebaf3982Sperseant $totalstart = 0; 176ebaf3982Sperseant $totalstop = 0; 177ebaf3982Sperseant for ($i = $_[0]; $i <= $_[1]; ++$i) { 178ebaf3982Sperseant $blstart = hex $sumloc{$i}; 179ebaf3982Sperseant last if $blstart <= 0; 180ebaf3982Sperseant $totalstart = $blstart if $totalstart == 0; 181ebaf3982Sperseant $blstop = hex $sumloc{$i + 1}; 182ebaf3982Sperseant $segstop = ((int ($blstart / $fps)) + 1) * $fps; 183ebaf3982Sperseant if ($segstop < $blstop || $blstop < $blstart) { 184ebaf3982Sperseant #print "Adjusting $blstop -> $segstop\n"; 185ebaf3982Sperseant $blstop = $segstop; 186ebaf3982Sperseant } 187ebaf3982Sperseant $totalstop = $blstop; 188ebaf3982Sperseant 189*b8eed869Sperseant print "pseg $i: write blocks ", hex $blstart, "-", hex ($blstop - 1), "\n"; 190ebaf3982Sperseant $blstart = $blstop; 191ebaf3982Sperseant } 192ebaf3982Sperseant $cmd = "dd if=$rdev of=$wfile bs=$fsize seek=$totalstart " . 193ebaf3982Sperseant "skip=$totalstart conv=notrunc count=" . 194ebaf3982Sperseant ($totalstop - $totalstart); 195ebaf3982Sperseant# print "$cmd\n"; 196ebaf3982Sperseant system("$cmd >/dev/null 2>&1"); 197ebaf3982Sperseant 198ebaf3982Sperseant return $i; 199ebaf3982Sperseant} 200ebaf3982Sperseant 2017cd0266aSperseantprint "Recreating filesystem image as of $sstart:\n"; 2027cd0266aSperseantif ($sstart == 0) { 2037cd0266aSperseant $cmd = "dd if=$rdev of=$wfile bs=1m conv=swab,oldebcdic"; # garbage 2047cd0266aSperseant} else { 2057cd0266aSperseant $cmd = "dd if=$gfile of=$wfile bs=1m"; 2067cd0266aSperseant} 2077cd0266aSperseantprint "$cmd\n"; 2087cd0266aSperseantsystem("$cmd >/dev/null 2>&1"); 2097cd0266aSperseant 210ebaf3982Sperseantprint "Copying over first superblock\n"; 211ebaf3982Sperseantsystem("dd if=$rdev of=$wfile bs=8k count=2 conv=notrunc >/dev/null 2>&1"); 212ebaf3982Sperseant 213*b8eed869Sperseantsub test_fsck 214*b8eed869Sperseant{ 215*b8eed869Sperseant my $a = $_[0]; 216*b8eed869Sperseant my $flags = $_[1]; 217*b8eed869Sperseant my $printit = $_[2]; 218*b8eed869Sperseant my $output = ""; 2197cd0266aSperseant 220*b8eed869Sperseant $flags = "-n -f -i 0x$a $wfile" unless $flags; 2217cd0266aSperseant 222*b8eed869Sperseant $cmd = "fsck_lfs $flags"; 2237cd0266aSperseant print "$cmd\n"; 2247cd0266aSperseant print LOG "$cmd\n"; 2257cd0266aSperseant open(FSCK, "$cmd 2>&1 |"); 22602680591Sperseant while(<FSCK>) { 22702680591Sperseant print LOG; 228*b8eed869Sperseant $rline = "$_"; 22902680591Sperseant chomp; 23002680591Sperseant 23102680591Sperseant # Known false positives (mismatch between sb and ifile, 23202680591Sperseant # which should be expected given we're using an arbitrarily 233ebaf3982Sperseant # old version of the ifile) 23402680591Sperseant if (m/AVAIL GIVEN/ || 23502680591Sperseant m/BFREE GIVEN/ || 23602680591Sperseant m/DMETA GIVEN/ || 2377cd0266aSperseant m/NCLEAN GIVEN/ || 2387cd0266aSperseant m/FREE BUT NOT ON FREE LIST/ || # UNWRITTEN inodes OK 239*b8eed869Sperseant m/FILE SYSTEM WAS MODIFIED/ || 2407cd0266aSperseant m/FREE LIST HEAD IN SUPERBLOCK/ ) { 24102680591Sperseant next; 24202680591Sperseant } 24302680591Sperseant 24402680591Sperseant # Fsck reports errors in ALL CAPS 24502680591Sperseant # But don't count hex numbers as "lowercase". 246*b8eed869Sperseant $oline = "$_"; 24702680591Sperseant s/0x[0-9a-f]*//g; 24802680591Sperseant if (m/[A-Z]/ && ! m/[a-z]/) { 24902680591Sperseant $error = 1; 2507cd0266aSperseant $errsn = $k; 251*b8eed869Sperseant $errstr = "1 $k 0x$a $oline"; 252*b8eed869Sperseant # last; 25302680591Sperseant } 254*b8eed869Sperseant 255*b8eed869Sperseant # Log everything we get, except for some things we 256*b8eed869Sperseant # will see every single time. 257*b8eed869Sperseant if (m/checkpoint invalid/ || 258*b8eed869Sperseant m/skipping free list check/ || 259*b8eed869Sperseant m/expect discrepancies/) { 260*b8eed869Sperseant next; 261*b8eed869Sperseant } 262*b8eed869Sperseant $output .= $rline; 26302680591Sperseant } 26402680591Sperseant close(FSCK); 265*b8eed869Sperseant 266*b8eed869Sperseant if ($? != 0) { 267*b8eed869Sperseant $error = 1; 268*b8eed869Sperseant $errsn = $k; 269*b8eed869Sperseant $errstr = "1 $k 0x$a <" . (hex $?) . ">"; 270*b8eed869Sperseant } 271*b8eed869Sperseant 272*b8eed869Sperseant if ($error || $printit) { 273*b8eed869Sperseant print $output; 274*b8eed869Sperseant } 275*b8eed869Sperseant} 276*b8eed869Sperseant 277*b8eed869Sperseant$blstart = 0; 278*b8eed869Sperseant$fps = $ssize / $fsize; 279*b8eed869Sperseant$oind = ($sstart ? $sstart : 1); 280*b8eed869SperseantBIGLOOP: foreach $k (sort { $a <=> $b } keys %iloc) { 281*b8eed869Sperseant $a = $iloc{$k}; 282*b8eed869Sperseant 283*b8eed869Sperseant if (hex($a) > hex($lastaddr)) { 284*b8eed869Sperseant print "Skipping out-of-place checkpoint $k at $a\n"; 285*b8eed869Sperseant next; 286*b8eed869Sperseant } 287*b8eed869Sperseant 288*b8eed869Sperseant if ($test_rfw && $iloc{$oind - 1}) { 289*b8eed869Sperseant for ($tk = $oind; $tk < $k; $tk++) { 290*b8eed869Sperseant print "Test roll-forward agent at non-checkpoint pseg $tk\n"; 291*b8eed869Sperseant print LOG "Test roll-forward agent at non-checkpoint pseg $tk\n"; 292*b8eed869Sperseant ©pseg($oind, $tk); 293*b8eed869Sperseant # Add -d flag here for verbose debugging info 294*b8eed869Sperseant $flags = "-p -f -i 0x" . $iloc{$oind - 1} . " $wfile"; 295*b8eed869Sperseant &test_fsck($iloc{$oind - 1}, $flags, 1); 296*b8eed869Sperseant last BIGLOOP if $error; 297*b8eed869Sperseant 298*b8eed869Sperseant # note lack of -i flag, since the roll-forward 299*b8eed869Sperseant # will have rewritten the superblocks. 300*b8eed869Sperseant &test_fsck($iloc{$oind - 1}, "-n -f $wfile", 0); 301*b8eed869Sperseant last BIGLOOP if $error; 302*b8eed869Sperseant } 303*b8eed869Sperseant } 304*b8eed869Sperseant 305*b8eed869Sperseant print "Recreate fs state at checkpoint pseg $k (from " . ($oind - 1) . 306*b8eed869Sperseant ")\n"; 307*b8eed869Sperseant $oind = ©pseg($oind, $k); 308*b8eed869Sperseant 309*b8eed869Sperseant &test_fsck($a, "", 0); 310*b8eed869Sperseant 31102680591Sperseant last if $error; 3127cd0266aSperseant $lastgood = $k; # record last good serial number 3137cd0266aSperseant} 314*b8eed869Sperseant 315*b8eed869Sperseantif ($errstr) { 316*b8eed869Sperseant print "$errstr\n"; 317*b8eed869Sperseant exit 0; 318*b8eed869Sperseant} 319*b8eed869Sperseant 320ebaf3982Sperseantif (!$errstr) { 321ebaf3982Sperseant print "Bring filesystem state up to log wrap\n"; 322ebaf3982Sperseant $lastgood = ©pseg($oind, 100000000000) - 1; 3237cd0266aSperseant 3247cd0266aSperseant print "Copying this good image to $gfile\n"; 3257cd0266aSperseant system("dd bs=1m if=$rdev of=$gfile >/dev/null 2>&1"); 326ebaf3982Sperseant print "0 $lastgood 0x$a\n"; 3277cd0266aSperseant exit 0; 32802680591Sperseant} 32902680591Sperseant 3307cd0266aSperseant# 331ebaf3982Sperseant# Ifile write-checking paranoia. 332ebaf3982Sperseant# 3337cd0266aSperseant# If we found an error, try to find which blocks of the Ifile inode changed 3347cd0266aSperseant# between the last good checkpoint and this checkpoint; and which blocks 3357cd0266aSperseant# *should* have changed. This means (1) which segments were written; and 3367cd0266aSperseant# (2) which inodes were written. The 0 block of the Ifile should always 3377cd0266aSperseant# have changed since lfs_avail is always in flux. 3387cd0266aSperseant# 3397cd0266aSperseant 3407cd0266aSperseant$cmd = "dumplfs"; 3417cd0266aSperseant$oseg = -1; 3427cd0266aSperseant%iblk = (); 3437cd0266aSperseant%iblk_done = (); 3447cd0266aSperseant%why = (); 3457cd0266aSperseant$iblk{0} = 1; 3467cd0266aSperseantfor ($i = $lastgood + 1; $i <= $errsn; $i++) { 3477cd0266aSperseant if ($oseg != $snloc{$i}) { 3487cd0266aSperseant $oseg = 0 + $snloc{$i}; 3497cd0266aSperseant $cmd .= " -s$oseg"; 35002680591Sperseant } 3517cd0266aSperseant} 3527cd0266aSperseant$cmd .= " $rdev"; 3537cd0266aSperseant 3547cd0266aSperseantopen(DUMPLFS, "$cmd |"); 3557cd0266aSperseantwhile(<DUMPLFS>) { 3567cd0266aSperseant if (m/ifpb *([0-9]*)/) { 3577cd0266aSperseant $ifpb = $1; 3587cd0266aSperseant } 3597cd0266aSperseant if (m/sepb *([0-9]*)/) { 3607cd0266aSperseant $sepb = $1; 3617cd0266aSperseant } 3627cd0266aSperseant if (m/cleansz *([0-9]*)/) { 3637cd0266aSperseant $cleansz = $1; 3647cd0266aSperseant } 3657cd0266aSperseant if (m/segtabsz *([0-9]*)/) { 3667cd0266aSperseant $segtabsz = $1; 3677cd0266aSperseant } 3687cd0266aSperseant last if m/SEGMENT/; 3697cd0266aSperseant} 3707cd0266aSperseantwhile(<DUMPLFS>) { 3717cd0266aSperseant chomp; 3727cd0266aSperseant 3737cd0266aSperseant # Skip over partial segments outside our range of interest 3747cd0266aSperseant if (m/roll_id.*serial *([0-9]*)/) { 3757cd0266aSperseant $serno = $1; 3767cd0266aSperseant if ($serno <= $lastgood || $serno > $errsn) { 3777cd0266aSperseant # Skip the rest of this partial segment 3787cd0266aSperseant while(<DUMPLFS>) { 3797cd0266aSperseant last if m/Segment Summary/ || m/SEGMENT/; 3807cd0266aSperseant } 3817cd0266aSperseant next; 3827cd0266aSperseant } 3837cd0266aSperseant } 3847cd0266aSperseant 3857cd0266aSperseant # Look for inodes 3867cd0266aSperseant if (m/Inode addresses/) { 3877cd0266aSperseant s/^[^{]*{/ /o; 3887cd0266aSperseant s/}[^{]*$/ /o; 3897cd0266aSperseant s/}[^{]*{/,/og; 3907cd0266aSperseant s/v[0-9]*//og; 3917cd0266aSperseant @ilist = split(','); 3927cd0266aSperseant foreach $i (@ilist) { 3937cd0266aSperseant $i =~ s/ *//og; 3947cd0266aSperseant next if $i == 1; 3957cd0266aSperseant $iaddr = $cleansz + $segtabsz + int ($i / $ifpb); 3967cd0266aSperseant $iblk{$iaddr} = 1; 3977cd0266aSperseant $why{$iaddr} .= " $i"; 3987cd0266aSperseant } 3997cd0266aSperseant } 4007cd0266aSperseant 4017cd0266aSperseant # Look for Ifile blocks actually written 4027cd0266aSperseant if (m/FINFO for inode: ([0-9]*) version/) { 4037cd0266aSperseant $i = $1; 4047cd0266aSperseant $inoblkmode = ($i == 1); 4057cd0266aSperseant } 4067cd0266aSperseant if ($inoblkmode && m/^[-\t 0-9]*$/) { 4077cd0266aSperseant s/\t/ /og; 4087cd0266aSperseant s/^ *//o; 4097cd0266aSperseant s/ *$//o; 4107cd0266aSperseant @bn = split(' '); 4117cd0266aSperseant foreach $b (@bn) { 4127cd0266aSperseant $iblk_done{$b} = 1; 4137cd0266aSperseant } 4147cd0266aSperseant } 4157cd0266aSperseant} 4167cd0266aSperseantclose(DUMPLFS); 4177cd0266aSperseant 4187cd0266aSperseant# Report found and missing Ifile blocks 4197cd0266aSperseantprint "Ifile blocks found:"; 4207cd0266aSperseantforeach $b (sort { $a <=> $b } keys %iblk) { 4217cd0266aSperseant if ($iblk_done{$b} == 1) { 4227cd0266aSperseant print " $b"; 4237cd0266aSperseant } 4247cd0266aSperseant} 4257cd0266aSperseantprint "\n"; 4267cd0266aSperseant 4277cd0266aSperseantprint "Ifile blocks missing:"; 4287cd0266aSperseantforeach $b (sort { $a <=> $b } keys %iblk) { 4297cd0266aSperseant if ($iblk_done{$b} == 0) { 4307cd0266aSperseant $why{$b} =~ s/^ *//o; 4317cd0266aSperseant print " $b ($why{$b})"; 4327cd0266aSperseant } 4337cd0266aSperseant} 4347cd0266aSperseantprint "\n"; 4357cd0266aSperseant 4367cd0266aSperseantprint "$errstr\n"; 4377cd0266aSperseantexit 0; 438