--- a/bin/ftbackup Fri Apr 29 17:43:52 2011 +0200
+++ b/bin/ftbackup Mon May 02 14:41:49 2011 +0200
@@ -14,6 +14,7 @@
use Cwd qw(realpath);
use English qw(-no_match_vars);
use if $ENV{DEBUG} => qw(Smart::Comments);
+use File::Temp;
$ENV{LC_ALL} = "C";
@@ -25,7 +26,7 @@
my $HOSTNAME = hostname;
my $NOW = time();
-my $opt_level = 7;
+my $opt_level = undef;
my $opt_today = strftime("%F", localtime $NOW);
my @opt_debug = ();
my $opt_verbose = 0;
@@ -40,6 +41,7 @@
sub slurp($);
sub get_configs(@);
sub get_candidates();
+sub get_excludes($@);
sub verbose(@);
sub update_devnames($$$);
sub get_history(@);
@@ -94,9 +96,11 @@
# get the backup candiates -> all file systems from /etc/fstab
# with a dump frequence > 0
my @devs = get_candidates();
+ get_excludes(\%cf, @devs);
### %cf
### @devs
+ ### x: exit
verbose +(map { "candidate: $_->{dev} as $_->{rdev}\n" } @devs), "\n";
@@ -175,7 +179,6 @@
$dir =~ s/_/__/g;
$dir =~ s/\//_/g;
$dir = "$cf{FTP_DIR}/$dir";
-
my @last;
if ($ftp) {
$ftp->home();
@@ -299,7 +302,7 @@
if $opt_dumpdates;
exec
-"dump -$dev->{level} -L $label -f- -u -z$cf{COMPRESSION_LEVEL} $dev->{dump}"
+"dump -$dev->{level} -L $label -f- -u -z$cf{COMPRESSION_LEVEL} -E $dev->{exclude}{inodes} $dev->{dump}"
. "| openssl enc -pass env:key -salt -blowfish";
die "Can't exec dumper\n";
};
@@ -330,6 +333,49 @@
print STDERR @_;
}
+sub get_excludes($@) {
+ my $cf = shift;
+ my @devs = @_;
+
+ foreach my $dev (@devs) {
+
+ my $exclude_files0 = File::Temp->new;
+ my $exclude_inodes = File::Temp->new;
+
+ if (my $excludelist = $cf->{EXCLUDE}{$dev->{dev}}) {
+ my (%files, %inodes);
+ if (-x $excludelist) {
+ # executable exclude list
+ # <inum><space><filename><NULL>
+ local $/ = "\0";
+ open(my $ex, "-|", "$excludelist") or die "Can't open $excludelist: $!\n";
+ while (<$ex>) {
+ chomp;
+ my ($i, $f) = split " ", $_;
+ $inodes{$i} = undef;
+ $files{$f} = undef;
+ }
+ }
+ else {
+ open(my $ex, "<", $excludelist) or die "Can't open $excludelist: $!\n";
+ while (<$ex>) { chomp; @files{(glob)} = () }
+ @inodes{ map { (stat)[1] } keys %files} = ();
+
+ }
+
+ foreach (keys %files) { print {$exclude_files0} $_, "\0" }
+ foreach (keys %inodes) { say {$exclude_inodes} $_ }
+ }
+ $exclude_files0->flush;
+ $exclude_inodes->flush;
+
+ # keep the FH to avoid removing the tmp files
+ $dev->{exclude}{files0} = $exclude_files0;
+ $dev->{exclude}{inodes} = $exclude_inodes;
+ }
+ return;
+}
+
sub get_candidates() {
# return the list of backup candidates
@@ -395,6 +441,11 @@
map { chomp } values %h;
%r = (%r, %h);
}
+ foreach (grep /^EXCLUDE:/ => keys %r) {
+ /^EXCLUDE:(\S+)/;
+ $r{EXCLUDE}{$1} = delete $r{$_};
+ }
+ ### %r
return %r;
}
@@ -528,7 +579,7 @@
sub get_estimate($$) {
my ($dev, $level) = @_;
print STDERR "% estimating $dev->{rdev} at level $level: ";
- chomp(my $_ = `dump -S -$level $dev->{rdev}`);
+ chomp(my $_ = `dump -S -$level -E $dev->{exclude}{inodes} $dev->{rdev}`);
print STDERR human_number($_) . "Byte\n";
return $_;
}
@@ -538,25 +589,25 @@
foreach my $dev (@devs) {
- if (defined $opt_level) {
- $dev->{level} = $opt_level;
- }
- elsif (!$dev->{last}
+ if (!$dev->{last}
or not $dev->{last}[0]
or $NOW - $dev->{last}[0] > ($cycle * 86_400))
{
$dev->{level} = 0;
}
- else { $dev->{level} = 0 }
-
- # now we'll see if the level really saves space compared
- # with the next lower level
- my @estimates;
- while ((my $l = $dev->{level}) > 0) {
- $estimates[$l] //= get_estimate($dev, $l);
- $estimates[$l - 1] //= get_estimate($dev, $l - 1);
- last if ($estimates[$l - 1] - $estimates[$l]) / $estimates[$l - 1] >= 0.10;
- --$dev->{level};
+ elsif (defined $opt_level) {
+ $dev->{level} = $opt_level
+ }
+ else {
+ my @estimates;
+ for (my $l = 0; $l < 9; ++$l) {
+ $estimates[$l] //= get_estimate($dev, $l);
+ $estimates[$l + 1] //= get_estimate($dev, $l + 1);
+ if (($estimates[$l] - $estimates[$l + 1]) / $estimates[$l] < 0.1) {
+ $dev->{level} = $l;
+ last;
+ }
+ }
}
warn "% $dev->{dev} will use level $dev->{level}\n";
}
@@ -719,6 +770,7 @@
COMPRESSION_LEVEL = 6
FULL_CYCLE = 7
KEEP = 2
+ EXCLUDE:<devpath> = <exclude file>
=over
@@ -754,6 +806,19 @@
normally you'll get KEEP backups in your backup directory. Useless
incremental backups are deleted automgically.
+=item EXCLUDE
+
+Here you may configure a list of files to be excluded on a per file system base
+
+ EXCLUDE:/dev/md1 = /etc/ftbackup.d/md1.exclude
+
+This file should contain a list (line by line) of files to be excluded from the
+backup. The file may be executable (similiar to the automounter executable maps),
+in that case, the file is expected to print a list of records. Each record contains of
+two space separated fields, inode number and the file name. The records are delimited by
+a NULL character.
+
+
=back
=head2 F<.netrc>
--- a/ftbackup.conf.example Fri Apr 29 17:43:52 2011 +0200
+++ b/ftbackup.conf.example Mon May 02 14:41:49 2011 +0200
@@ -27,3 +27,5 @@
# Always keep this number of (full) backups
# (including the current one)
# KEEP = 2
+
+# EXCLUDE:<fs> = <name of exclude list>