#!/usr/bin/perl
die "fs-diff 1.1, check for new/changed/deleted files.\n
fs-diff	                        Save current state to /var/fs-diff/.snapshot
fs-diff --snapshot		Print current state
fs-diff appname [snap1 [snap2]] Save difference between current state and
                                /var/fs-diff/.snapshot to /var/fs-diff/appname
				With snap1 - diff current state and snap1
				With snap1 and snap2 - diff snap1 and snap2\n" 
    if grep {/^-h|--help$/} @ARGV;
$stdout = shift if $ARGV[0] eq "--snapshot";
($app_name, $snap1, $snap2) = @ARGV;
if (not defined $app_name) {
    open DUMP,">/var/fs-diff/.snapshot" and select DUMP or die $! if ! $stdout;
    dir_snapshot("/");
} else {
    die "bad appname\n" unless $app_name=~/^\w[\w\d-.+]*$/;
    open(DIFF,">/var/fs-diff/$app_name") and select DIFF or die $!;
    open(OLD,(defined $snap1 ? $snap1 : "/var/fs-diff/.snapshot")) or die $!;
    open(NEW,(defined $snap2 ? $snap2 : "$0 --snapshot |")) or die $!;
    diff_snapshots(\*OLD, \*NEW);
}

sub dir_snapshot {
    my $cwd = $_[0];
    my $file;
    my %EXCL = map {$_,1} qw(/dev /home /mnt /proc /root /tmp /usr/src 
	/var/fs-diff /var/log /var/run /var/www);	# /var/qmail /var/oops
    local ($,, $\) = (",","\n");
    local *CWD;
    opendir(CWD, $cwd) or die "can't opendir `$cwd': $!";
    while ($file = readdir(CWD)) {
	next if $file eq ".." or $file eq "." or $EXCL{$file = $cwd.$file};
	print((lstat $file)[2,4,5,7,9], $file . (-d $file && "/").
	    (-l $file && " -> ".readlink($file)));
	dir_snapshot($file."/") if -d _ and not -l _;
    }
}
sub diff_snapshots {
    my ($OLD, $NEW) = @_;
    local ($,, $\) = (",","\n");
    my ($file, %F);
    while (<$OLD>) {
        /^(?:[^,]*,){5}(.*)$/;
        ($file = $1) =~ s/ -> .*//;
        $F{$file} = $_;
    }
    while (<$NEW>) {
        /^(?:[^,]*,){5}(.*)$/;
        ($file = $1) =~ s/ -> .*//;
        if    (not exists $F{$file}) 		    { print("  $file") } 
        elsif ($_ ne $F{$file} and $file !~ m{/$})  { print("? $file") }
        delete $F{$file};
    }
    print "- $_" for keys %F;
}
