#!/usr/bin/perl -s

# rdistsumm - summarize rdist stdout and stderr output, highlighting any errors
# Steve Kinzler, steve@kinzler.com, Jan 93/Aug 93
# https://kinzler.com/me/home.html#unixadm

# Works for both old (BSD) and new (USC, 6.*) output formats.
# Works for both real and verification runs.
# Can be used to monitor rdists since errors will be reported as they occur.

$usage = "usage: $0 [ -g ] [ -e ] [ -s ] [ -v ] [ file ... ]
	-g	ignore unknown group errors
	-e	report errors only (disable summary reporting)
	-s	report summary only (disable error reporting)
	-v	report hosts as they finish\n";

die $usage  if $h;

$| = 1;

close STDIN if @ARGV;

$nohost = 'NO_HOST';
$host   = $nohost;
$hosts{$host}++;
$upatt  = 'updat(ing|ed)|install(ing|ed)|remov(ing|ed)|mkdir';

while (<>) {
	next if $g && /(^|: )unknown group /i;

	if (/^(\S+): updating host /i) {
		push(@hosts, $1);
	}
	if ((($h) = /^(\S+): /) && grep($h eq $_, @hosts)) {
		$host = $h;
		s/(^\S+: +)//;
		$label = $1;
	} else {
		$label = '';
	}

	next if $item{$host} && &doitem($_);

	if (/^updating host (\S*)/i) {
		$newhost = $1;
		&enderror() if $error{$host};
		if (! $label && $newhost ne $host) {
			&endhost();
			$host = $newhost;
		}
		$hosts{$host}++;
		$prev{$host} = $_;

	} elsif (/^updating of .* finished/i) {
		&enderror() if $error{$host};
		&endhost()  if $label;
		undef $prev{$host};

	} elsif (/Not installed, by special request/i) {
		&enderror() if $error{$host};
		undef $prev{$host};

	} elsif (/^notify[ :]/i) {
		&enderror() if $error{$host};
		$prev{$host} = $_;

	} elsif (/^($upatt)[ :]/io || /: ($upatt)([ :]|$)/io ||
		 /(^|: )(ch(grp|mod|own)|need) (to|from) /i) {
		&enderror() if $error{$host};
		$item{$host} = $_;

	} else {
		$errors{$host} .= $prev{$host} if $prev{$host};
		delete $prev{$host};
		$errcnt{$host}++, next	       if $_ eq $error{$host};
		&enderror()		       if $error{$host};
		$error{$host} = $_;
		$errcnt{$host} = 1;
	}
}

foreach $host (     keys %item)  { &doitem(''); }
foreach $host (     keys %error) { &enderror(); }
foreach $host (sort keys %hosts) { &endhost();  }

exit if $e;

$: = ' ';
format STDOUT =
  ~~^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    $hosts
.

foreach (sort keys %report) {
	undef %hosts;
	foreach $host (split(/ /, $report{$_})) {
		$hosts{$host}++;
	}
	$hosts = join(' ', sort keys %hosts);
	$files{$hosts} .= $_;
}

foreach $hosts (sort keys %files) {
	print "\n", $files{$hosts};
	write;
}

sub doitem {
	local($_) = @_;
	$item{$host} .= $_, return 1 if /^(cmd)?special[ :]/i;

	$report{$item{$host}} .= ($report{$item{$host}}) ? " $host" : $host;
	$prev{$host} = $item{$host};
	delete $item{$host};
	return 0;
}

sub enderror {
	$errors{$host} .= $error{$host};
	$errors{$host} .= "previous message repeated $errcnt{$host} times\n"
		if $errcnt{$host} > 1;
	delete $error{$host};
	delete $errcnt{$host};
}

sub endhost {
	print "updating of $host finished\n" if $v && $host ne $nohost;
	print "########## $host ##########\n$errors{$host}\n"
		if ! $s && $errors{$host};
	delete $errors{$host};
	delete $hosts{$host};
}
