--- a/ftbackup.conf.example Tue Apr 26 23:24:07 2011 +0200
+++ b/ftbackup.conf.example Wed Apr 27 16:58:51 2011 +0200
@@ -19,3 +19,10 @@
# Do we need compression? Unfortunately currently only
# global
# COMPRESSION_LEVEL = 6
+
+# Do a full backup every 7 days
+# FULL_CYCLE = 7
+
+# Always keep this number of (full) backups
+# (including the current one)
+# KEEP = 2
--- a/sbin/ftbackup Tue Apr 26 23:24:07 2011 +0200
+++ b/sbin/ftbackup Wed Apr 27 16:58:51 2011 +0200
@@ -35,6 +35,7 @@
my $opt_label = "daily";
my $opt_info = 0;
my $opt_config = "";
+my $opt_clean = 1;
my $opt_dumpdates = "/var/lib/dumpdates";
sub get_configs(@);
@@ -46,6 +47,7 @@
sub real_device($);
sub get_estimate($$);
sub devno($);
+sub unlink_old_dumps($$);
our @AT_EXIT;
END { $_->() foreach @AT_EXIT }
@@ -54,8 +56,9 @@
my %CONFIG = (
FTP_DIR => "backup/<LABEL>/<HOSTNAME>",
FTP_PASSIVE => 1,
+ COMPRESSION_LEVEL => 6,
FULL_CYCLE => 7,
- COMPRESSION_LEVEL => 6,
+ KEEP => 2,
);
@@ -74,6 +77,7 @@
"m|man" => sub { pod2usage(-exit => 0, -verbose => 3) },
"C|config=s" => sub { @CONFIGS = ($_[1]) },
"V|version" => sub { print "$ME: $VERSION\n"; exit 0 },
+ "c|clean!" => \$opt_clean,
"D|dumpdates=s" => \$opt_dumpdates,
) or pod2usage;
@@ -166,26 +170,33 @@
$ftp->try(cwd => $dir);
#verbose "Now in @{[$ftp->pwd]}.\n" if $ftp;
+ unlink_old_dumps($ftp, $cf{KEEP} + 1)
+ if $opt_clean;
# 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
foreach (reverse sort $ftp->ls) {
/^(?<date>.*)\.(?<level>\d+)$/ or next;
- $last[$+{level}] = $+{date};
- last if $+{level} == 0;
+ $last[$+{level}] = str2time $+{date};
}
}
+ # now check, which of the old backups can be purged
+ # The config KEEP tells us how many full dumps we need to
+ # keep. The pre-dump cleaning should keep this number
+ # and after successfull dump we need to cleanup again
+ #$last[0] = [ sort { $a->{stamp} <=> $b->{stamp} } @{$last[0]} ];
+
# for safety we check if there is really a full dump not older than xxx days
if ($dev->{level} > 0) {
if (!@last) {
$dev->{level} = 0;
warn "adjusted backup level to 0, last full backup missing\n";
- } elsif ($NOW - str2time($last[0]) > ($cf{FULL_CYCLE} * 86_400)) {
+ } elsif (($NOW - $last[0]) > ($cf{FULL_CYCLE} * 86_400)) {
$dev->{level} = 0;
warn sprintf "adjusted backup level to 0, last full backup is %.1f days old\n",
- ($NOW - str2time $last[0])/86_400;
+ ($NOW - $last[0])/86_400;
}
}
@@ -287,6 +298,9 @@
update_devnames($opt_dumpdates, $dev->{dump} => $dev->{rdev})
if $opt_dumpdates;
+
+ unlink_old_dumps($ftp, $cf{KEEP})
+ if $ftp and $opt_clean;
}
}
@@ -518,6 +532,34 @@
return @devs;
}
+sub unlink_old_dumps($$) {
+ my ($ftp, $keep) = @_;
+ my @dumps;
+ foreach ($ftp->ls) {
+ /^(?<date>.*)\.(?<level>\d+)$/ or next;
+ push @{$dumps[$+{level}]} => { file => $_, date => $+{date}, stamp => str2time($+{date})};
+ }
+
+ ### @dumps
+
+ # sort the level 0 dumps by date and remove all but the last $keep
+ # ones.
+ # if we found level 0 dumps, we remove all level 1+ dumps older than
+ # the oldest level 0 dump we'll remove
+ @{$dumps[0]} = reverse sort { $a->{stamp} <=> $b->{stamp} } @{$dumps[0]};
+ my @unlink = @{$dumps[0]}[$keep..$#{$dumps[0]}];
+ push @unlink => grep { $_->{stamp} <= $unlink[0]->{stamp} } @{@dumps[1..$#dumps]}
+ if @unlink;
+ ### @unlink
+
+ foreach (@unlink) {
+ say "DELETE: $_->{file}";
+ next if $opt_dry;
+ $ftp->delete($_->{file});
+ }
+}
+
+
#/dev/vda1 0 Thu Apr 14 12:54:31 2011 +0200
#/dev/vda1 1 Thu Apr 14 12:54:16 2011 +0200
@@ -567,12 +609,11 @@
Even more debugging is shown using the DEBUG=1 environment setting.
-=item B<--clean> [I<days>]
+=item B<--clean>
Cleanup older backups we do not need (that is: incremental backups with
-no previous full backup. If I<days> are given, then all full backups older than
-the number of I<days> are removed (and all incremental backups based on these
-full backups). (default: 0 and not implemented)
+no previous full backup. The number of old backups we keep
+is read from the configuration file. (default: 1)
=item B<--dry>
@@ -624,8 +665,47 @@
FTP_HOST = <no default>
FTP_DIR = "backup/<LABEL>/<HOSTNAME>"
FTP_PASSIVE = 1
+ COMPRESSION_LEVEL = 6
FULL_CYCLE = 7
- COMPRESSION_LEVEL = 6
+ KEEP = 2
+
+=over
+
+=item KEY
+
+The encryption key to use. (We use symmetric blowfish encryption currently.)
+
+=item FTP_HOST
+
+The FTP host to send the backup to.
+
+=item FTP_DIR
+
+A template for storing the backup file(s). Each dumped file system needs
+its own directory!
+
+=item FTP_PASSIVE
+
+A switch to activate the usage of passive FTP.
+
+=item COMPRESSION_LEVEL
+
+The level of the used gzip compression.
+
+=item FULL_CYCLE
+
+A full backup is forced if the last full backup is older than thi number
+of days.
+
+=item KEEP
+
+The number of full backups (including the current one!) to keep. It means, that
+normally you'll get KEEP backups in your backup directory. Useless
+incremental backups are deleted automgically.
+
+=back
+
+
=head2 F<.netrc>