Subversion Repositories general

Compare Revisions

Ignore whitespace Rev 1263 → Rev 1253

/fsbackup/trunk/fsbackup.pl
3,28 → 3,30
#
# http://www.opennet.ru/dev/fsbackup/
# Copyright (c) 2001-2002 by Maxim Chirkov. <mc@tyumen.ru>
# Copyright (c) 2003-2006 by Anatoli Klassen. <anatoli@aksoft.net>
#
# Command line flags:
# -n - create a new (full) archive
# -c - delete old cache and create a full archive
# Ключи:
# -n - создаем новый архив независимо от состояния хэша.
# -f - full_backup - полный бэкап в архив, без хэша.
# -h - hash - только генерация хэша, без помещения файлов в архив.
# -c - clean - очиска хранилища с инкрементальным бэкапом и создание нового бэкапа.
#
# $Id$
#
#############################################
use constant DB_DEF_CACHE_SIZE => 40960000; # size of cache in memory
use constant DB_DEF_CACHE_SIZE => 40960000; # Размер кэша для размежения хэша в памяти
 
use POSIX;
use File::Find;
use Digest::MD5 qw(md5_base64);
use Net::FTP;
use DB_File;
use BSD::stat;
 
use constant VERB_SILENT => 0; # Silent mode, suspend all output.
use constant VERB_ERROR => 1; # Output all errors and warnings.
use constant VERB_ALL => 2; # Output all the available data.
use constant VERB_ERROR => 1; # Output all errors and warnings.
use constant VERB_ALL => 2; # Output all the available data.
 
my $version = "3.0";
my $version = "2.0";
my $list_lines_cnt = 0;
my $del_lines_cnt = 0;
my $cur_time = time();
33,9 → 35,12
my $cfg_new_flag = 0;
my $cfg_clean_flag = 0;
my $config = 0;
my $cur_backup_size = 1536; # tar block size, to calc volumes size
my $cur_backup_size = 1536; # Размер блока tar
my $backup_file_base;
my $prog_pgp_filter;
my $prog_gzip_filter;
my $arc_ext;
my $ftp;
my $cur_increment_level;
my $cur_dir;
my $cur_path;
50,241 → 55,448
my $db_hashinfo2;
my $file;
my @volume_position=(0);
my @fs_path=(); # /dir[/file]
my @fs_notpath=(); # !
my @fs_mask=(); # =~
my @fs_filemask=(); # f~
my @fs_dirmask=(); # d~
my @fs_notmask=(); # =!
my @fs_notfilemask=(); # f!
my @fs_notdirmask=(); # d!
my @fs_path=(); # /dir[/file] - путь к файлу/директории для бэкапа.
my @fs_notpath=(); # ! - отрицание пути, не помещать в бэкап. Всегда должен быть первым символом.
my @fs_mask=(); # =~ - маска для файла или директории, а не абсолютный путь. Первый или второй символ.
my @fs_filemask=(); # f~ - маска для файла. Первый или второй символ.
my @fs_dirmask=(); # d~ - маска для директории. Первый или второй символ.
my @fs_notmask=(); # =! - "НЕ" маска для файла или директории, а не абсолютный путь. Первый или второй символ.
my @fs_notfilemask=(); # f! - "НЕ" маска для файла. Первый или второй символ.
my @fs_notdirmask=(); # d! - "НЕ" маска для директории. Первый или второй символ.
 
