bei mir läuft BackupPC 24/7 und macht täglich erfolgreich backups von verschiedenen Client´s
zusätzlich beinhaltet dieser Patch 2 neue Dateien,
BackupPC_fixPoolMdsums
BackupPC_verifyPool
Download dieser Patch lässt sich auch in bereits konfigurierte installationen einspielen, dafür bei Punkt 3 weiter machen
Installation BackupPC (Debian Jessie)
1. als erstes wird ein System Update gemacht und anschliessend BackupPC über das debian Repository installiert
Code: Alles auswählen
apt-get update && apt-get dist-upgrade
apt-get install backuppc
Code: Alles auswählen
htpasswd /etc/backuppc/htpasswd backuppc
Code: Alles auswählen
/etc/init.d/backuppc stop
BackupPC ist in diesem fall in /usr/share/backuppc installiert, das Archiv beinhaltet einen Ordner usr der über den Ordner auf dem Server kopiert wird und somit die Dateien überschreibt die verändert wurden, anschliessend wird BackupPC gestartet
Code: Alles auswählen
/etc/init.d/backuppc start
Code: Alles auswählen
#!/usr/bin/perl
#============================================================= -*-perl-*-
#
# BackupPC_fixPoolMdsums: Rename/move pool files if mdsum path name invalid
#
# DESCRIPTION
# See 'usage' for more detailed description of what it does
#
# AUTHOR
# Jeff Kosowsky
#
# COPYRIGHT
# Copyright (C) 2011 Jeff Kosowsky
#
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
#========================================================================
#
# Version 0.2, released January 2011 (BackupPC_fixPoolMdsums)
# Version 3.3.1-1, patched 8 Apr 2016.
#
#========================================================================
use strict;
use warnings;
use lib "/usr/share/BackupPC/lib";
use BackupPC::Lib;
use BackupPC::jLib 0.4.0; # Requires version >= 0.4.0
use File::Glob ':glob';
use Getopt::Long qw(:config no_ignore_case bundling);
#Variables
my $bpc = BackupPC::Lib->new or die("BackupPC::Lib->new failed\n");
my $md5 = Digest::MD5->new;
my $MAXLINKS = $bpc->{Conf}{HardLinkMax};
#Option variables:
my $Force;
my $warndups;
my $outfile;
my $TopDir = my $TopDir_def = $bpc->{TopDir};
my $verbose=0;
#$dryrun=0; #Global variable defined in jLib.pm (do not use 'my')
$dryrun=1; #Global variable defined in jLib.pm (do not use 'my')
usage() unless(
GetOptions(
"dryrun|d!" => \$dryrun,
"Force" => \$Force, #Override stuff...
"outfile|o=s" => \$outfile,
"topdir|t=s" => \$TopDir, #Location of TopDir
"verbose|v+" => \$verbose, #Verbosity (repeats allowed)
"warndups|w" => \$warndups, #Warn if dup created in new chain
)
&& defined $outfile
);
#############################################################################
if($TopDir ne $TopDir_def) {
#NOTE: if we are not using the TopDir in the config file, then we
# need to manually override the settings of BackupPC::Lib->new
# which *doesn't* allow you to set TopDir (even though it seems so
# from the function definition, it gets overwritten later when the
# config file is read)
$TopDir =~ s|//*|/|g; #Remove any lurking double slashes
$TopDir =~ s|/*$||g; #Remove trailing slash
$bpc->{TopDir} = $TopDir;
$bpc->{Conf}{TopDir} = $TopDir;
$bpc->{storage}->setPaths({TopDir => $TopDir});
$bpc->{PoolDir} = "$bpc->{TopDir}/pool";
$bpc->{CPoolDir} = "$bpc->{TopDir}/cpool";
}
%Conf = $bpc->Conf(); #Global variable defined in jLib.pm (do not use 'my')
#############################################################################
my $compress = $Conf{CompressLevel};
my $pool = $compress > 0 ? "cpool" : "pool";
my $compare = $compress > 0 ? \&zcompare2 : \&jcompare;
my $file2md5 = $compress > 0 ? \&zFile2MD5 : \&File2MD5;
my ($OUT);
die "ERROR: '$outfile' already exists!\n" if -e $outfile;
open($OUT, '>', "$outfile") or
die "ERROR: Can't open '$outfile' for writing!($!)\n";
chdir $TopDir;
if(!$Force &&
(my @partialbackups = glob("pc/*/NewFileList{,.[0-9]*}"))) {
die("ERROR: Pool conflicts will occur if NewFileList present (--Force overrides):\n " .
join('\n ', @partialbackups) . "\n");
}
system("$bpc->{InstallDir}/bin/BackupPC_serverMesg status jobs >/dev/null 2>&1");
unless(($? >>8) == 1) {
die "Dangerous to run when BackupPC is running!!!\n"
if $TopDir eq $TopDir_def;
warn "WARNING: May be dangerous to run when BackupPC is running!!!\n";
#Warn but don't die if *appear* to be in different TopDir
}
my $totalfiles = 0;
my $md5errors = 0;
my $fixed = 0;
my $badpoolentry = 0;
my $chaindups = 0;
my $norename = 0;
my $renumbererr = 0;
scan_pool($pool);
#Note: Total = total pool files scanned
# NotFixed = NoRename (i.e. rename fails - shouldn't happen...)
# ChainDups (only calcualted if --warndups set)
# RenumberErrs = Errors renumbering old chain after move (shouldn't happen...)
printf("Total=%d Md5PathErrors=%d [Fixed=%d, NotFixed=%d]%s\n",
$totalfiles, $md5errors, $fixed, ($md5errors-$fixed),
($dryrun ? " DRY-RUN" : ""));
printf("BadPoolEntries=%d RenumberErrs=%d\n", $badpoolentry, $renumbererr);
printf("ChainDups=%d\n", $chaindups) if $warndups;
print "\n";
exit;
#######################################################################
#Run through the pool looking for misnamed md5sum paths
sub scan_pool
{
my ($fpool) = @_;
my ($dh, @fstat);
return unless glob("$fpool/[0-9a-f]"); #No entries in pool
my @hexlist = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
my ($idir, $jdir, $kdir);
foreach my $i (@hexlist) {
print STDERR "\n**$fpool/$i: " if $verbose >=2;
$idir = $fpool . "/" . $i . "/";
foreach my $j (@hexlist) {
print STDERR "$j " if $verbose >=2;
$jdir = $idir . $j . "/";
foreach my $k (@hexlist) {
$kdir = $jdir . $k . "/";
unless(opendir($dh, $kdir)) {
warn "Can't open pool directory: $kdir\n" if $verbose>=4;
next;
}
#Sort directory entries so that chains are ordered lowest to
#highest - This preserves sequential order between source and
#target chains PLUS ensures that we fill holes corretly and
#most efficiently
my @entries = sort {poolname2number($a) cmp poolname2number($b)}
(readdir ($dh));
close($dh);
warn "POOLDIR: $kdir (" . ($#entries-1) ." files)\n"
if $verbose >=3;
my $chainholes = 0;
my $chainstart;
my $lastdigest='';
foreach (@entries) {
next if /^\.\.?$/; # skip dot files (. and ..)
$totalfiles++;
my $origfile = ${kdir} . $_;
unless(m|^([0-9a-f]+)(_[0-9]+)?|) {
warn "ERROR: '$origfile' is not a valid pool entry\n";
$badpoolentry++;
next;
}
my $origdigest = $1;
my $newdigest = $file2md5->($bpc, $md5, $origfile, -1, $compress);
if($newdigest eq "-1") {
$badpoolentry++;
warn "ERROR: Can't calculate md5sum name for: $origfile\n";
next;
}
if($newdigest ne $origdigest) { #MD5sum Path is WRONG
$md5errors++;
if($origdigest ne $lastdigest) { #New chain
#So go back and renumber last chain to remove holes
if($chainholes > 0) {
renumber_pool_chain($chainstart, $chainholes)>0
or $renumbererr++;
}
$lastdigest=$origdigest; #Reset to new chain base
$chainholes = 0;
$chainstart = $origfile; #lowest element of chain
#since we are sorting directory in chain order
}
if(rename_entry($origfile, $newdigest)>0) {$chainholes++}
}
}
#Check in case any holes unfixed at end of directory scan
if($chainholes > 0) {
renumber_pool_chain($chainstart, $chainholes) >0
or $renumbererr++;
}
}
}
}
print STDERR "\n" if $verbose >=2;
}
#Rename/move pool chain entry $source to first open position
#in $digest chain if permitted. Renumber source chain as
#needed after the move
sub rename_entry
{
my ($source, $digest) = @_;
my $dups = '';
my @dups = ();
my $poolpath = $bpc->MD52Path($digest,$compress);
my $poolbase_ = $poolpath . "_";
for(my $i=0; -f $poolpath; $i++) { # Iterate through pool chain with same md5sum to find
# first free entry
if($warndups && (stat(_))[3] < $MAXLINKS &&
! $compare->($source,$poolpath)) { #Matches existing pool entry
push(@dups,$i);
}
$poolpath = $poolbase_ . $i;
}
$poolpath =~ m|^$TopDir/?((.*)/.*)|;
my $target = $1; #Path relative to TopDir
my $dir = $2; #Relative to TopDir
# print "$source $target [$md5errors/$totalfiles]$dups\n";
if(@dups) {
$dups = " CHAINDUPS(" . join(',', @dups) . ")";
warn "WARN: $dups: $source->$target\n" if $verbose >=1;
$chaindups++;
}
if((!-d $dir && !jmkpath($dir, 0, 0750)) || #Directory creation error
!jrename($source,$poolpath)) { #Rename error
warn "ERROR: Can't rename: $source->$target\n" if $verbose >=1;
print $OUT "$source $target NO_RENAME$dups\n";
$norename++;
return -1;
}
#Fixed without errors
print $OUT "$source $target FIXED$dups\n";
$fixed++;
return 1;
}
sub usage
{
print STDERR <<EOF;
usage: $0 [options] --outfile|-o <outfile>
Options:
--dryrun|-d Dry-run
Negate with: --nodryrun
--Force Force - MAY BE DANGEROUS!
--topdir|-t Location of TopDir. [Default = $TopDir_def]
Note you may want to change from default for example
if you are working on a shadow copy.
--verbose|-v Verbose (repeat for more verbosity)
--warndups|-w Warn if renamed pool entry is a pool duplicate
DESCRIPTION:
Find and fix md5sum pool name errors in pool and cpool
DETAILS:
Recurses through pool and cpool trees to test if the md5sum name of each
pool file is correct relative to the file data. If not, the program attempts
to rename (i.e. move) it to its proper md5sum name.
If there already are pool files with the new name, then move it to
the end of the target chain. After removing, renumber the source
chain (if needed) to fill in holes left by the move. Note that the relative
ordering of each chain is preserved.
If the contents of the file match the contents of any of the files in the
target chain, note the duplicate suffix numbers.
If the --warndups|-w flag is set then check to see if the renamed pool
entry duplicates an existing pool entry (with <MAX LINKS). This may be
slow if you have a lot of chains since to check for duplicates you need
to compare files
Note: it is not generally an error to have two pool entries in the same
chain with the same data (in fact, it occurs intentionally when you exceed
MAX LINKS), it just may waste some space. My routine BackupPC_fixLinks.pl
can correct just such duplicates later if that is an issue.
In any case, if all your misnumbering was consistent you won\'t have this
situation anyway.
<outfile> records all the changes made plus appends a status code:
FIXED = pool file moved/renamed and original chain renumbered if needed.
NO_RENAME = Signals error in renaming/moving the pool file. The mdsum name
was thus not corrected.
DUPS(n1,n2,n3) = Signals duplicates in the target chain and lists the
suffixes (-1 = no suffix)
The following errors are tabulated but shouldn\'t occur:
BadPoolEntries = Files in pool with name not of form [0-9a-f]+(_[0-9]+)?
or that can\'t be read to compute the MD5 path digest
RenumberErrors = Failures to renumber original chain to fill hole
after renaming
EOF
exit(1)
}
Code: Alles auswählen
#!/usr/bin/perl
#============================================================= -*-perl-*-
#
# BackupPC_verifyPool: Verify pool integrity
#
# DESCRIPTION
#
# BackupPC_verifyPool tries to verify the integrity of the pool files,
# based on their file names, which are supposed to correspond to MD5
# digests calculated from the (uncompressed) length and parts of their
# (again uncompressed) contents.
# Needs to be run as backuppc user for access to the pool files and
# meta data.
#
# Usage: BackupPC_verifyPool [-v] [-p] [-u] [-r range] [-s]
#
# Options:
#
# -v Show what is going on. Without this flag, only errors found
# are displayed, which might be very boring. Use '-p' for a
# bit of entertainment without causing your tty to scroll so
# much.
# -p Show more terse progress output.
# -u Check the pool (uncompressed files), not the cpool
# (uncompressed files).
# -r range Specify the pool range to check (see below). 'range'
# can be a Perl expression like '0 .. 255' or '0, 10, 30 .. 40'.
# Only safe characters allowed [\da-fA-F,.\s].
# -s Show summary.
#
# The pool range was chosen as in BackupPC_nightly as means to divide
# the possibly lengthy operation of verifying the pool into smaller
# steps. The full pool goes from 0 to 255, that's all you really need to
# know. For more information, see BackupPC_nightly from the BackupPC
# distribution.
#
# AUTHOR
# Holger Parplies <wopp at parplies.de>
#
# VERSION
# $Id$
#
# COPYRIGHT
# Copyright (C) 2007 Holger Parplies
#
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
#========================================================================
#
# Version 3.3.1-1, patched 8 Apr 2016.
#
#========================================================================
use strict;
use lib '/usr/share/backuppc/lib'; # Debian; change to fit your needs
use BackupPC::Lib;
use BackupPC::FileZIO;
use Getopt::Std;
use File::Find;
# $ENV {PATH} = '/bin:/usr/bin';
# chdir '.';
my %opts = (
v => 0, # verbose output
p => 0, # terse progress output
u => 0, # pool (1) or cpool (0)
r => '0 .. 255', # range
s => 0, # show summary
);
unless (getopts ('vpur:s', \%opts)) {
die <<EOM;
Usage: $0 [-v] [-p] [-u] [-r range] [-s]
Options: -v Verbose output of files being checked and result
-p Terse output of what is happening (counter)
-u Check uncompressed pool (pool instead of cpool)
-r range Check subset of pool (default whole pool = 0 .. 255).
Use any valid Perl expression containing only numbers
(octal or hexadecimal is ok), dots, commas and whitespace
here.
-s Show summary.
EOM
}
# unbuffered output
$| = 1;
# some variables
my $bpc = new BackupPC::Lib # BackupPC object
or die "Can't create BackupPC object!\n";
my $pooldir = $bpc -> {TopDir} . '/' . ($opts {u} ? 'pool' : 'cpool') . '/';
# Pool directory to check
my @range; # Pool range to check
my $mismatch_count = 0; # number of invalid files
my $file_count = 0; # running file count for progress output
my $md5; # handle of MD5 object
# # untaint range specification; NOTE THAT THIS IS NOT SECURE!
# $opts {r} = $1
# if $opts {r} =~ /^(.*)$/;
# check range specification
die "Range specification '$opts{r}' contains insecure characters!\n"
if $opts {r} !~ /^[0-9a-fA-Fx.,\s]*$/;
eval "\@range = ($opts{r});";
if ($@) {
die "Range specification '$opts{r}' is invalid: $@\n";
} elsif (not defined @range or @range == 0) {
die "Range specification '$opts{r}' is empty. Nothing to do.\n";
} elsif (grep { $_ < 0 or $_ > 255 } @range) {
die "Range specification '$opts{r}' contains values outside (0 .. 255)\n";
}
# iterate over the specified part of the pool
$md5 = new Digest::MD5
or die "Can't create MD5 object: $!\n";
foreach my $i (@range) {
my $dir = sprintf '%s/%1x/%1x', $pooldir, int ($i / 16), $i % 16;
find (\&validate_pool_dir, $dir)
if -d $dir;
}
# Summary
if ($opts {s}) {
printf "%d files in %d directories checked, %d had wrong digests.\n",
$file_count, @range * 16, $mismatch_count;
} elsif ($mismatch_count > 0) {
print "ERROR: $mismatch_count files in ", $opts {u} ? 'pool' : 'cpool',
", range ($opts{r}), seem to be corrupt!\n";
}
# Return code
exit $mismatch_count > 0 ? 1 : 0;
# actual verification process
sub validate_pool_dir {
my ($name_md5) = ($_ =~ /^([0-9a-fA-F]{32})/);
my $content_md5;
return # ignore directories
if -d $File::Find::name;
$file_count ++;
if ($opts {p} and not $opts {v}) {
if (/^([0-9a-fA-F])([0-9a-fA-F])/) {
print "[$1$2 $file_count]\r";
} else {
print "[ $file_count]\r";
}
}
# since we are only reading the file, we can treat the 'compLevel' parameter
# of BackupPC::FileZIO::open as a boolean
my $fh = BackupPC::FileZIO -> open ($File::Find::name, 0, ! $opts {u});
if (defined $fh) {
my $buf;
my $bytes = $fh -> read (\$buf, 1024 * 1024 + 100);
if ($bytes > 1024 * 1024) {
# read complete file for determining length. Keep first 1MB in $buf,
# put total length into $bytes, read in 100KB chunks for lower mem usage
my $buf2;
my $new = 1;
while ($new > 0) {
$new = $fh -> read (\$buf2, 102400);
$bytes += $new;
}
}
$content_md5 = $bpc -> Buffer2MD5 ($md5, $bytes, \$buf);
if ($content_md5 ne $name_md5) {
# print ">$content_md5< != >$name_md5<\n";
printf "[%5d] %-36.36s != %-32.32s\n", $file_count, $_, $content_md5;
} elsif ($opts {v}) {
printf "[%5d] %-36.36s (%10d) ok\n", $file_count, $_, $bytes;
}
} else {
# open failed, count as mismatch
print "$_: BackupPC::FileZIO::open failed!\n";
$mismatch_count ++;
}
}
Code: Alles auswählen
#========================================================================
#
# ChangeLog - change log for BackupPC.
#
# DESCRIPTION
# Revision history for BackupPC, detailing significant changes between
# versions, most recent first.
#
# AUTHOR
# Craig Barratt <cbarratt@users.sourceforge.net>
#
#========================================================================
#
# Version 3.3.1, released 11 Jan 2015.
#
# See http://backuppc.sourceforge.net.
#
#========================================================================
#------------------------------------------------------------------------
# Version 3.3.1-1, 08 Apr 2016
#------------------------------------------------------------------------
* Custom Changes
* patch from debian jessie backuppc (3.3.0-2) unstable with
Version 3.3.1, released 11 Jan 2015. to 3.3.1-1 Custom
#------------------------------------------------------------------------
# Version 3.3.1, 11 Jan 2015
#------------------------------------------------------------------------
* Added more helpful text (instead of "New Key") for BackupFilesOnly and BackupFilesExclude in the CGI editor.
* Removed deprecated defined(@Backups) from lib/BackupPC/CGI/Browse.pm; patch from Alexander Moisseev.
* Updated Spanish language file lib/BackupPC/Lang/es.pm from Luis Bustamante.