--- psinib.pl 2003/01/21 19:50:47 1.5 +++ psinib.pl 2003/10/12 15:58:28 1.11 @@ -64,7 +64,9 @@ my @in_backup; # shares which are backeduped this run -my $p = new Net::Ping->new(); +my $p = new Net::Ping->new("tcp", 2); +# ping will try tcp connect to netbios-ssn (139) +$p->{port_num} = getservbyname("netbios-ssn", "tcp"); my $backup_ok = 0; @@ -79,7 +81,7 @@ next if !/^\s*smbmount\s/; my (undef,$share,undef,$opt) = split(/\s+/,$_,4); - my ($user,$passwd,$workgroup); + my ($user,$passwd,$workgroup,$ip); foreach (split(/,/,$opt)) { my ($n,$v) = split(/=/,$_,2); @@ -95,6 +97,8 @@ } } elsif ($n =~ m#workgroup#i) { $workgroup = $v; + } elsif ($n =~ m#ip#i) { + $ip = $v; } } @@ -105,10 +109,10 @@ my $bl = "$BACKUP_DEST/$host/$dir/latest"; # latest backup my $bc = "$BACKUP_DEST/$host/$dir/$date_dir"; # current one my $real_bl; - if (-e $bl) { + if (-l $bl) { $real_bl=readlink($bl) || die "can't read link $bl: $!"; $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/"); - if (-e $bc && $real_bl eq $bc) { + if (-l $bc && $real_bl eq $bc) { print "$share allready backuped...\n"; $backup_ok++; next; @@ -119,8 +123,8 @@ print "working on $share\n"; - - my $ip = get_ip($share); + # try to nmblookup IP + $ip = get_ip($share) if (! $ip); if ($ip) { xlog($share,"IP is $ip"); @@ -161,6 +165,10 @@ print L "$t $share\t$m\n"; } +# dump warn and dies into log +BEGIN { $SIG{'__WARN__'} = sub { xlog('WARN',$_[0]) ; warn $_[0] } } +BEGIN { $SIG{'__DIE__'} = sub { xlog('DIE',$_[0]) ; die $_[0] } } + # split share name to host, dir and currnet date dir sub share2host_dir { @@ -186,9 +194,9 @@ my %param = ( debug => 0 ); - $param{username} = shift; - $param{password} = shift; - $param{workgroup} = shift; + $param{username} = shift || warn "can't find username for share $share"; + $param{password} = shift || warn "can't find passwod for share $share"; + $param{workgroup} = shift || warn "can't find workgroup for share $share"; my ($host,$dir,$date_dir) = share2host_dir($share); @@ -198,14 +206,28 @@ my $bc = "$BACKUP_DEST/$host/$dir/$date_dir"; my $real_bl; - if (-e $bl) { + if (-l $bl) { $real_bl=readlink($bl) || die "can't read link $bl: $!"; $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/"); } else { - print "no old backup, this is first run...\n"; + print "no old backup, trying to find last backup, "; + if (opendir(BL_DIR, "$BACKUP_DEST/$host/$dir")) { + my @bl_dirs = sort grep { !/^\./ && -d "$BACKUP_DEST/$host/$dir/$_" } readdir(BL_DIR); + closedir(BL_DIR); + $real_bl=pop @bl_dirs; + print "using $real_bl as latest...\n"; + $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/"); + if ($real_bl eq $bc) { + xlog($share,"latest from today (possible partial backup)"); + rename $real_bl,$real_bl.".partial" || warn "can't reaname partial backup: $!"; + $real_bl .= ".partial"; + } + } else { + print "this is first run...\n"; + } } - if (-e $bc && $real_bl && $real_bl eq $bc) { + if (-l $bc && $real_bl && $real_bl eq $bc) { print "$share allready backuped...\n"; return; } @@ -255,24 +277,24 @@ my $di = 0; while ($di <= $#dirs && $real_bl) { my $d=$dirs[$di++]; - opendir(DIR,"$bl/$d") || warn "opendir($bl/$d): $!\n"; + opendir(DIR,"$real_bl/$d") || warn "opendir($real_bl/$d): $!\n"; # read .backupignore if exists - if (-f "$bl/$d/.backupignore") { - open(I,"$bl/$d/.backupignore"); + if (-f "$real_bl/$d/.backupignore") { + open(I,"$real_bl/$d/.backupignore"); while() { chomp; push @ignore,norm_dir("$d/$_"); } close(I); -print STDERR "ignore: ",join("|",@ignore),"\n"; - link "$bl/$d/.backupignore","$bc/$d/.backupignore" || - warn "can't copy $bl/$d/.backupignore to current backup dir: $!\n"; +#print STDERR "ignore: ",join("|",@ignore),"\n"; + link "$real_bl/$d/.backupignore","$bc/$d/.backupignore" || + warn "can't copy $real_bl/$d/.backupignore to current backup dir: $!\n"; } # read .md5sum if exists - if (-f "$bl/$d/.md5sum") { - open(I,"$bl/$d/.md5sum"); + if (-f "$real_bl/$d/.md5sum") { + open(I,"$real_bl/$d/.md5sum"); while() { chomp; my ($md5,$f) = split(/\s+/,$_,2); @@ -286,7 +308,7 @@ next if ($f eq '.'); next if ($f eq '..'); my $pr = norm_dir("$d/$f"); # path relative - my $pf = norm_dir("$d/$f","$bl/"); # path full + my $pf = norm_dir("$d/$f","$real_bl/"); # path full if (grep(/^\Q$pr\E$/,@ignore) == 0) { if (-f $pf) { push @files,$pr; @@ -315,9 +337,16 @@ $di = 0; while ($di <= $#smb_dirs) { - my $d=$smb_dirs[$di++]; + my $d=$smb_dirs[$di]; my $pf = norm_dir($d,"smb:$share/"); # path full - my $D = $smb->opendir($pf) || warn "smb->opendir($pf): $!\n"; + my $D = $smb->opendir($pf); + if (! $D) { + xlog($share,"FATAL: $share: $!"); + # remove failing dir + delete $smb_dirs[$di]; + next; + } + $di++; my @clutter = $smb->readdir_struct($D); foreach my $item (@clutter) { @@ -452,7 +481,7 @@ xlog($share,"$transfer bytes transfered..."); foreach (@ln_files) { - link "$bl/$_","$bc/$_" || warn "link $bl/$_ -> $bc/$_: $!\n"; + link "$real_bl/$_","$bc/$_" || warn "link $real_bl/$_ -> $bc/$_: $!\n"; } # remove files @@ -473,22 +502,29 @@ # create .md5sum my $last_dir = ''; my $md5; - foreach my $f (sort { $file_md5{$a}<=>$file_md5{$b} } keys %file_md5) { + foreach my $f (sort { $file_md5{$a} cmp $file_md5{$b} } keys %file_md5) { my $dir = dirname($f); my $file = basename($f); -print "$f -- $dir / $file<--\n"; +#print "$f -- $dir / $file<--\n"; if ($dir ne $last_dir) { close($md5) if ($md5); open($md5, ">> $bc/$dir/.md5sum") || warn "can't create $bc/$dir/.md5sum: $!"; $last_dir = $dir; -print STDERR "writing $last_dir/.md5sum\n"; +#print STDERR "writing $last_dir/.md5sum\n"; } print $md5 $file_md5{$f}," $file\n"; } - close($md5); + close($md5) if ($md5); # create leatest link -# symlink $bc,$bl || warn "can't create latest symlink $bl -> $bc: $!\n"; +#print "ln -s $bc $real_bl\n"; + if (-l $bl) { + unlink $bl || warn "can't remove old latest symlink $bl: $!\n"; + } + symlink $bc,$bl || warn "can't create latest symlink $bl -> $bc: $!\n"; + + # FIX: sanity check -- remove for speedup + xlog($share,"failed to create latest symlink $bl -> $bc...") if (readlink($bl) ne $bc || ! -l $bl); xlog($share,"backup completed..."); } @@ -547,7 +583,7 @@ over network) =item - usage of C<.md5sum> files (compatible with command-line utility -C to keep file between snapshots hard-linked +C) to keep file between snapshots hard-linked =back @@ -591,6 +627,32 @@ server/c_WinNT_fonts/yyyymmdd/.... +=head2 Won't I run out of disk space? + +Of course you will... Snapshots and logfiles will eventually fill-up your disk. +However, you can do two things to stop that: + +=head3 Clean snapshort older than x days + +You can add following command to your C crontab: + + find /backup/isis_backup -type d -mindepth 3 -maxdepth 3 -mtime +11 -exec rm -Rf {} \; + +I assume that C is directory in which are your snapshots +and that you don't want to keep snapshots older than 11 days (that's +C<-mtime +11> part of command). + +=head3 Rotate your logs + +I will leave that to you. I relay on GNU/Debian's C to do it for me. + +=head2 What are I directories? + +If there isn't I symlink in snapshot directory, it's preatty safe to +assume that previous backup from that day failed. So, that directory will +be renamed to I and snapshot will be performed again, +linking same files (other alternative would be to erase that dir and find +second-oldest directory, but this seemed like more correct approach). =head1 AUTHOR