xref: /netbsd-src/regress/sys/fs/lfs/ckckp/check-all (revision 11a6dbe72840351315e0652b2fc6663628c84cad)
102680591Sperseant#!/usr/pkg/bin/perl
2ebaf3982Sperseant#
3*11a6dbe7Smartin#	$NetBSD: check-all,v 1.5 2008/04/30 13:10:52 martin 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#
20ebaf3982Sperseant# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21ebaf3982Sperseant# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22ebaf3982Sperseant# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23ebaf3982Sperseant# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24ebaf3982Sperseant# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25ebaf3982Sperseant# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26ebaf3982Sperseant# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27ebaf3982Sperseant# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28ebaf3982Sperseant# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29ebaf3982Sperseant# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30ebaf3982Sperseant# POSSIBILITY OF SUCH DAMAGE.
31ebaf3982Sperseant#
3202680591Sperseant
3302680591Sperseant#
3402680591Sperseant# Use dumplfs to find all locations of the Ifile inode on a given disk.
3502680591Sperseant# Order these by serial number and call fsck_lfs on the raw disk for each.
36ebaf3982Sperseant# If any fsck gives errors (any line of all capital letters, with a few
37ebaf3982Sperseant# exceptions) print an error code with the daddr of the failing Ifile inode
38ebaf3982Sperseant# location.
3902680591Sperseant#
4002680591Sperseant
417cd0266aSperseant$| = 1;
4202680591Sperseant$rdev = $ARGV[0];
437cd0266aSperseant$gfile = $ARGV[1];
447cd0266aSperseant$wfile = $ARGV[2];
457cd0266aSperseant$sstart = $ARGV[3];
46b8eed869Sperseant$test_rfw = 1; # $ARGV[4];
4702680591Sperseant$rollid = 0;
4802680591Sperseantopen(DUMPLFS, "dumplfs $rdev |");
4902680591Sperseant
5002680591Sperseant# Look for "roll_id" so we don't use garbage
5102680591Sperseantwhile (<DUMPLFS>) {
527cd0266aSperseant	if ($ssize == 0 && m/ssize *([0-9]*)/) {
537cd0266aSperseant		$ssize = $1;
547cd0266aSperseant	}
557cd0266aSperseant	if ($fsize == 0 && m/fsize *([0-9]*)/) {
567cd0266aSperseant		$fsize = $1;
577cd0266aSperseant	}
5802680591Sperseant	if (m/roll_id *([x0-9a-f]*)/) {
5902680591Sperseant		$rollid = $1;
6002680591Sperseant		last;
6102680591Sperseant	}
6202680591Sperseant}
6302680591Sperseant
6402680591Sperseant# Now look for inodes and segment summaries.  Build a hash table of these
6502680591Sperseant# based on serial number.  Ignore any with serial numbers lower than $sstart.
6602680591Sperseant
6702680591Sperseant%iloc = ();
687cd0266aSperseant%snloc = ();
697cd0266aSperseant%sumloc = ();
707cd0266aSperseantprint "Reading segments:";
7102680591Sperseantwhile (<DUMPLFS>) {
7202680591Sperseant	if (m/roll_id *([0-9a-f]*)/) {
7302680591Sperseant		# print "rollid $1\n";
7402680591Sperseant		if ("0x$1" ne $rollid) {
7502680591Sperseant			# Skip the rest of this segment
76ebaf3982Sperseant			print "{skip bad rollid 0x$1}";
7702680591Sperseant			while(<DUMPLFS>) {
7802680591Sperseant				last if m/SEGMENT/;
7902680591Sperseant			}
807cd0266aSperseant			# Fall through
8102680591Sperseant		}
8202680591Sperseant	}
837cd0266aSperseant	if (m/roll_id.*serial *([0-9]*)/) {
8402680591Sperseant		$serno = $1;
857cd0266aSperseant		$snloc{$serno} = $segnum;
867cd0266aSperseant		$sumloc{$serno} = $sumloc;
87ebaf3982Sperseant		print "($serno)";
8802680591Sperseant		if ($serno < $sstart) {
8902680591Sperseant			# Skip the rest of this partial segment
90ebaf3982Sperseant			#print "{skip bad serno $serno}";
9102680591Sperseant			while(<DUMPLFS>) {
927cd0266aSperseant				last if m/Segment Summary/ ||
937cd0266aSperseant					m/SEGMENT/;
9402680591Sperseant			}
957cd0266aSperseant			# Fall through
9602680591Sperseant		}
9702680591Sperseant	}
987cd0266aSperseant	if (m/Segment Summary Info at 0x([0-9a-f]*)/) {
997cd0266aSperseant		$sumloc = $1;
100ebaf3982Sperseant		next;
1017cd0266aSperseant	}
10202680591Sperseant	if (m/0x([0-9a-f]*)/) {
10302680591Sperseant		foreach $ss (split "0x", $_) {
10402680591Sperseant			if ($ss =~ m/^([0-9a-f][0-9a-f]*)/) {
10502680591Sperseant				# print "iblk 0x$1\n";
10602680591Sperseant				$daddr = $1;
10702680591Sperseant				if (m/[^0-9]1v1/) {
10802680591Sperseant					# print "** ifblk 0x$daddr\n";
10902680591Sperseant					$iloc{$serno} = $daddr;
1107cd0266aSperseant					$lastaddr = $daddr;
11102680591Sperseant				}
11202680591Sperseant			}
11302680591Sperseant		}
11402680591Sperseant	}
1157cd0266aSperseant	if (m/SEGMENT *([0-9]*)/) {
1167cd0266aSperseant		$segnum = $1;
117ebaf3982Sperseant		print "[$segnum]";
11802680591Sperseant	}
11902680591Sperseant}
1207cd0266aSperseantprint "\n";
12102680591Sperseantclose(DUMPLFS);
12202680591Sperseant
123ebaf3982Sperseant# Complain about missing partial-segments
124ebaf3982Sperseantfor ($i = $sstart; $i < $serno; ++$i) {
125ebaf3982Sperseant	if (hex $sumloc{$i} == 0 && $i > 0) {
126ebaf3982Sperseant		print "Oops, couldn't find pseg $i\n";
127ebaf3982Sperseant	}
128ebaf3982Sperseant}
129ebaf3982Sperseant
1307cd0266aSperseant# If there were no checkpoints, print *something*
1317cd0266aSperseantif ($#iloc == 0) {
1327cd0266aSperseant	print "0 $sstart 0\n";
1337cd0266aSperseant	exit 0;
1347cd0266aSperseant}
1357cd0266aSperseant
13602680591Sperseant#
13702680591Sperseant# Now fsck each checkpoint in turn, beginning with $sstart.
1387cd0266aSperseant# Because the log wraps we will have to reconstruct the filesystem image
1397cd0266aSperseant# as it existed at each checkpoint before running fsck.
1407cd0266aSperseant#
14102680591Sperseant# Look for lines containing only caps or "!", but ignore known
14202680591Sperseant# false positives.
14302680591Sperseant#
14402680591Sperseant$error = 0;
1457cd0266aSperseant$lastgood = $sstart - 1;
14602680591Sperseantopen(LOG, ">>check-all.log");
1477cd0266aSperseantprint "Available checkpoints:";
1487cd0266aSperseantprint LOG "Available checkpoints:";
14902680591Sperseantforeach $k (sort { $a <=> $b } keys %iloc) {
15002680591Sperseant	$a = $iloc{$k};
1517cd0266aSperseant	print " $a";
1527cd0266aSperseant	print LOG " $a";
1537cd0266aSperseant}
1547cd0266aSperseantprint "\n";
1557cd0266aSperseantprint LOG "\n";
1567cd0266aSperseant
157ebaf3982Sperseant#
158ebaf3982Sperseant# Copy the partial segments $_[0]--$_[1] from the raw device onto
159ebaf3982Sperseant# the working file.  Return the next partial-segment serial number
160ebaf3982Sperseant# after the last one we copied (usually $_[1] + 1, except in case of
161ebaf3982Sperseant# an error).
162ebaf3982Sperseant#
163ebaf3982Sperseantsub copypseg
164ebaf3982Sperseant{
165ebaf3982Sperseant	my ($blstart, $blstop, $segstop, $cmd);
166ebaf3982Sperseant	my ($totalstart, $totalstop);
167ebaf3982Sperseant
168ebaf3982Sperseant	$totalstart = 0;
169ebaf3982Sperseant	$totalstop = 0;
170ebaf3982Sperseant	for ($i = $_[0]; $i <= $_[1]; ++$i) {
171ebaf3982Sperseant		$blstart = hex $sumloc{$i};
172ebaf3982Sperseant		last if $blstart <= 0;
173ebaf3982Sperseant		$totalstart = $blstart if $totalstart == 0;
174ebaf3982Sperseant		$blstop = hex $sumloc{$i + 1};
175ebaf3982Sperseant		$segstop = ((int ($blstart / $fps)) + 1) * $fps;
176ebaf3982Sperseant		if ($segstop < $blstop || $blstop < $blstart) {
177ebaf3982Sperseant			#print "Adjusting $blstop -> $segstop\n";
178ebaf3982Sperseant			$blstop = $segstop;
179ebaf3982Sperseant		}
180ebaf3982Sperseant		$totalstop = $blstop;
181ebaf3982Sperseant
182b8eed869Sperseant		print "pseg $i: write blocks ", hex $blstart, "-", hex ($blstop - 1), "\n";
183ebaf3982Sperseant		$blstart = $blstop;
184ebaf3982Sperseant	}
185ebaf3982Sperseant	$cmd = "dd if=$rdev of=$wfile bs=$fsize seek=$totalstart " .
186ebaf3982Sperseant		"skip=$totalstart conv=notrunc count=" .
187ebaf3982Sperseant		($totalstop - $totalstart);
188ebaf3982Sperseant#	print "$cmd\n";
189ebaf3982Sperseant	system("$cmd >/dev/null 2>&1");
190ebaf3982Sperseant
191ebaf3982Sperseant	return $i;
192ebaf3982Sperseant}
193ebaf3982Sperseant
1947cd0266aSperseantprint "Recreating filesystem image as of $sstart:\n";
1957cd0266aSperseantif ($sstart == 0) {
1967cd0266aSperseant	$cmd = "dd if=$rdev of=$wfile bs=1m conv=swab,oldebcdic"; # garbage
1977cd0266aSperseant} else {
1987cd0266aSperseant	$cmd = "dd if=$gfile of=$wfile bs=1m";
1997cd0266aSperseant}
2007cd0266aSperseantprint "$cmd\n";
2017cd0266aSperseantsystem("$cmd >/dev/null 2>&1");
2027cd0266aSperseant
203ebaf3982Sperseantprint "Copying over first superblock\n";
204ebaf3982Sperseantsystem("dd if=$rdev of=$wfile bs=8k count=2 conv=notrunc >/dev/null 2>&1");
205ebaf3982Sperseant
206b8eed869Sperseantsub test_fsck
207b8eed869Sperseant{
208b8eed869Sperseant	my $a = $_[0];
209b8eed869Sperseant	my $flags = $_[1];
210b8eed869Sperseant	my $printit = $_[2];
211b8eed869Sperseant	my $output = "";
2127cd0266aSperseant
213b8eed869Sperseant	$flags = "-n -f -i 0x$a $wfile" unless $flags;
2147cd0266aSperseant
215b8eed869Sperseant	$cmd = "fsck_lfs $flags";
2167cd0266aSperseant	print "$cmd\n";
2177cd0266aSperseant	print LOG "$cmd\n";
2187cd0266aSperseant	open(FSCK, "$cmd 2>&1 |");
21902680591Sperseant	while(<FSCK>) {
22002680591Sperseant		print LOG;
221b8eed869Sperseant		$rline = "$_";
22202680591Sperseant		chomp;
22302680591Sperseant
22402680591Sperseant		# Known false positives (mismatch between sb and ifile,
22502680591Sperseant		# which should be expected given we're using an arbitrarily
226ebaf3982Sperseant		# old version of the ifile)
22702680591Sperseant		if (m/AVAIL GIVEN/ ||
22802680591Sperseant		    m/BFREE GIVEN/ ||
22902680591Sperseant		    m/DMETA GIVEN/ ||
2307cd0266aSperseant		    m/NCLEAN GIVEN/ ||
2317cd0266aSperseant		    m/FREE BUT NOT ON FREE LIST/ ||	# UNWRITTEN inodes OK
232b8eed869Sperseant		    m/FILE SYSTEM WAS MODIFIED/ ||
2337cd0266aSperseant		    m/FREE LIST HEAD IN SUPERBLOCK/ ) {
23402680591Sperseant			next;
23502680591Sperseant		}
23602680591Sperseant
23702680591Sperseant		# Fsck reports errors in ALL CAPS
23802680591Sperseant		# But don't count hex numbers as "lowercase".
239b8eed869Sperseant		$oline = "$_";
24002680591Sperseant		s/0x[0-9a-f]*//g;
24102680591Sperseant		if (m/[A-Z]/ && ! m/[a-z]/) {
24202680591Sperseant			$error = 1;
2437cd0266aSperseant			$errsn = $k;
244b8eed869Sperseant			$errstr = "1 $k 0x$a $oline";
245b8eed869Sperseant			# last;
24602680591Sperseant		}
247b8eed869Sperseant
248b8eed869Sperseant		# Log everything we get, except for some things we
249b8eed869Sperseant		# will see every single time.
250b8eed869Sperseant		if (m/checkpoint invalid/ ||
251b8eed869Sperseant		    m/skipping free list check/ ||
252b8eed869Sperseant		    m/expect discrepancies/) {
253b8eed869Sperseant			next;
254b8eed869Sperseant		}
255b8eed869Sperseant		$output .= $rline;
25602680591Sperseant	}
25702680591Sperseant	close(FSCK);
258b8eed869Sperseant
259b8eed869Sperseant	if ($? != 0) {
260b8eed869Sperseant		$error = 1;
261b8eed869Sperseant		$errsn = $k;
262b8eed869Sperseant		$errstr = "1 $k 0x$a <" . (hex $?) . ">";
263b8eed869Sperseant	}
264b8eed869Sperseant
265b8eed869Sperseant	if ($error || $printit) {
266b8eed869Sperseant		print $output;
267b8eed869Sperseant	}
268b8eed869Sperseant}
269b8eed869Sperseant
270b8eed869Sperseant$blstart = 0;
271b8eed869Sperseant$fps = $ssize / $fsize;
272b8eed869Sperseant$oind = ($sstart ? $sstart : 1);
273b8eed869SperseantBIGLOOP: foreach $k (sort { $a <=> $b } keys %iloc) {
274b8eed869Sperseant	$a = $iloc{$k};
275b8eed869Sperseant
276b8eed869Sperseant	if (hex($a) > hex($lastaddr)) {
277b8eed869Sperseant		print "Skipping out-of-place checkpoint $k at $a\n";
278b8eed869Sperseant		next;
279b8eed869Sperseant	}
280b8eed869Sperseant
281b8eed869Sperseant	if ($test_rfw && $iloc{$oind - 1}) {
282b8eed869Sperseant		for ($tk = $oind; $tk < $k; $tk++) {
283b8eed869Sperseant			print "Test roll-forward agent at non-checkpoint pseg $tk\n";
284b8eed869Sperseant			print LOG "Test roll-forward agent at non-checkpoint pseg $tk\n";
285b8eed869Sperseant			&copypseg($oind, $tk);
286b8eed869Sperseant			# Add -d flag here for verbose debugging info
287b8eed869Sperseant			$flags = "-p -f -i 0x" . $iloc{$oind - 1} . " $wfile";
288b8eed869Sperseant			&test_fsck($iloc{$oind - 1}, $flags, 1);
289b8eed869Sperseant			last BIGLOOP if $error;
290b8eed869Sperseant
291b8eed869Sperseant			# note lack of -i flag, since the roll-forward
292b8eed869Sperseant			# will have rewritten the superblocks.
293b8eed869Sperseant			&test_fsck($iloc{$oind - 1}, "-n -f $wfile", 0);
294b8eed869Sperseant			last BIGLOOP if $error;
295b8eed869Sperseant		}
296b8eed869Sperseant	}
297b8eed869Sperseant
298b8eed869Sperseant	print "Recreate fs state at checkpoint pseg $k (from " . ($oind - 1) .
299b8eed869Sperseant	      ")\n";
300b8eed869Sperseant	$oind = &copypseg($oind, $k);
301b8eed869Sperseant
302b8eed869Sperseant	&test_fsck($a, "", 0);
303b8eed869Sperseant
30402680591Sperseant	last if $error;
3057cd0266aSperseant	$lastgood = $k;	# record last good serial number
3067cd0266aSperseant}
307b8eed869Sperseant
308b8eed869Sperseantif ($errstr) {
309b8eed869Sperseant	print "$errstr\n";
310b8eed869Sperseant	exit 0;
311b8eed869Sperseant}
312b8eed869Sperseant
313ebaf3982Sperseantif (!$errstr) {
314ebaf3982Sperseant	print "Bring filesystem state up to log wrap\n";
315ebaf3982Sperseant	$lastgood = &copypseg($oind, 100000000000) - 1;
3167cd0266aSperseant
3177cd0266aSperseant	print "Copying this good image to $gfile\n";
3187cd0266aSperseant	system("dd bs=1m if=$rdev of=$gfile >/dev/null 2>&1");
319ebaf3982Sperseant	print "0 $lastgood 0x$a\n";
3207cd0266aSperseant	exit 0;
32102680591Sperseant}
32202680591Sperseant
3237cd0266aSperseant#
324ebaf3982Sperseant# Ifile write-checking paranoia.
325ebaf3982Sperseant#
3267cd0266aSperseant# If we found an error, try to find which blocks of the Ifile inode changed
3277cd0266aSperseant# between the last good checkpoint and this checkpoint; and which blocks
3287cd0266aSperseant# *should* have changed.  This means (1) which segments were written; and
3297cd0266aSperseant# (2) which inodes were written.  The 0 block of the Ifile should always
3307cd0266aSperseant# have changed since lfs_avail is always in flux.
3317cd0266aSperseant#
3327cd0266aSperseant
3337cd0266aSperseant$cmd = "dumplfs";
3347cd0266aSperseant$oseg = -1;
3357cd0266aSperseant%iblk = ();
3367cd0266aSperseant%iblk_done = ();
3377cd0266aSperseant%why = ();
3387cd0266aSperseant$iblk{0} = 1;
3397cd0266aSperseantfor ($i = $lastgood + 1; $i <= $errsn; $i++) {
3407cd0266aSperseant	if ($oseg != $snloc{$i}) {
3417cd0266aSperseant		$oseg = 0 + $snloc{$i};
3427cd0266aSperseant		$cmd .= " -s$oseg";
34302680591Sperseant	}
3447cd0266aSperseant}
3457cd0266aSperseant$cmd .= " $rdev";
3467cd0266aSperseant
3477cd0266aSperseantopen(DUMPLFS, "$cmd |");
3487cd0266aSperseantwhile(<DUMPLFS>) {
3497cd0266aSperseant	if (m/ifpb *([0-9]*)/) {
3507cd0266aSperseant		$ifpb = $1;
3517cd0266aSperseant	}
3527cd0266aSperseant	if (m/sepb *([0-9]*)/) {
3537cd0266aSperseant		$sepb = $1;
3547cd0266aSperseant	}
3557cd0266aSperseant	if (m/cleansz *([0-9]*)/) {
3567cd0266aSperseant		$cleansz = $1;
3577cd0266aSperseant	}
3587cd0266aSperseant	if (m/segtabsz *([0-9]*)/) {
3597cd0266aSperseant		$segtabsz = $1;
3607cd0266aSperseant	}
3617cd0266aSperseant	last if m/SEGMENT/;
3627cd0266aSperseant}
3637cd0266aSperseantwhile(<DUMPLFS>) {
3647cd0266aSperseant	chomp;
3657cd0266aSperseant
3667cd0266aSperseant	# Skip over partial segments outside our range of interest
3677cd0266aSperseant	if (m/roll_id.*serial *([0-9]*)/) {
3687cd0266aSperseant		$serno = $1;
3697cd0266aSperseant		if ($serno <= $lastgood || $serno > $errsn) {
3707cd0266aSperseant			# Skip the rest of this partial segment
3717cd0266aSperseant			while(<DUMPLFS>) {
3727cd0266aSperseant				last if m/Segment Summary/ || m/SEGMENT/;
3737cd0266aSperseant			}
3747cd0266aSperseant			next;
3757cd0266aSperseant		}
3767cd0266aSperseant	}
3777cd0266aSperseant
3787cd0266aSperseant	# Look for inodes
3797cd0266aSperseant	if (m/Inode addresses/) {
3807cd0266aSperseant		s/^[^{]*{/ /o;
3817cd0266aSperseant		s/}[^{]*$/ /o;
3827cd0266aSperseant		s/}[^{]*{/,/og;
3837cd0266aSperseant		s/v[0-9]*//og;
3847cd0266aSperseant		@ilist = split(',');
3857cd0266aSperseant		foreach $i (@ilist) {
3867cd0266aSperseant			$i =~ s/ *//og;
3877cd0266aSperseant			next if $i == 1;
3887cd0266aSperseant			$iaddr = $cleansz + $segtabsz + int ($i / $ifpb);
3897cd0266aSperseant			$iblk{$iaddr} = 1;
3907cd0266aSperseant			$why{$iaddr} .= " $i";
3917cd0266aSperseant		}
3927cd0266aSperseant	}
3937cd0266aSperseant
3947cd0266aSperseant	# Look for Ifile blocks actually written
3957cd0266aSperseant	if (m/FINFO for inode: ([0-9]*) version/) {
3967cd0266aSperseant		$i = $1;
3977cd0266aSperseant		$inoblkmode = ($i == 1);
3987cd0266aSperseant	}
3997cd0266aSperseant	if ($inoblkmode && m/^[-\t 0-9]*$/) {
4007cd0266aSperseant		s/\t/ /og;
4017cd0266aSperseant		s/^ *//o;
4027cd0266aSperseant		s/ *$//o;
4037cd0266aSperseant		@bn = split(' ');
4047cd0266aSperseant		foreach $b (@bn) {
4057cd0266aSperseant			$iblk_done{$b} = 1;
4067cd0266aSperseant		}
4077cd0266aSperseant	}
4087cd0266aSperseant}
4097cd0266aSperseantclose(DUMPLFS);
4107cd0266aSperseant
4117cd0266aSperseant# Report found and missing Ifile blocks
4127cd0266aSperseantprint "Ifile blocks found:";
4137cd0266aSperseantforeach $b (sort { $a <=> $b } keys %iblk) {
4147cd0266aSperseant	if ($iblk_done{$b} == 1) {
4157cd0266aSperseant		print " $b";
4167cd0266aSperseant	}
4177cd0266aSperseant}
4187cd0266aSperseantprint "\n";
4197cd0266aSperseant
4207cd0266aSperseantprint "Ifile blocks missing:";
4217cd0266aSperseantforeach $b (sort { $a <=> $b } keys %iblk) {
4227cd0266aSperseant	if ($iblk_done{$b} == 0) {
4237cd0266aSperseant		$why{$b} =~ s/^ *//o;
4247cd0266aSperseant		print " $b ($why{$b})";
4257cd0266aSperseant	}
4267cd0266aSperseant}
4277cd0266aSperseantprint "\n";
4287cd0266aSperseant
4297cd0266aSperseantprint "$errstr\n";
4307cd0266aSperseantexit 0;
431