#!/usr/bin/perl
$ENV{'PATH'} = '/usr/local/bin:/usr/ucb:/usr/bsd:/bin:/usr/bin:'
	     . '/usr/local/etc:/etc:/usr/etc:/sbin:/usr/sbin';

$customdf = 'di -s n -f Sbuv2M';
$xfsinven = 'xfsdump -I depth=2';

# dumpdates - list last dump dates for mounted filesystems
# Steve Kinzler, steve@kinzler.com, Feb 94
# https://kinzler.com/me/home.html#unixadm

use Getopt::Std;	$Getopt::Std::STANDARD_HELP_VERSION = 1;

$usage = "usage: $0 [ -h0123456789au ] [ -m host ] [ patt ... ]
	-h	display just this help message
	-0-9	display just dates for these dump levels (default all)
	-a	also display filesystems with no relevant dump dates
	-u	also display current disk usage in kilobytes
	-m	report for the given remote host instead of the local host
	patt	restrict output to lines matching any of the given patterns
By default, lists last dump dates for local mounted filesystems, taking
data from /etc/dumpdates files and XFS inventories.\n";

getopts('h0123456789aum:') || die $usage;

die $usage if $opt_h;

foreach (0 .. 9) {
	push(@levels, $_) if eval "\$opt_$_";
}
@levels = (0 .. 9) unless @levels;

$head = $tail = '';
if ($opt_m) {
	$rsh = (-f '/usr/bin/remsh') ? '/usr/bin/remsh' :
	       (-f '/usr/bin/rcmd')  ? '/usr/bin/rcmd'  : 'rsh';
	$head = "$rsh -n \"$opt_m\" " .
		"'exec /bin/sh -c \"PATH=$ENV{'PATH'}; exec ";
	$tail = "\"'";
}

&loadmount();
&loaddate()  if grep(! /^xfs$/i, values %type);
&loadinven() if grep(  /^xfs$/i, values %type);
if ($opt_u && ($warn = &loadused())) {
	warn $warn if &loadused($customdf);
}

foreach $spec (sort keys %mount) {
	$flag = 0;
	foreach (@levels) {
		$flag++, &printline($spec, $_) if defined $date{$spec, $_};
	}
	&printline($spec, '-') if $opt_a && ! $flag;
}

###############################################################################

sub printline {
	local($spec, $level) = @_;
	local($used, $line);

	$used = sprintf(' %7s', ($used{$spec} =~ /\S/) ? $used{$spec} : '?');
	$line = sprintf("%-19s %1s %-24s%s %s\n", $spec, $level,
			($level eq '-') ? '??? ??? ?? ??:??:?? ????'
					: $date{$spec, $level},
			($opt_u) ? $used : '', $mount{$spec});
	print $line if ! @ARGV || grep($line =~ /$_/, @ARGV);
}

sub loadmount {
	open(MOUNT, "${head}mount$tail |") ||
		die "$0: cannot run mount ($!)";

	while (<MOUNT>) {
		s:^\s+(/\S*)\s+(/\S*):$1 on $2:;	# for aix3
		($type) = / type (\S+) /;
		$type = 'UNKNOWN' unless $type;
		if (m:^/dev/\S* on /dev/:) {
			0;
		} elsif (m:^(/dev/\S*) on (/\S*):) {
			($mount{$1}, $type{$1}) = ($2, $type);
		} elsif (m:^(/\S*) on (/dev/\S*):) {
			($mount{$2}, $type{$2}) = ($1, $type);
		}
	}

	close MOUNT;
}

sub loaddate {
	unless (open(DUMPDATES, "${head}cat /etc/dumpdates$tail |")) {
		warn "$0: cannot cat /etc/dumpdates ($!)";
		return;
	}

	while (<DUMPDATES>) {
		s/^\s+//; s/\s+$//;
		next if /^#/ || /^$/;

		($spec, $level, $date) = split(/\s+/, $_, 3);
		$spec =~ s,/dev/r,/dev/,;
		$date{$spec, $level} = $date
			unless $type{$spec} =~ /^xfs$/i ||
			       defined $date{$spec, $level};
	}

	close DUMPDATES;
}

sub loadinven {
	unless (open(XFSINVEN, "${head}$xfsinven$tail |")) {
		warn "$0: cannot $xfsinven ($!)";
		return;
	}

	# Note: we assume inventory items are appended chronologically
	# and that only items for the local host are in the inventory.

	$spec = $date = '';
	while (<XFSINVEN>) {
		s/\s*$//, s;^[^/:]*:/;/;, s;/dev/r;/dev/;, $spec = $_, next
			if s/^\t\tdevice:\s*//;
		s/\s*$//, $date = $_, next if s/^\t\ttime:\s*//;
		if (s/^\t\tlevel:\s*//) {
			s/\s*$//, $date{$spec, $_} = $date
				if $type{$spec} =~ /^xfs$/i;
			$spec = $date = '';
		}
	}

	close XFSINVEN;
}

sub loadused {
	local($df) = ($_[0]) ? $_[0] : 'df';

	return "$0: cannot run \"$df\" ($!)"
		unless open(DF, "$head$df$tail |");

	$_ = <DF>;
	if    (/^Filesystem\s+1(024|K)-blocks\s+Used\s+/i)  { $fmt = 1; }
	elsif (/^Filesystem\s+512-bl(oc)?ks\s+used\s+/i)    { $fmt = 2; }
	elsif (/^Filesystem\s+Total KB\s+free\s+%used\s+/i) { $fmt = 3; }
	elsif (/^Filesystem\s+Total\s+kbytes\s+/i)	    { $fmt = 4; }
	elsif (/^Filesystem\s+Type\s+blocks\s+use\s+/i)	    { $fmt = 5; }
	elsif (/^Filesystem\s+Type\s+kbytes\s+use\s+/i)	    { $fmt = 6; }
	elsif (/^Filesystem\s+kbytes\s+used\s+/i)	    { $fmt = 7; }
	else {
		close DF;
		return "$0: unknown \"$df\" format";
	}

	while (<DF>) {
		@__ = split;
		if (grep($fmt == $_, (1, 4, 7))) {
			$used{$__[0]} = $__[2];
		} elsif ($fmt == 2) {
			$used{$__[0]} = int($__[2] / 2 + .5);
		} elsif ($fmt == 3) {
			$used{$__[0]} = int($__[1] * $__[3] / 100 + .5);
		} elsif ($fmt == 5) {
			$used{$__[0]} = int($__[3] / 2 + .5);
		} elsif ($fmt == 6) {
			$used{$__[0]} = $__[3];
		}
	}

	close DF;
	return '';
}
