#!/usr/bin/perl

# na_snapmon - monitor snapshot usage and keep it under control
# Copyright (C) 1998  Daniel Quinlan
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

use Getopt::Std;
require "find.pl";

sub usage;
sub trim_snapshots;
sub snap_delete;

my $limit;
my $prog;

$prog = $0;
$prog =~ s@.*/@@;

getopts("hd");

if ($opt_h) {
    &usage;
    exit 0;
}

foreach $dir (@ARGV) {
    my $df_worked = 0;
    if (! -d $dir) {
	warn("$prog: $dir: no such snapshot mount point");
    }
    open (DF, "df -k $dir |");
    while (<DF>) {
	if (/[0-9]%/) {
	    $df_worked = 1;
	    ($fs, $blocks, $used, $avail, $capacity, $mount) = split;
	    if ($capacity !~ /^[0-9]?[0-9]%/) {
		$fs =~ s/:.*//;
		trim_snapshots($fs, $dir);
	    }
	}
    }
    close (DF);
}

sub trim_snapshots {
    my ($filer, $dir) = @_;
    my (@list, @snapshots, %atime);

    # read snapshot list
    opendir(DIR, $dir) || die "can't opendir $dir: $!";
    @snapshots = grep { ! /^\.\.?$/ && -d "$dir/$_" } readdir(DIR);
    closedir DIR;

    # sort by atime
    foreach $entry (@snapshots) {
	$atime{$entry} = -A "$dir/$entry";
    }
    @snapshots = sort {$atime{$a} <=> $atime{$b}} @snapshots;

    # maybe delete something
    while ($s = (pop @snapshots)) {
	# try to delete dump snapshots more than two days old, but since
	# this might fail, keep trying to delete after this one.
	if ($s =~ /^snapshot_for_(dump|backup)\.[0-9]+$/ && $atime{$s} > 2) {
	    snap_delete($filer, $s);
	    next;
	}
	# skip manual snapshots
	next if ($s !~ /^(hourly|nightly|weekly)\.[0-9]+$/);
	# leave one snapshot at all times
	next if ($s =~ /^hourly\.0$/);
	snap_delete($filer, $s);
	last;
    }
}

sub snap_delete {
    my ($filer, $snapshot) = @_;

    if ($opt_d || ($> != 0)) {
	print "debug: rsh $filer snap delete $snapshot\n";
    }
    else {
	system("logger -t na_snapmon \"rsh $filer snap delete $snapshot\"");
	system("rsh $filer snap delete $snapshot");
    }
}

sub usage {
    print <<EOF;
usage: $prog [-hd] [list of snapshot mount points]

 -h        print this help
 -d        debugging mode: don't do, just show

The best way to use this program is from a root cron job running
on an adminhost for the Network Appliance(s).  Running it every
10 minutes is sufficient.
EOF
}
