--- a/ftbackup Tue Oct 27 22:32:42 2009 +0100
+++ b/ftbackup Wed Oct 28 23:00:02 2009 +0100
@@ -8,6 +8,7 @@
use Perl6::Slurp;
use Getopt::Long;
use Sys::Hostname;
+use Time::Local;
use Pod::Usage;
use POSIX qw(strftime);;
use English qw(-no_match_vars);
@@ -23,7 +24,7 @@
my $NODE = hostname;
my $NOW = time();
-my $opt_level = 0;
+my $opt_level = undef;
my $opt_today = strftime("%F", localtime $NOW);
my @opt_debug = ();
my $opt_verbose = 0;
@@ -34,6 +35,7 @@
sub get_configs(@);
sub get_candidates();
sub verbose(@);
+sub iso2epoch($);
our @AT_EXIT;
END { $_->() foreach @AT_EXIT };
@@ -90,10 +92,25 @@
verbose "Now in @{[$ftp->pwd]}.\n";
+ # examine the situation and decide about the level
+ # FIXME: currently we simply run a full dump every FULL_CYCLE
+ # days, the intermediate dumps are level 1
+ my @last;
+ foreach (reverse sort $ftp->ls) {
+ /^(?<date>.*)\.(?<level>\d+)$/;
+ $last[$+{level}] = $+{date};
+ last if $+{level} == 0;
+ }
+
+ if (not defined $opt_level) {
+ $opt_level =
+ ($NOW - iso2epoch $last[0])/86400 > $cf{FULL_CYCLE} ? 0 : 1;
+ }
+
my $file = strftime("%F_%R", localtime $NOW)
. ".$opt_level";
my $label = "$NODE:" . basename($dev->{rdev});
- verbose "Working on $dev->{dev} as $dev->{rdev} on $dev->{mountpoint}, stored as $file\n";
+ verbose "\tdumping $dev->{dev} as $dev->{rdev} on $dev->{mountpoint} to $file\n";
next if $opt_dry;
## complain if there is already a full backup in this
@@ -187,6 +204,8 @@
# $dev does not have to contain the real device
my $rdev = $dev;
if ($dev ~~ /^(LABEL|UUID)=/) {
+ # NOTE: dump is able to handle LABEL=... too, but I think
+ # it's more easy for recovery to know the real device
chomp($rdev = `blkid -c /dev/null -o device -t '$dev'`);
}
$rdev = readlink $rdev while -l $rdev;
@@ -277,6 +296,15 @@
sub get_home { return $data{ref shift}{home} };
}
+sub iso2epoch($) {
+ $_[0] =~ /(?<year>\d+)\D(?<mon>\d+)\D(?<mday>\d+)
+ (?:\D(?<hour>\d\d)\D(?<min>\d\d)(?:\D(?<sec>\d\d))?)?/x;
+ my %iso = ((sec => 0, min => 0, hour => 0), %+);
+ $iso{mon}--;
+ $iso{year} += 1900 if $iso{year} < 100;
+ return timelocal(@iso{qw/sec min hour mday mon year/});
+}
+
__END__
=head1 NAME
@@ -308,7 +336,8 @@
=item B<-l>|B<--level> I<level>
The backup level. Level other than "0" needs a previous
-level 0 (full) backup. (default: 0)
+level 0 (full) backup. If not specified, it is choosen automagically.
+(default: undef)
=item B<-L>|B<--label> I<label>
@@ -322,6 +351,8 @@
=head1 FILES
+=head2 Configuration
+
The config files are searched in the following places:
/etc/ftbackup
@@ -333,6 +364,21 @@
be a config file. The config files have to be mode 0600 and they have to be
owned by the EUID running the process.
+The config file may contain the following items (listed with their built in defaults)
+
+ KEY = <no default>
+ FTP_HOST = <no default>
+ FTP_DIR = "backup/<LABEL>/<NODE>"
+ FTP_PASSIVE = 1
+ FULL_CYCLE = 7
+
+=head2 F<.netrc>
+
+You may miss the login information for the FTP server. Currently we rely on a valid
+F<~/.netrc> entry. An example line of the F<~/.netrc>:
+
+ machine ... login ... password ...
+
=cut
# vim:sts=4 sw=4 aw ai sm: