Subversion Repositories general

Compare Revisions

Ignore whitespace Rev 1257 → Rev 1258

/fsbackup/trunk/fsbackup.pl
3,30 → 3,28
#
# 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>
#
# Ключи:
# -n - создаем новый архив независимо от состояния хэша.
# -f - full_backup - полный бэкап в архив, без хэша.
# -h - hash - только генерация хэша, без помещения файлов в архив.
# -c - clean - очиска хранилища с инкрементальным бэкапом и создание нового бэкапа.
# Command line flags:
# -n - create a new (full) archive
# -c - delete old cache and create a full archive
#
# $Id$
#
#############################################
use constant DB_DEF_CACHE_SIZE => 40960000; # Размер кэша для размежения хэша в памяти
use constant DB_DEF_CACHE_SIZE => 40960000; # size of cache in memory
 
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 = "2.0";
my $version = "3.0";
my $list_lines_cnt = 0;
my $del_lines_cnt = 0;
my $cur_time = time();
35,12 → 33,9
my $cfg_new_flag = 0;
my $cfg_clean_flag = 0;
my $config = 0;
my $cur_backup_size = 1536; # Размер блока tar
my $cur_backup_size = 1536; # tar block size, to calc volumes size
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;
55,448 → 50,241
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!
 
# ------------- Обработка параметров командной строки
 
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];
# Load the config
if($ARGV[0] eq "-n" || $ARGV[0] eq "-c") {
$config = $ARGV[1];
}
else {
$config = $ARGV[0];
}
 
if ( ! -f $config){
die "Usage: fsbackup.pl [-n|-f|-h|-c] config_name\n";
if(!-f $config) {
die "Usage: fsbackup.pl [-n|-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 varisble in fsbackup.pl\n";
if(! -d $cfg_cache_dir) {
die "\$cfg_cache_dir ($cfg_cache_dir) not found. Set \$cfg_cache_dir variable in fsbackup.pl\n";
}
 
$cfg_time_limit *= 60 * 60 * 24; # Дни в секунды.
$cfg_size_limit *= 1024; # Килобайты в байты.
$cfg_maximum_archive_size *= 1024; # Килобайты в байты.
# Convert config values
$cfg_time_limit *= 60 * 60 * 24;
$cfg_size_limit *= 1024;
$cfg_maximum_archive_size *= 1024;
 
chdir($cfg_root_path);
 
if ($ARGV[0] eq "-h"){
$cfg_backup_style = "hash";
# Command line args
if($ARGV[0] eq "-n" || $ARGV[0] eq "-c") {
$cfg_new_flag = 1;
}
if ($ARGV[0] eq "-f" ){
$cfg_backup_style = "full_backup";
}
 
if ($ARGV[0] eq "-c" ){
$cfg_clean_flag=1;
} else {
$cfg_clean_flag=0;
if($ARGV[0] eq "-c") {
$cfg_clean_flag = 1;
}
 
#------------------- Проверяем переменные в файле конфигурации.
if ($cfg_backup_name !~ /^[\w\d\_.]+$/){
die "Found illegal characters in $cfg_backup_name ($cfg_backup_name).";
# Check config
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 (! grep {$_ eq $cfg_backup_style} ("backup", "full_backup", "sync", "hash")){
die "Unknown backup_style:\$cfg_backup_style=$cfg_backup_style\n";
if(! -d $cfg_local_path) {
die "Can't find \$cfg_local_path ($cfg_local_path)";
}
 
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);
 
if ($cfg_backup_style eq "full_backup" || $cfg_backup_style eq "hash"){
$cfg_new_flag=1;
$cfg_clean_flag=1;
}
# Prepare
print "Creating $cfg_backup_name\n" if($cfg_verbose == &VERB_ALL);
 
if (! grep {$_ eq $cfg_type} ("local", "remote_ssh", "remote_ftp")){
die "Unknown backup target:\$cfg_type=$cfg_type\n";
}
chdir($cfg_root_path);
 
if (($cfg_type eq "local") && (! -d $cfg_local_path)){
die "Can't find \$cfg_local_path ($cfg_local_path)";
if(! -d "$cfg_cache_dir/$cfg_backup_name") {
mkdir("$cfg_cache_dir/$cfg_backup_name", 0700);
}
 
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";
}
# 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;
}
 
print "Creating $cfg_type $cfg_backup_style: $cfg_backup_name\n" if ($cfg_verbose == &VERB_ALL);
if($cur_increment_level >= $cfg_increment_level) {
$cur_increment_level=0;
}
 
if ($cfg_pgp_userid ne "" && $prog_pgp ne ""){
print "PGP: enabled\n" if ($cfg_verbose == &VERB_ALL);
if($cur_increment_level == 0) {
$cfg_new_flag = 1;
$cfg_clean_flag = 1;
}
 
# 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="";
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 ($prog_gzip ne ""){
$prog_gzip_filter="| $prog_gzip";
$arc_ext=".gz";
} else {
$prog_gzip_filter="";
$arc_ext="";
# 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 (! -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;
}
#Создаем новый хеш.
# Create new cache
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";
 
# Создаем список файлов для помещения в архив.
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";
# 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";
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);
 
while(<DATA>){
chomp;
$cur_path = $_;
if ($cur_path =~ /^\!(.*)$/){ # !
push @fs_notpath, $1;
# 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";
}
}
 
} 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);
}
# 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);
}
close(LIST);
 
#--------------------------------------------------------------------
# Последовательно просматририваем весь список директорий отмеченных для бэкапа
 
 
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);
# 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++;
}
close (LIST);
close (DIRS);
#------------
# Составляем список удаленных файлов.
close(DEL);
 
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);
 
# Записываем хэш на диск.
# Save the cache
$dbobj_new->sync();
untie %active_hash_new;
untie %active_hash_last;
 
chdir ("/"); # Переходим в корень, так как все пути у нас без корневого /
# Goto root because all paths are without leading /
chdir("/");
 
# Активируем 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);
# Tar them
if($cfg_exit_on_empty == 1 && $list_lines_cnt == 0 && $del_lines_cnt == 0) {
print "WARNING: Nothing to backup.\n";
exit;
}
 
#------------
# Архивируем и передаем в хранилище.
 
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;
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/");
}
}
if ( $cfg_type eq "local"){
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("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";
 
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;
}
# 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_mtime, $stat_time, $stat_flags);
my($tmp, $stat_mode, $stat_uid, $stat_gid, $stat_size, $stat_time, $stat_flags);
$file_name = $_;
$file_fullpath = $File::Find::name;
504,54 → 292,23
$file_fullpath_esc = $file_fullpath;
$file_fullpath_esc =~ s/\'/\'\\\'\'/g;
 
# Создаем список директорий
if((-d $file_fullpath) && (! -l $file_fullpath)) {
# dir
if((-d $file_fullpath) && (!-l $file_fullpath)) {
if(check_path($file_dir, $file_name) == 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";
}
($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/;
 
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);
$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;
}
else {
push @fs_notpath, "$file_dir/$file_name"; # if nodump - skip all subitems
if($cfg_stopdir_prune == 1) {
$File::Find::prune = 1;
return;
}
}
}
}
else {
561,17 → 318,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, $stat_mtime,
($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);
unless($stat_flags & UF_NODUMP) {
$checksum_stat= md5_base64("$stat_mtime/$stat_size/$stat_mode/$stat_uid/$stat_gid");
# $file_fullpath_md5 = md5_base64($file_fullpath);
$checksum_stat = md5_base64("$stat_time/$stat_size/$stat_mode/$stat_uid/$stat_gid");
$file_fullpath_md5 = $file_fullpath;
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_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_verbose == &VERB_ALL);
next;
}
583,12 → 340,13
 
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} = "$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);
$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);
}
else {
$active_hash_new{$file_fullpath} = "F $checksum_stat";
check_update($file_fullpath, "F $checksum_stat", $file_fullpath, $stat_size);
}
}
}
}
595,142 → 353,107
}
 
###############################################
# Проверяем изменился ли файл или нет, если да апдейтим лог.
sub check_update{
my ($file, $checksum, $filesum, $stat_size) = @_;
# Check if file was updated
sub check_update
{
my($file, $checksum, $filesum, $stat_size) = @_;
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;
}
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;
}
$list_lines_cnt++;
}
 
}
$list_lines_cnt++;
}
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);
}
}
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);
}
}
 
###############################################
# 0 - не добавлять файл
# 1 - добавть файл
 
sub check_path {
my ($dir_name, $file_name) = @_;
my ($item, $path);
# 0 - don't add the file
# 1 - add the file
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_notmask){
if ($path =~ /$item/){
return 0;
}
}
foreach $item (@fs_filemask) {
return 1 if($file_name =~ /$item/);
}
 
foreach $item (@fs_notfilemask){
if ($file_name =~ /$item/){
return 0;
}
}
foreach $item (@fs_notdirmask) {
return 0 if($dir_name =~ /$item/);
}
 
foreach $item (@fs_filemask){
if ($file_name =~ /$item/){
return 1;
}
}
foreach $item (@fs_mask) {
return 1 if($path =~ /$item/);
}
 
foreach $item (@fs_notdirmask){
if ($dir_name =~ /$item/){
return 0;
}
}
foreach $item (@fs_dirmask) {
return 1 if($dir_name =~ /$item/);
}
 
foreach $item (@fs_notpath) {
return 0 if(($dir_name eq $item) || ($path eq $item) || ($dir_name =~ /^$item\//));
}
 
foreach $item (@fs_mask){
if ($path =~ /$item/){
return 1;
}
}
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.
# 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);
 
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();
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++;
}
close(TMP_LIST);
close(FULL_LIST);
}
return $tmp_list_path;
}
###############################################
# Содание списка файлов для помещения в определенный том многотомного архива.
 
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);
}
return $tmp_list_path;
}
###############################################
###############################################
 
747,8 → 470,7
=head1 DESCRIPTION
 
C<fsbackup.pl> is a incremental backup creation utility.
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
C<fsbackup.pl> support backup compression and encryption. 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>).
832,18 → 554,8
 
=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:
852,43 → 564,10
 
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.
907,18 → 586,13
 
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
 
970,6 → 644,9
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.
977,5 → 654,6
=head1 AUTHORS
 
Maxim Chirkov <mc@tyumen.ru>
Anatoli Klassen <anatoli@aksoft.net>
 
=cut