# Load the config
if($ARGV[0] eq "-n" || $ARGV[0] eq "-c") {
$config = $ARGV[1];
# ------------- Обработка параметров командной строки
 
if ($ARGV[0] eq "-n" || $ARGV[0] eq "-h" || $ARGV[0] eq "-f" || $ARGV[0] eq "-c"){
$cfg_new_flag=1;
$config = $ARGV[1];
} else {
$cfg_new_flag=0;
$config = $ARGV[0];
}
else {
$config = $ARGV[0];
}
 
if(!-f $config) {
die "Usage: fsbackup.pl [-n|-c] config_name\n";
if ( ! -f $config){
die "Usage: fsbackup.pl [-n|-f|-h|-c] config_name\n";
}
 
require "$config";
 
$cfg_move_old_backup = 1 if(!defined($cfg_move_old_backup));
$cfg_exit_on_empty = 1 if(!defined($cfg_exit_on_empty));
$cfg_move_old_backup=1 if(!defined($cfg_move_old_backup));
$cfg_exit_on_empty=1 if(!defined($cfg_exit_on_empty));
 
if(! -d $cfg_cache_dir) {
die "\$cfg_cache_dir ($cfg_cache_dir) not found. Set \$cfg_cache_dir variable in fsbackup.pl\n";
if ( ! -d $cfg_cache_dir){
die "\$cfg_cache_dir ($cfg_cache_dir) not found. Set \$cfg_cache_dir varisble in fsbackup.pl\n";
}
 
# Convert config values
$cfg_time_limit *= 60 * 60 * 24;
$cfg_size_limit *= 1024;
$cfg_maximum_archive_size *= 1024;
$cfg_time_limit *= 60 * 60 * 24; # Дни в секунды.
$cfg_size_limit *= 1024; # Килобайты в байты.
$cfg_maximum_archive_size *= 1024; # Килобайты в байты.
 
# Command line args
if($ARGV[0] eq "-n" || $ARGV[0] eq "-c") {
$cfg_new_flag = 1;
chdir($cfg_root_path);
 
if ($ARGV[0] eq "-h"){
$cfg_backup_style = "hash";
}
if ($ARGV[0] eq "-f" ){
$cfg_backup_style = "full_backup";
}
 
if($ARGV[0] eq "-c") {
$cfg_clean_flag = 1;
if ($ARGV[0] eq "-c" ){
$cfg_clean_flag=1;
} else {
$cfg_clean_flag=0;
}
 
# Check config
if($cfg_backup_name !~ /^[\w\d\_.]+$/) {
die "Found illegal characters in $cfg_backup_name ($cfg_backup_name).";
#------------------- Проверяем переменные в файле конфигурации.
if ($cfg_backup_name !~ /^[\w\d\_.]+$/){
die "Found illegal characters in $cfg_backup_name ($cfg_backup_name).";
}
 
if(!grep {$_ eq $cfg_checksum} ("md5", "timesize")) {
if (! grep {$_ eq $cfg_checksum} ("md5", "timesize")){
die "Unknown checksum method:\$cfg_checksum=$cfg_checksum (allowed md5 or timesize)\n";
}
 
if(! -d $cfg_local_path) {
die "Can't find \$cfg_local_path ($cfg_local_path)";
if (! grep {$_ eq $cfg_backup_style} ("backup", "full_backup", "sync", "hash")){
die "Unknown backup_style:\$cfg_backup_style=$cfg_backup_style\n";
}
 
my($sec, $min, $hour, $mday, $mon, $year) = localtime($cur_time);
$backup_file_base = sprintf("%s-%4.4d.%2.2d.%2.2d.%2.2d.%2.2d.%2.2d",
$cfg_backup_name, $year+1900, $mon+1, $mday, $hour, $min, $sec);
 
# Prepare
print "Creating $cfg_backup_name\n" if($cfg_verbose == &VERB_ALL);
if ($cfg_backup_style eq "full_backup" || $cfg_backup_style eq "hash"){
$cfg_new_flag=1;
$cfg_clean_flag=1;
}
 
chdir($cfg_root_path);
if (! grep {$_ eq $cfg_type} ("local", "remote_ssh", "remote_ftp")){
die "Unknown backup target:\$cfg_type=$cfg_type\n";
}
 
if(! -d "$cfg_cache_dir/$cfg_backup_name") {
mkdir("$cfg_cache_dir/$cfg_backup_name", 0700);
if (($cfg_type eq "local") && (! -d $cfg_local_path)){
die "Can't find \$cfg_local_path ($cfg_local_path)";
}
 
# Calc increment level
if($cfg_increment_level != 0) {
if(open(INCREMENT_LEVEL, "<$cfg_cache_dir/$cfg_backup_name/.increment_level")) {
$cur_increment_level = <INCREMENT_LEVEL>;
$cur_increment_level++;
close(INCREMENT_LEVEL);
}
else {
print "Can't open increment level file ($cfg_cache_dir/$cfg_backup_name/.increment_level).\n";
$cur_increment_level = 0;
}
if ($cfg_backup_style eq "backup"){
my ($sec,$min,$hour,$mday,$mon,$year) = localtime($cur_time);
$backup_file_base = sprintf ("%s-%4.4d.%2.2d.%2.2d.%2.2d.%2.2d.%2.2d",
$cfg_backup_name,$year+1900,$mon+1,$mday,$hour,$min,$sec);
}else{
$backup_file_base="$cfg_backup_name";
}
 
if($cur_increment_level >= $cfg_increment_level) {
$cur_increment_level=0;
}
print "Creating $cfg_type $cfg_backup_style: $cfg_backup_name\n" if ($cfg_verbose == &VERB_ALL);
 
if($cur_increment_level == 0) {
$cfg_new_flag = 1;
$cfg_clean_flag = 1;
}
if ($cfg_pgp_userid ne "" && $prog_pgp ne ""){
print "PGP: enabled\n" if ($cfg_verbose == &VERB_ALL);
 
if(open(INCREMENT_LEVEL, ">$cfg_cache_dir/$cfg_backup_name/.increment_level")) {
print INCREMENT_LEVEL $cur_increment_level;
close(INCREMENT_LEVEL);
}
else {
print "Can't save increment level to file ($cfg_cache_dir/$cfg_backup_name/.increment_level).\n";
}
print "Current increment number: $cur_increment_level\n" if($cfg_verbose == &VERB_ALL);
# PGP 2.6 (pgp)
# $prog_pgp_filter="| $prog_pgp -ef $cfg_pgp_userid -z'$cfg_pgp_userid' ";
# PGP 5.0 (pgpe)
# $prog_pgp_filter="| $prog_pgp -f $cfg_pgp_userid";
# GnuPG (pgp)
$prog_pgp_filter="| $prog_pgp -v --batch -e -r $cfg_pgp_userid";
} else {
$prog_pgp_filter="";
}
 
# Load old cache
if(-f "$cfg_cache_dir/$cfg_backup_name/.hash" && $cfg_new_flag == 0) {
rename("$cfg_cache_dir/$cfg_backup_name/.hash", "$cfg_cache_dir/$cfg_backup_name/.hash.last");
$db_hashinfo = new DB_File::HASHINFO ;
$db_hashinfo->{'cachesize'} = DB_DEF_CACHE_SIZE;
unless($dbobj_last = tie(%active_hash_last, "DB_File", "$cfg_cache_dir/$cfg_backup_name/.hash.last",
O_RDWR|O_CREAT, 0644, $db_hashinfo))
{
print "WARNING: Error in hash, creating full backup.\n";
unlink "$cfg_cache_dir/$cfg_backup_name/.hash.last";
}
if ($prog_gzip ne ""){
$prog_gzip_filter="| $prog_gzip";
$arc_ext=".gz";
} else {
$prog_gzip_filter="";
$arc_ext="";
}
 
# Create new cache
if (! -d "$cfg_cache_dir/$cfg_backup_name"){
mkdir("$cfg_cache_dir/$cfg_backup_name", 0700);
}
 
# ---------- Активируем FTP соединение
 
ftp_connect();
 
#----------- Вычисляем уровень инкрементальности.
if ($cfg_increment_level != 0 && $cfg_backup_style eq "backup"){
if(open(INCREMENT_LEVEL, "<$cfg_cache_dir/$cfg_backup_name/.increment_level")) {
$cur_increment_level = <INCREMENT_LEVEL>;
$cur_increment_level++;
close (INCREMENT_LEVEL);
}
else {
print "Can't open increment level file ($cfg_cache_dir/$cfg_backup_name/.increment_level).\n";
$cur_increment_level = 0;
}
 
if ($cur_increment_level >= $cfg_increment_level){
$cur_increment_level=0;
}
 
if ($cur_increment_level == 0){
$cfg_new_flag=1;
$cfg_clean_flag=1;
}
if(open(INCREMENT_LEVEL, ">$cfg_cache_dir/$cfg_backup_name/.increment_level")) {
print INCREMENT_LEVEL $cur_increment_level;
close (INCREMENT_LEVEL);
}
else {
print "Can't save increment level to file ($cfg_cache_dir/$cfg_backup_name/.increment_level).\n";
}
print "Current increment number: $cur_increment_level\n" if ($cfg_verbose == &VERB_ALL);
}
################################################
#----------- Считываем хэш в память.
 
if ( (-f "$cfg_cache_dir/$cfg_backup_name/.hash" || $cfg_type ne "local" ) && $cfg_new_flag == 0){
# Считываем текущий хеш в память.
 
if ( $cfg_type eq "local"){
rename ("$cfg_cache_dir/$cfg_backup_name/.hash", "$cfg_cache_dir/$cfg_backup_name/.hash.last");
}elsif ( $cfg_type eq "remote_ssh"){
system ("$prog_ssh -l $cfg_remote_login $cfg_remote_host 'cat $cfg_remote_path/.hash' > $cfg_cache_dir/$cfg_backup_name/.hash.last") == 0 || print "SSH connection failed: $?\n";
} elsif ( $cfg_type eq "remote_ftp"){
unlink ("$cfg_cache_dir/$cfg_backup_name/.hash.last");
$ftp->get(".hash", "$cfg_cache_dir/$cfg_backup_name/.hash.last")|| print "FTP error, Can't GET .hash\n";
}
$db_hashinfo = new DB_File::HASHINFO ;
$db_hashinfo->{'cachesize'} = DB_DEF_CACHE_SIZE;
if (! ($dbobj_last = tie(%active_hash_last, "DB_File", "$cfg_cache_dir/$cfg_backup_name/.hash.last", O_RDWR|O_CREAT, 0644, $db_hashinfo ))){
print "WARNING: Error in hash, creating full backup.\n" if ($cfg_verbose >= &VERB_ERROR);
unlink "$cfg_cache_dir/$cfg_backup_name/.hash.last";
$dbobj_last = tie(%active_hash_last, "DB_File", "$cfg_cache_dir/$cfg_backup_name/.hash.last", O_RDWR|O_CREAT, 0644, $db_hashinfo )||print "Can't create or open DB File!";
}
# $dbobj->del($key);
# $dbobj->sync();
 
}
 
# Закрываем ftp соединение. Следующий блок может выполняться гораздо дольше
# чем таймаут ftp.
if ( $cfg_type eq "remote_ftp"){
$ftp->quit;
}
#Создаем новый хеш.
unlink("$cfg_cache_dir/$cfg_backup_name/.hash");
$db_hashinfo2 = new DB_File::HASHINFO ;
$db_hashinfo2->{'cachesize'} = 100000;
$dbobj_new = tie(%active_hash_new, "DB_File", "$cfg_cache_dir/$cfg_backup_name/.hash",
O_RDWR|O_CREAT, 0644, $db_hashinfo2) || print "Can't create or open DB File!\n";
$db_hashinfo2->{'cachesize'} = 100000;
$dbobj_new = tie(%active_hash_new, "DB_File", "$cfg_cache_dir/$cfg_backup_name/.hash", O_RDWR|O_CREAT, 0644, $db_hashinfo2) || print "Can't create or open DB File!\n";
 
# Save meta info
open(META, ">$cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.meta")
|| print "Can't create meta file ($cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.meta).\n";
# Создаем список файлов для помещения в архив.
open (LIST, ">$cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.list")|| print "Can't create list file ($cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.list).\n";
flock (LIST, 2);
 
# Создаем список директорий в архиве.
open (DIRS, ">$cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.dir")|| print "Can't create list file ($cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.dir).\n";
flock (DIRS, 2);
 
open (META, ">$cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.meta")|| print "Can't create meta file ($cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.meta).\n";
print META "fsbackup $version\n";
print META "increment level: $cur_increment_level\n";
close(META);
 
# Create list of files to save
open(LIST, ">$cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.list")
|| print "Can't create list file ($cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.list).\n";
flock(LIST, 2);
# Считываем список подлежащих бэкапу директорий в память.
 
# Load list of dirs and files to backup from the config
while(<DATA>) {
chomp;
if(/^\!(.*)$/) { # !
push @fs_notpath, $1;
}
elsif(/^\=\~(.*)$/){ # =~
push @fs_mask, $1;
}
elsif(/^f\~(.*)$/){ # f~
push @fs_filemask, $1;
}
elsif(/^d\~(.*)$/){ # d~
push @fs_dirmask, $1;
}
elsif(/^\=\!(.*)$/){ # =!
push @fs_notmask, $1;
}
elsif(/^f\!(.*)$/){ # f!
push @fs_notfilemask, $1;
}
elsif(/^d\!(.*)$/){ # d!
push @fs_notdirmask, $1;
}
elsif(/^#/ || /^\s*$/){ # comment
next;
}
elsif(/[\/\w]+/) { # /dir[/file]
push @fs_path, $_;
}
else {
print STDERR "Syntax error: $_, ingnored.\n";
}
}
while(<DATA>){
chomp;
$cur_path = $_;
if ($cur_path =~ /^\!(.*)$/){ # !
push @fs_notpath, $1;
 
# Find dirs and files to backup
foreach $cur_pathitem (@fs_path) {
print "Adding $cur_pathitem ... " if($cfg_verbose == &VERB_ALL);
find(\&add_to_backup, $cur_pathitem);
print "done\n" if($cfg_verbose == &VERB_ALL);
} elsif ($cur_path =~ /^\=\~(.*)$/){ # =~
push @fs_mask, $1;
 
} elsif ($cur_path =~ /^f\~(.*)$/){ # f~
push @fs_filemask, $1;
 
} elsif ($cur_path =~ /^d\~(.*)$/){ # d~
push @fs_dirmask, $1;
 
} elsif ($cur_path =~ /^\=\!(.*)$/){ # =!
push @fs_notmask, $1;
 
} elsif ($cur_path =~ /^f\!(.*)$/){ # f!
push @fs_notfilemask, $1;
 
} elsif ($cur_path =~ /^d\!(.*)$/){ # d!
push @fs_notdirmask, $1;
 
} elsif ($cur_path =~ /^#/ || $cur_path =~ /^\s*$/){ # comment
next;
 
} elsif ($cur_path =~ /[\/\w]+/) { # /dir[/file]
push @fs_path, $cur_path;
 
} else {
print STDERR "Syntax error: $cur_path, ingnored.\n" if ($cfg_verbose >= &VERB_ALL);
}
}
close(LIST);
 
# Create list of deleted files and dirs
open(DEL, ">$cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.del")
|| print "Can't create list file ($cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.del).\n";
flock (DEL, 2);
while(($file, $key) = each(%active_hash_last)) {
$file =~ s/\'/\'\\\'\'/g;
$file =~ s/^\/(.*)$/$1/;
print DEL "rm -rf '$file'\n";
$del_lines_cnt++;
#--------------------------------------------------------------------
# Последовательно просматририваем весь список директорий отмеченных для бэкапа
 
 
foreach $cur_pathitem (@fs_path){
print "Adding $cur_pathitem....\n" if ($cfg_verbose == &VERB_ALL);
find (\&add_to_backup, $cur_pathitem);
print "done\n" if ($cfg_verbose == &VERB_ALL);
}
close(DEL);
close (LIST);
close (DIRS);
#------------
# Составляем список удаленных файлов.
 
# Save the cache
open (DEL, ">$cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.del")|| print "Can't create list file ($cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.del).\n";
flock (DEL, 2);
if ($cfg_backup_style ne "hash"){
while(($file, $key)= each(%active_hash_last)){
$file =~ s/\'/\'\\\'\'/g;
$file =~ s/^\/(.*)$/$1/;
print DEL "rm -rf '$file'\n";
$del_lines_cnt++;
}
}
close(DEL);
 
# Записываем хэш на диск.
$dbobj_new->sync();
untie %active_hash_new;
untie %active_hash_last;
 
# Goto root because all paths are without leading /
chdir("/");
chdir ("/"); # Переходим в корень, так как все пути у нас без корневого /
 
# Tar them
if($cfg_exit_on_empty == 1 && $list_lines_cnt == 0 && $del_lines_cnt == 0) {
print "WARNING: Nothing to backup.\n";
exit;
# Активируем FTP соединение второй раз.
ftp_connect();
 
#------------
# Если только обновляем хэш, то записываем его и выходим.
 
if ($cfg_backup_style eq "hash"){ # Только создать хэшь без архивирования.
 
if ( $cfg_type eq "local"){
system( "cp -f $cfg_cache_dir/$cfg_backup_name/.hash $cfg_local_path/.hash") == 0 || print "Local FS copy hash failed: $?";
} elsif ( $cfg_type eq "remote_ssh"){
system( "cat $cfg_cache_dir/$cfg_backup_name/.hash | $prog_ssh -l $cfg_remote_login $cfg_remote_host 'cat - > $cfg_remote_path/.hash'") == 0 || print "SSH connection failed (copy hash): $?\n";
} elsif ( $cfg_type eq "remote_ftp"){
$ftp->delete(".hash");
$ftp->put("$cfg_cache_dir/$cfg_backup_name/.hash", ".hash")|| print "Can't upload .hash to remote server via FTP\n";
}
exit (0);
}
 
#------------
# Архивируем и передаем в хранилище.
 
if ($cfg_exit_on_empty == 1 && $list_lines_cnt == 0 && $del_lines_cnt == 0){
print "$cfg_exit_on_empty\n";
print "WARNING: Nothing to backup.\n" if ($cfg_verbose >= &VERB_ALL);
exit;
}
if ( $cfg_type eq "local"){
print "Storing local backup\n" if($cfg_verbose == &VERB_ALL);
if($cfg_clean_flag == 1) { # delete old backup
if($cfg_save_old_backup == 0) {
system("$prog_rm -f $cfg_local_path/*");
}
elsif($cfg_move_old_backup == 1) {
system("mkdir $cfg_local_path/OLD") if(!-d "$cfg_local_path/OLD");
system("$prog_rm -f $cfg_local_path/OLD/*");
system("mv -f $cfg_local_path/$cfg_backup_name* $cfg_local_path/OLD/");
}
print "Storing local backup...\n" if ($cfg_verbose == &VERB_ALL);
if ($cfg_backup_style eq "sync"){
if ($cfg_clean_flag == 1){ # Удалить старые копии
print "WARNING: If you really shure to delete $cfg_local_path before sync operatioun uncomment line 'system( \"find \$cfg_local_path -not -path '\$cfg_local_path' -maxdepth 1 -exec \$prog_rm -rf \{\} \\;\");'" if ($cfg_verbose >= &VERB_ALL);
# system( "find $cfg_local_path -not -path '$cfg_local_path' -maxdepth 1 -exec $prog_rm -rf \{\} \\;");
}
 
system( "cd $cfg_local_path; sh $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.del");
system( "$prog_tar -c -f - -T $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.list| $prog_tar -xf - -C $cfg_local_path") == 0 || print "Local FS sync failed (tar|untar): $?\n";
system( "cd $cfg_local_path; sh $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.dir");
system( "cp -f $cfg_cache_dir/$cfg_backup_name/.hash $cfg_local_path/$backup_file_base.hash") == 0 || print "Local FS copy failed: $?\n";
 
} else {
if ($cfg_clean_flag == 1){ # Удалить старые копии
if ($cfg_save_old_backup == 0){
system( "$prog_rm -f $cfg_local_path/*");
} elsif($cfg_move_old_backup == 1) {
if (! -d "$cfg_local_path/OLD"){
system( "mkdir $cfg_local_path/OLD");
}
system( "$prog_rm -f $cfg_local_path/OLD/*");
system( "mv -f $cfg_local_path/$cfg_backup_name* $cfg_local_path/OLD/");
# system( "$prog_rm -f $cfg_local_path/*");
}
}
system( "cp -f $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.meta $cfg_local_path/$backup_file_base.meta") == 0 || print "Local FS .meta copy failed: $?\n";
system( "cp -f $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.list $cfg_local_path/$backup_file_base.list") == 0 || print "Local FS .list copy failed: $?\n";
system( "cp -f $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.dir $cfg_local_path/$backup_file_base.dir") == 0 || print "Local FS .dir copy failed: $?\n";
system( "cp -f $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.del $cfg_local_path/$backup_file_base.del") == 0 || print "Local FS .del copy failed: $?\n";
#system( "cp -f $cfg_cache_dir/$cfg_backup_name/.hash $cfg_local_path/$backup_file_base.hash") == 0 || print "Local FS .hash copy failed: $?\n";
# Обрабатываем разбиение на тома
for ($arc_block_level=0; $arc_block_level <= $#volume_position; $arc_block_level++){
my $tmp_list_file = create_tmp_list($arc_block_level, $volume_position[$arc_block_level], $volume_position[$arc_block_level+1], "$cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.list");
system( "$prog_tar -c -f - -T $tmp_list_file $prog_gzip_filter $prog_pgp_filter > $cfg_local_path/$backup_file_base-$arc_block_level.tar${arc_ext}") == 0 || print "Local FS tar backup failed: $?\n";
}
}
 
} elsif ( $cfg_type eq "remote_ssh"){
print "Storing remote ssh backup...\n" if ($cfg_verbose == &VERB_ALL);
if ($cfg_backup_style eq "sync"){
if ($cfg_clean_flag == 1){ # Удалить старые копии
system( "$prog_ssh -l $cfg_remote_login $cfg_remote_host find $cfg_remote_path -not -path '$cfg_remote_path' -maxdepth 1 -exec rm -rf \{\} \\;");
}
system( "cat $cfg_cache_dir/$cfg_backup_name/.hash | $prog_ssh -l $cfg_remote_login $cfg_remote_host 'cat - > $cfg_remote_path/.hash'") == 0 || print "SSH connection failed (store .hash): $?\n";
system( "cat $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.del | $prog_ssh -l $cfg_remote_login $cfg_remote_host 'cat - > $cfg_remote_path/.del'") == 0 || print "SSH connection failed (store .hash): $?\n";
system( "cat $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.dir | $prog_ssh -l $cfg_remote_login $cfg_remote_host 'cat - > $cfg_remote_path/.dir'") == 0 || print "SSH connection failed (store .hash): $?\n";
system("$prog_ssh -l $cfg_remote_login $cfg_remote_host '(cd $cfg_remote_path; sh .del)'");
system( "$prog_tar -c -f - -T $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.list $prog_gzip_filter| $prog_ssh -l $cfg_remote_login $cfg_remote_host tar -xf - -C $cfg_remote_path") == 0 || print "SSH connection failed (tar): $?\n";;
system("$prog_ssh -l $cfg_remote_login $cfg_remote_host '(cd $cfg_remote_path; sh .dir)'");
 
 
open (DEL, "<$cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.del");
flock (DEL, 1);
while(<DEL>){
chomp;
$cur_file = $_;
$cur_file =~ s/\'/\'\\\'\'/g;
system("$prog_ssh -l $cfg_remote_login $cfg_remote_host rm -f '$cfg_remote_path/$cur_file'");
}
close(DEL);
} else {
if ($cfg_clean_flag == 1){ # Удалить старые копии
 
if ($cfg_save_old_backup == 0){
system( "$prog_ssh -l $cfg_remote_login $cfg_remote_host rm -f $cfg_remote_path/*");
} else {
system( "$prog_ssh -l $cfg_remote_login $cfg_remote_host '(if [ ! -d $cfg_remote_path/OLD ]; then mkdir $cfg_remote_path/OLD; fi)'");
system( "$prog_ssh -l $cfg_remote_login $cfg_remote_host rm -f $cfg_remote_path/OLD/*");
system( "$prog_ssh -l $cfg_remote_login $cfg_remote_host mv -f $cfg_remote_path/$cfg_backup_name* $cfg_remote_path/OLD/");
# system( "$prog_ssh -l $cfg_remote_login $cfg_remote_host rm -f $cfg_remote_path/*");
}
}
system( "cat $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.list | $prog_ssh -l $cfg_remote_login $cfg_remote_host 'cat - > $cfg_remote_path/$backup_file_base.list'") == 0 || print "SSH connection failed (copy .list): $?\n";
system( "cat $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.dir | $prog_ssh -l $cfg_remote_login $cfg_remote_host 'cat - > $cfg_remote_path/$backup_file_base.dir'") == 0 || print "SSH connection failed (copy .dir): $?\n";
system( "cat $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.del | $prog_ssh -l $cfg_remote_login $cfg_remote_host 'cat - > $cfg_remote_path/$backup_file_base.del'") == 0 || print "SSH connection failed (copy .del): $?\n";
system( "cat $cfg_cache_dir/$cfg_backup_name/.hash | $prog_ssh -l $cfg_remote_login $cfg_remote_host 'cat - > $cfg_remote_path/$backup_file_base.hash'") == 0 || print "SSH connection failed (copy .hash): $?\n";
system( "cat $cfg_cache_dir/$cfg_backup_name/.hash | $prog_ssh -l $cfg_remote_login $cfg_remote_host 'cat - > $cfg_remote_path/.hash'") == 0 || print "SSH connection failed (cache .hash): $?\n";
# Обрабатываем разбиение на тома
for ($arc_block_level=0; $arc_block_level <= $#volume_position; $arc_block_level++){
my $tmp_list_file = create_tmp_list($arc_block_level, $volume_position[$arc_block_level], $volume_position[$arc_block_level+1], "$cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.list");
system( "$prog_tar -c -f - -T $tmp_list_file $prog_gzip_filter $prog_pgp_filter| $prog_ssh -l $cfg_remote_login $cfg_remote_host 'cat - > $cfg_remote_path/$backup_file_base-$arc_block_level.tar${arc_ext}'") == 0 || print "SSH connection failed (tar): $?\n";
}
}
} elsif ( $cfg_type eq "remote_ftp"){
print "Storing remote ftp backup...\n" if ($cfg_verbose == &VERB_ALL);
 
if ($cfg_backup_style eq "sync"){
print "WARNING: Backup style 'sync' only allowed for local and remote_ssh storage.\n" if ($cfg_verbose >= &VERB_ALL);
} else {
if ($cfg_clean_flag == 1){ # Удалить старые копии
if ($cfg_save_old_backup == 0){
foreach $cur_dir ($ftp->ls()){
$ftp->delete($cur_dir);
}
} else {
$ftp->mkdir("$cfg_remote_path/OLD");
$ftp->cwd("$cfg_remote_path/OLD");
foreach $cur_dir ($ftp->ls()){
$ftp->delete($cur_dir);
}
$ftp->cwd("$cfg_remote_path");
foreach $cur_dir ($ftp->ls()){
if ($cur_dir =~ /$cfg_backup_name/){
$ftp->rename($cur_dir,"$cfg_remote_path/OLD/$cur_dir");
}
}
foreach $cur_dir ($ftp->ls()){
$ftp->delete($cur_dir);
}
}
}
$ftp->delete("$backup_file_base.list");
$ftp->put("$cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.list", "$backup_file_base.list") || print "Can't PUT .list file to remote FTP server\n";
$ftp->delete("$backup_file_base.dir");
$ftp->put("$cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.dir", "$backup_file_base.dir")|| print "Can't PUT .dir file to remote FTP server\n";
$ftp->delete("$backup_file_base.del");
$ftp->put("$cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.del", "$backup_file_base.del")|| print "Can't PUT .del file to remote FTP server\n";
$ftp->delete("$backup_file_base.hash");
$ftp->put("$cfg_cache_dir/$cfg_backup_name/.hash", "$backup_file_base.hash")|| print "Can't PUT old .hash file to remote FTP server\n";
$ftp->delete(".hash");
$ftp->put("$cfg_cache_dir/$cfg_backup_name/.hash", ".hash")|| print "Can't PUT new .hash file to remote FTP server\n";
# Обрабатываем разбиение на тома
for ($arc_block_level=0; $arc_block_level <= $#volume_position; $arc_block_level++){
my $tmp_list_file = create_tmp_list($arc_block_level, $volume_position[$arc_block_level], $volume_position[$arc_block_level+1], "$cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.list");
$ftp->delete("$backup_file_base-$arc_block_level.tar${arc_ext}");
open (TAR,"$prog_tar -c -f - -T $tmp_list_file $prog_gzip_filter $prog_pgp_filter|")|| print "tar failed: $?\n";
flock(TAR,1);
$ftp->put(*TAR, "$backup_file_base-$arc_block_level.tar${arc_ext}")|| print "Can't store backup archive to remote FTP server.\n";
close(TAR);
}
$ftp->quit;
}
}
system("cp -f $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.meta $cfg_local_path/$backup_file_base.meta")
== 0 || print "Local FS .meta copy failed: $?\n";
system("cp -f $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.list $cfg_local_path/$backup_file_base.list")
== 0 || print "Local FS .list copy failed: $?\n";
system("cp -f $cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.del $cfg_local_path/$backup_file_base.del")
== 0 || print "Local FS .del copy failed: $?\n";
 
# Split to volumes
for($arc_block_level = 0; $arc_block_level <= $#volume_position; $arc_block_level++) {
my $tmp_list_file = create_tmp_list($arc_block_level, $volume_position[$arc_block_level],
$volume_position[$arc_block_level+1], "$cfg_cache_dir/$cfg_backup_name/$cfg_backup_name.list");
system("$prog_tar -c -f - -n -z -T $tmp_list_file > $cfg_local_path/$backup_file_base-$arc_block_level.tar.gz") == 0 || print "Local FS tar backup failed: $?\n";
if ( $cfg_type eq "remote_ftp"){
$ftp->quit;
}
 
print "***** Backup successful complete.\n" if($cfg_verbose == &VERB_ALL);
print "***** Backup successful complete.\n" if ($cfg_verbose == &VERB_ALL);
exit (0);
 
 
########################################
sub add_to_backup
{
my($file_name, $file_dir, $md5_checksum_stat, $checksum_stat, $file_fullpath_esc);
my($tmp, $stat_mode, $stat_uid, $stat_gid, $stat_size, $stat_time, $stat_flags);
my($tmp, $stat_mode, $stat_uid, $stat_gid, $stat_size, $stat_mtime, $stat_time, $stat_flags);
$file_name = $_;
$file_fullpath = $File::Find::name;
292,23 → 504,54
$file_fullpath_esc = $file_fullpath;
$file_fullpath_esc =~ s/\'/\'\\\'\'/g;
 
# dir
if((-d $file_fullpath) && (!-l $file_fullpath)) {
# Создаем список директорий
if((-d $file_fullpath) && (! -l $file_fullpath)) {
if(check_path($file_dir, $file_name) == 1) {
($tmp, $tmp, $stat_mode, $tmp, $stat_uid, $stat_gid, $tmp, $stat_size, $tmp, $tmp,
$stat_time, $tmp, $tmp, $tmp, $tmp, $tmp, $stat_flags, $tmp) = lstat($file_fullpath);
$checksum_stat = md5_base64("$stat_time/$stat_mode/$stat_uid/$stat_gid");
$file_fullpath_esc =~ s/^\/(.*)$/$1/;
if($cfg_backup_style ne "hash") {
($tmp, $tmp, $stat_mode, $tmp, $stat_uid, $stat_gid, $tmp, $stat_size, $tmp, $stat_mtime,
$stat_time, $tmp, $tmp, $tmp, $tmp, $tmp, $stat_flags, $tmp) = lstat($file_fullpath);
$stat_mode = sprintf ("%04o", $stat_mode & 07777);
$file_fullpath_esc =~ s/^\/(.*)$/$1/;
my ($sec,$min,$hour,$mday,$mon,$year) = localtime($stat_time);
$stat_time = sprintf("%4.4d%2.2d%2.2d%2.2d%2.2d.%2.2d",
$year+1900, $mon+1, $mday, $hour, $min, $sec);
print DIRS "mkdir -p '$file_fullpath_esc'\n";
print DIRS "chmod $stat_mode '$file_fullpath_esc'\n";
print DIRS "chown $stat_uid:$stat_gid '$file_fullpath_esc'\n";
print DIRS "touch -t $stat_time '$file_fullpath_esc'\n";
if($stat_flags) {
print DIRS "chflags "
. ($stat_flags & UF_NODUMP ? "nodump," : "")
. ($stat_flags & UF_IMMUTABLE ? "uchg," : "")
. ($stat_flags & UF_APPEND ? "uappnd," : "")
. ($stat_flags & UF_OPAQUE ? "opaque," : "")
. ($stat_flags & UF_NOUNLINK ? "uunlnk," : "")
. ($stat_flags & SF_ARCHIVED ? "arch," : "")
. ($stat_flags & SF_IMMUTABLE ? "schg," : "")
. ($stat_flags & SF_APPEND ? "sappnd," : "")
. ($stat_flags & SF_NOUNLINK ? "sunlnk," : "")
. " '$file_fullpath_esc'\n";
}
 
$active_hash_new{$file_fullpath} = "D $checksum_stat";
check_update($file_fullpath, "D $checksum_stat", $file_fullpath, $stat_size);
 
if($stat_flags & UF_NODUMP) {
push @fs_notpath, "$file_dir/$file_name"; # if nodump - skip all subitems
if($cfg_stopdir_prune == 1) {
$File::Find::prune = 1;
return;
unless($stat_flags & UF_NODUMP) {
$cur_backup_size += int(length($file_fullpath)/100.0 + 1) * 512;
if($cfg_maximum_archive_size > 0 && $cur_backup_size + 10240 >= $cfg_maximum_archive_size) {
my $old_val = $cur_backup_size - $stat_size - int(length($file_fullpath)/100.0 + 1) * 512;
my $tmp_pos = $#volume_position+1;
print "Volume $tmp_pos Done. Size: $old_val\n" if($cfg_verbose == &VERB_ALL);
$cur_backup_size = $stat_size + int(length($file_fullpath)/100.0 + 1) * 512 + 1536;
push @volume_position, $list_lines_cnt;
}
$active_hash_new{$file_fullpath} = "D";
check_update($file_fullpath, "D", $file_fullpath, $stat_size);
}
else {
push @fs_notpath, "$file_dir/$file_name"; # if nodump - skip all subitems
if($cfg_stopdir_prune == 1) {
$File::Find::prune = 1;
return;
}
}
}
}
else {
318,17 → 561,17
}
}
}
# file or symlink
# Работаем с файлами
elsif((-f $file_fullpath) || (-l $file_fullpath)) {
if(check_path($file_dir, $file_name) == 1) {
($tmp, $tmp, $stat_mode, $tmp, $stat_uid, $stat_gid, $tmp, $stat_size, $tmp, $tmp,
($tmp, $tmp, $stat_mode, $tmp, $stat_uid, $stat_gid, $tmp, $stat_size, $tmp, $stat_mtime,
$stat_time, $tmp, $tmp, $tmp, $tmp, $tmp, $stat_flags, $tmp) = lstat($file_fullpath);
unless($stat_flags & UF_NODUMP) {
$checksum_stat = md5_base64("$stat_time/$stat_size/$stat_mode/$stat_uid/$stat_gid");
$checksum_stat= md5_base64("$stat_mtime/$stat_size/$stat_mode/$stat_uid/$stat_gid");
# $file_fullpath_md5 = md5_base64($file_fullpath);
$file_fullpath_md5 = $file_fullpath;
 
if($cfg_time_limit != 0 && $cur_time - $cfg_time_limit > $stat_time) {
print "Time limit: $cur_time - $cfg_time_limit > $stat_time, file $file_fullpath ignored.\n"
if($cfg_time_limit != 0 && $cur_time - $cfg_time_limit > $stat_mtime) {
print "Time limit: $cur_time - $cfg_time_limit > $stat_mtime, file $file_fullpath ignored.\n"
if($cfg_verbose == &VERB_ALL);
next;
}
340,13 → 583,12
 
if(($cfg_checksum eq "md5") && (! -l $file_fullpath)) {
($md5_checksum_stat, $tmp) = split(/\s+/, `$prog_md5sum '$file_fullpath_esc'`);
$active_hash_new{$file_fullpath_md5} = "F $checksum_stat/$md5_checksum_stat";
check_update($file_fullpath, "F $checksum_stat/$md5_checksum_stat", $file_fullpath_md5, $stat_size);
$active_hash_new{$file_fullpath_md5} = "$checksum_stat/$md5_checksum_stat";
check_update($file_fullpath, "$checksum_stat/$md5_checksum_stat", $file_fullpath_md5, $stat_size);
} else {
$active_hash_new{$file_fullpath} = $checksum_stat;
check_update($file_fullpath, $checksum_stat, $file_fullpath, $stat_size);
}
else {
$active_hash_new{$file_fullpath} = "F $checksum_stat";
check_update($file_fullpath, "F $checksum_stat", $file_fullpath, $stat_size);
}
}
}
}
353,107 → 595,142
}
 
###############################################
# Check if file was updated
sub check_update
{
my($file, $checksum, $filesum, $stat_size) = @_;
# Проверяем изменился ли файл или нет, если да апдейтим лог.
sub check_update{
my ($file, $checksum, $filesum, $stat_size) = @_;
if($active_hash_last{$filesum} ne $checksum) {
$file =~ s/^\/(.*)$/$1/;
print LIST "$file\n";
$stat_size = 0 if(-l "/$file");
# next volume
$cur_backup_size += $stat_size + int(length($file)/100.0 + 1)*512;
if($cfg_maximum_archive_size > 0 && $cur_backup_size + 10240 >= $cfg_maximum_archive_size) {
my $old_val = $cur_backup_size - $stat_size - int(length($file)/100.0 + 1)*512;
my $tmp_pos = $#volume_position+1;
print "Volume $tmp_pos Done. Size: $old_val\n" if ($cfg_verbose == &VERB_ALL);
$cur_backup_size = $stat_size + int(length($file)/100.0 + 1)*512 + 1536;
push @volume_position, $list_lines_cnt;
if (($active_hash_last{$filesum} ne $checksum) && ($checksum ne "D")){
if ($cfg_backup_style ne "hash"){
$file =~ s/^\/(.*)$/$1/;
print LIST "$file\n";
# Обрабатываем случай разбиения гиганских архивов.
if (-l "/$file"){
$stat_size = 0;
}
$cur_backup_size += $stat_size + int(length($file)/100.0 + 1)*512;
# print "$cur_backup_size:$stat_size:$file\n";
if ($cfg_maximum_archive_size > 0 && $cur_backup_size + 10240 >= $cfg_maximum_archive_size){
my $old_val = $cur_backup_size - $stat_size - int(length($file)/100.0 + 1)*512;
my $tmp_pos= $#volume_position+1;
print "Volume $tmp_pos Done. Size: $old_val\n" if ($cfg_verbose == &VERB_ALL);
$cur_backup_size = $stat_size + int(length($file)/100.0 + 1)*512 + 1536;
push @volume_position, $list_lines_cnt;
}
 
}
$list_lines_cnt++;
}
$list_lines_cnt++;
}
 
if($active_hash_last{$filesum} && substr($active_hash_last{$filesum}, 0, 1) ne substr($checksum, 0, 1)) {
# if old entry was a directory and now it's file or link or vice versa, leave it in hash
# to add it later to the delete list
}
else {
delete $active_hash_last{$filesum};
$dbobj_last->del($filesum) if(defined $dbobj_last);
}
if(($active_hash_last{$filesum} eq "D") && ($checksum ne "D")
|| ($active_hash_last{$filesum} ne "D") && ($checksum eq "D"))
{
# if old entry was a directory and now it's file or link or vice versa, leave it in hash
# to add it later to the delete list
}
else {
delete $active_hash_last{$filesum};
if (defined $dbobj_last){
$dbobj_last->del($filesum);
}
}
}
 
###############################################
# 0 - don't add the file
# 1 - add the file
sub check_path
{
my ($dir_name, $file_name) = @_;
my ($item, $path);
# 0 - не добавлять файл
# 1 - добавть файл
 
sub check_path {
my ($dir_name, $file_name) = @_;
my ($item, $path);
$path = "$dir_name/$file_name";
$path = "$dir_name/$file_name";
 
foreach $item (@fs_notmask) {
return 0 if($path =~ /$item/);
}
 
foreach $item (@fs_notfilemask) {
return 0 if($file_name =~ /$item/);
}
 
foreach $item (@fs_filemask) {
return 1 if($file_name =~ /$item/);
}
foreach $item (@fs_notmask){
if ($path =~ /$item/){
return 0;
}
}
 
foreach $item (@fs_notdirmask) {
return 0 if($dir_name =~ /$item/);
}
foreach $item (@fs_notfilemask){
if ($file_name =~ /$item/){
return 0;
}
}
 
foreach $item (@fs_mask) {
return 1 if($path =~ /$item/);
}
foreach $item (@fs_filemask){
if ($file_name =~ /$item/){
return 1;
}
}
 
foreach $item (@fs_dirmask) {
return 1 if($dir_name =~ /$item/);
}
foreach $item (@fs_notdirmask){
if ($dir_name =~ /$item/){
return 0;
}
}
 
foreach $item (@fs_notpath) {
return 0 if(($dir_name eq $item) || ($path eq $item) || ($dir_name =~ /^$item\//));
}
 
return 1;
foreach $item (@fs_mask){
if ($path =~ /$item/){
return 1;
}
}
 
foreach $item (@fs_dirmask){
if ($dir_name =~ /$item/){
return 1;
}
}
 
 
foreach $item (@fs_notpath){
if (($dir_name eq $item) || ($path eq $item) || ($dir_name =~ /^$item\//)){
return 0;
}
}
 
return 1;
}
###############################################
# Устанавливаем соединение с удаленным сервером по FTP.
 
sub ftp_connect{
if ( $cfg_type eq "remote_ftp"){
$ftp = Net::FTP->new($cfg_remote_host, Timeout => 30, Debug => 0) || die "Can't connect to ftp server.\n";
$ftp->login($cfg_remote_login, $cfg_remote_password) || die "Can't login to ftp server.\n";
$ftp->cwd($cfg_remote_path) || die "Path $cfg_remote_path not found on ftp server.\n";
$ftp->binary();
}
}
###############################################
# Split the big list into volume list
sub create_tmp_list
{
my($arc_block_level, $position1, $position2, $full_list_path) = @_;
my($tmp_list_path, $pos_counter);
# Содание списка файлов для помещения в определенный том многотомного архива.
 
if($arc_block_level == 0 && $position1 == 0 && $position2 eq '') {
$tmp_list_path = $full_list_path;
}
else {
$pos_counter = 0;
$tmp_list_path = "$full_list_path.$arc_block_level";
open(FULL_LIST, "<$full_list_path") || die "Can't open full list $full_list_path\n";
flock(FULL_LIST, 1);
open(TMP_LIST, ">$tmp_list_path") || die "Can't create temp list $tmp_list_path\n";
flock(TMP_LIST, 2);
while(<FULL_LIST>) {
print TMP_LIST $_ if(($pos_counter >= $position1) && ($pos_counter < $position2 || $position2 eq ''));
$pos_counter++;
sub create_tmp_list{
my ($arc_block_level, $position1, $position2, $full_list_path) = @_;
my ($tmp_list_path, $pos_counter);
 
if ($arc_block_level == 0 && $position1 == 0 && $position2 eq ''){
$tmp_list_path = $full_list_path;
} else {
$pos_counter = 0;
$tmp_list_path = "$full_list_path.$arc_block_level";
open(FULL_LIST, "<$full_list_path")|| die "Can't open full list $full_list_path\n";
flock(FULL_LIST, 1);
open(TMP_LIST, ">$tmp_list_path")|| die "Can't create temp list $tmp_list_path\n";
flock(TMP_LIST, 2);
while(<FULL_LIST>){
if (($pos_counter >= $position1) && ($pos_counter < $position2 || $position2 eq '')){
print TMP_LIST $_;
}
$pos_counter++;
}
close(TMP_LIST);
close(FULL_LIST);
}
close(TMP_LIST);
close(FULL_LIST);
}
return $tmp_list_path;
return $tmp_list_path;
}
 
###############################################
###############################################
 
470,7 → 747,8
=head1 DESCRIPTION
 
C<fsbackup.pl> is a incremental backup creation utility.
C<fsbackup.pl> support backup compression and encryption. Some addition
C<fsbackup.pl> support backup compression and encryption. Backup can be stored
on local file system and on remote host stored over SSH or FTP. Some addition
scripts allow backups SQL tables from PostgreSQL and MySQL (C<pgsql_backup.sh>
and C<mysql_backup.sh>)), save system configuration files and list of installed
packages (C<sysbackup.sh>).
554,8 → 832,18
 
=item B<$prog_tar> = 'tar'
 
=item B<$prog_ssh> = 'ssh'
 
=item B<$prog_rm> = 'rm'
 
=item B<$prog_gzip> = 'gzip'
 
=item B<$prog_pgp> = 'gpg'
 
Full path of some external program running from C<fsbackup.pl>.
B<$prog_gzip = ''> - not use compression, B<$prog_pgp = ''> - not use
encryption.
 
=item B<$cfg_checksum> = 'timesize'
 
File checksum method:
564,10 → 852,43
 
md5 - checksum of file attributes + MD5 checksum of file content.
 
=item B<$cfg_backup_style> = 'backup'
 
Backup style:
 
backup - incremental backup (copy only new and changed files).
 
full_backup - full backup (copy all files).
 
sync - file tree synchronization.
 
hash - hash creation without storing archive (spying for new or changed files).
 
=item B<$cfg_increment_level> = 7
 
Incremental level (after how many incremental copy make full refresh of backup)
 
=item B<$cfg_type> = 'remote_ssh'
 
Type of backup storage:
 
local - store backup on local file system.
remote_ssh - store backup on remote host over SSH connection.
remote_ftp - store backup on remote FTP server.
 
 
=item B<$cfg_remote_host> = 'backup-server.test.ru'
 
=item B<$cfg_remote_login> = 'backup_login'
 
=item B<$cfg_remote_path> = '/home/backup_login/backup'
 
Connection parameters for remote_ssh storage type.
 
=item B<$cfg_remote_password> = 'Test1234'
 
Password of remote login for remote_ftp storage type.
 
=item B<$cfg_local_path> = '/var/backup/'
 
Path of directory to store backup on local file system for local storage type.
586,13 → 907,18
 
Root path for initial chdir.
 
=item B<$cfg_pgp_userid> = ''
 
Name of user in public key ring with public key will be used for PGP encryption.
Not use encryption if not set.
 
=item B<$cfg_verbose> = 3
 
Verbose level.
 
0 - Silent mode, suspend all output, except fatal configuration errors.
1 - Output errors and warnings.
2 - Output all the available data.
0 - Silent mode, suspend all output, except fatal configuration errors.
1 - Output errors and warnings.
2 - Output all the available data.
 
=item B<$cfg_save_old_backup> = 1
 
644,9 → 970,6
Copyright (c) 2001 by Maxim Chirkov <mc@tyumen.ru>
http://www.opennet.ru/dev/fsbackup/
 
Copyright (c) 2003-2006 by Anatoli Klassen. <anatoli@aksoft.net>
http://www.26th.net/public/projects/fsbackup/
 
=head1 BUGS
 
Look TODO file.
654,6 → 977,5
=head1 AUTHORS
 
Maxim Chirkov <mc@tyumen.ru>
Anatoli Klassen <anatoli@aksoft.net>
 
=cut