Skip to content

Instantly share code, notes, and snippets.

@anazawa
Created October 9, 2013 23:35
Show Gist options
  • Save anazawa/6910434 to your computer and use it in GitHub Desktop.
Save anazawa/6910434 to your computer and use it in GitHub Desktop.
#!/usr/bin/env perl
use strict;
use warnings;
use Time::Piece;
use Time::Seconds;
our $VERSION = '0.02';
my $file_system = shift || '/';
#my $backupdir = '/backup/esprimo';
my $backupdir = '/home/anazawa/work/backup/tmp';
my $size_limit = 100000; # MB
my @fstab;
if ( open my $fh, '<', '/etc/fstab' ) {
while ( <$fh> ) {
chomp;
next if /^\#/;
push @fstab, [ split ];
}
close $fh;
}
my ( $device, $mount_point );
if ( $file_system =~ m{^/dev/} ) {
$device = $file_system;
$mount_point = { map { @{$_}[0,1] } @fstab }->{ $device };
}
else {
$mount_point = $file_system;
$device = { map { @{$_}[1,0] } @fstab }->{ $mount_point };
}
my @dumpdates;
if ( open my $fh, '<', '/etc/dumpdates' ) {
while ( my $line = <$fh> ) {
chomp $line;
my ( $d, $level, $date ) = split ' ', $line, 3;
next unless $d eq $device;
$date = localtime->strptime( $date, '%a %b %e %T %Y' );
push @dumpdates, { level => $level, date => $date };
}
close $fh;
}
my $prefix = $mount_point eq '/' ? 'root' : ( split '/', $mount_point )[-1];
my $this_backup = localtime;
my @full_backups = map { $_->{date} } grep { $_->{level} == 0 } @dumpdates;
if ( !@dumpdates or $this_backup->ymd(q{}) > $dumpdates[-1]{date}->ymd(q{}) ) {
my $level = @dumpdates ? $dumpdates[-1]{level} + 1 : 0;
$level = 1 if $level > 7; # differencial backup
$level = 0 if @full_backups and $this_backup - $full_backups[-1] >= ONE_MONTH;
my $file = "$backupdir/$prefix";
$file .= '-' . $this_backup->ymd(q{});
$file .= $level == 1 ? '-D' : '-I' if $level;
$file .= '.dump';
die "File already exists: $file" if -e $file;
# TODO: -L is missing
my @options = (
"-$level", # dump level
'-u', # update /etc/dumpdates
'-a', # auto-size
'-b' => 64, # blocksize
'-C' => 32, # cachesize
'-f' => $file, #
);
system '/sbin/dump', @options, $file_system;
}
my @old_files;
if ( @full_backups and opendir my $dh, $backupdir ) {
for my $basename ( sort readdir $dh ) {
next unless $basename =~ /^$prefix\-(\d{8})(?:\-\w)?\.dump$/;
last if $1 >= $full_backups[-1]->ymd(q{});
push @old_files, $basename;
}
closedir $dh;
}
# TODO: use autodie;
if ( @old_files ) {
( my $tarball = $old_files[0] ) =~ s/\.dump$/\.tar\.gz/;
chdir $backupdir or die "Can't cd to $backupdir: $!\n";
die "File already exists: $backupdir/$tarball" if -e $tarball;
system( 'tar', '-czf', $tarball, @old_files ) == 0 or die "Failed to create tarball";
unlink or warn "Can't unlink $_: $!" for @old_files;
}
__END__
=head1 NAME
dump.pl - Multilevel incremental backup using dump(8)
=head1 SYNOPSIS
./dump.pl filesystem
=head1 DESCRIPTION
=cut
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment