/[psinib]/psinib.pl
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /psinib.pl

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.2 by dpavlin, Sat Jan 4 12:14:54 2003 UTC revision 1.17 by dpavlin, Sun Oct 26 14:04:17 2003 UTC
# Line 12  Line 12 
12  #  #
13  #  #
14  # usage:  # usage:
15  #       $ backup.pl mountscript  #       $ psinib.pl mountscript
16    
17  use strict 'vars';  use strict 'vars';
18  use Data::Dumper;  use Data::Dumper;
# Line 22  use List::Compare; Line 22  use List::Compare;
22  use Filesys::SmbClient;  use Filesys::SmbClient;
23  #use Taint;  #use Taint;
24  use Fcntl qw(LOCK_EX LOCK_NB);  use Fcntl qw(LOCK_EX LOCK_NB);
25    use Digest::MD5;
26    use File::Basename;
27    use Getopt::Long;
28    
29  # configuration  # configuration
30  my $LOG_TIME_FMT = '%Y-%m-%d %H:%M:%S'; # strftime format for logfile  my $LOG_TIME_FMT = '%Y-%m-%d %H:%M:%S'; # strftime format for logfile
31  my $DIR_TIME_FMT = '%Y%m%d';            # strftime format for backup dir  my $DIR_TIME_FMT = '%Y%m%d';            # strftime format for backup dir
32    
33    # define timeout for ping
34    my $PING_TIMEOUT = 5;
35    
36  my $LOG = '/var/log/backup.log';        # add path here...  my $LOG = '/var/log/backup.log';        # add path here...
37  $LOG = '/tmp/backup.log';  #$LOG = '/tmp/backup.log';
38    
39  # store backups in which directory  # store backups in which directory
40  my $BACKUP_DEST = '/data/isis_backup';  my $BACKUP_DEST = '/backup/isis_backup';
41    #my $BACKUP_DEST = '/tmp/backup/';
42    
43  # files to ignore in backup  # files to ignore in backup
44  my @ignore = ('.md5sum', '.backupignore', 'backupignore.txt');  my @ignore = ('.md5sum', '.backupignore', 'backupignore.txt');
45    
46  # open log  # open log
47  open(L, "> $LOG") || die "can't open log $LOG: $!";  open(L, ">> $LOG") || die "can't open log $LOG: $!";
48  select((select(L), $|=1)[0]);   # flush output  select((select(L), $|=1)[0]);   # flush output
49    
50  # make a lock on logfile  # make a lock on logfile
# Line 48  my $c = 0; Line 55  my $c = 0;
55          sleep 1;          sleep 1;
56          redo if ++$c < 10;          redo if ++$c < 10;
57          # no response for 10 sec, bail out          # no response for 10 sec, bail out
58          print STDERR "can't take lock on $LOG -- another $0 running?\n";          xlog("ABORT","can't take lock on $LOG -- another $0 running?");
59          exit 1;          exit 1;
60  }  }
61    
62  # taint path: nmblookup should be there!  # taint path: nmblookup should be there!
63  $ENV{'PATH'} = "/usr/bin:/bin";  $ENV{'PATH'} = "/usr/bin:/bin";
64    
65    my $use_ping = 1;       # default: use syn tcp ping to verify that host is up
66    my $verbose = 1;        # default verbosity level
67    my $quiet = 0;
68    
69    my $result = GetOptions(
70            "ping!" => \$use_ping, "backupdest!" => \$BACKUP_DEST,
71            "verbose+" => \$verbose, "quiet+" => \$quiet,
72    );
73    
74    $verbose -= $quiet;
75    
76  my $mounts = shift @ARGV ||  my $mounts = shift @ARGV ||
77          'mountscript';          'mountscript';
78  #       die "usage: $0 mountscript";  #       die "usage: $0 mountscript";
# Line 62  my $mounts = shift @ARGV || Line 80  my $mounts = shift @ARGV ||
80    
81  my @in_backup;  # shares which are backeduped this run  my @in_backup;  # shares which are backeduped this run
82    
83  my $p = new Net::Ping->new();  # init Net::Ping object
84    my $ping;
85    if ($use_ping) {
86            $ping = new Net::Ping->new("syn", 2);
87            # ping will try tcp connect to netbios-ssn (139)
88            $ping->{port_num} = getservbyname("netbios-ssn", "tcp");
89    }
90    
91    # do syn ping to cifs port
92    sub host_up {
93            my $ping = shift || return;
94            my $host_ip = shift || xlog("host_up didn't get IP");
95            my $timeout = shift;
96            return 1 if (! $use_ping);
97    
98            $ping->ping($host_ip,$timeout);
99            my $return = 0;
100    
101            while (my ($host,$rtt,$ip) = $ping->ack) {
102                    xlog("","HOST: $host [$ip] ACKed in $rtt seconds");
103                    $return = 1 if ($ip eq $host_ip);
104            }
105            return $return;
106    }
107    
108  my $backup_ok = 0;  my $backup_ok = 0;
109    
110  my $smb;  my $smb;
111  my %smb_atime;  my %smb_atime;
112  my %smb_mtime;  my %smb_mtime;
113    my %file_md5;
114    
115  open(M, $mounts) || die "can't open $mounts: $!";  open(M, $mounts) || die "can't open $mounts: $!";
116  while(<M>) {  while(<M>) {
# Line 76  while(<M>) { Line 118  while(<M>) {
118          next if !/^\s*smbmount\s/;          next if !/^\s*smbmount\s/;
119          my (undef,$share,undef,$opt) = split(/\s+/,$_,4);          my (undef,$share,undef,$opt) = split(/\s+/,$_,4);
120    
121          my ($user,$passwd,$workgroup);          my ($user,$passwd,$workgroup,$ip);
122    
123          foreach (split(/,/,$opt)) {          foreach (split(/,/,$opt)) {
124                  my ($n,$v) = split(/=/,$_,2);                  my ($n,$v) = split(/=/,$_,2);
# Line 92  while(<M>) { Line 134  while(<M>) {
134                          }                          }
135                  } elsif ($n =~ m#workgroup#i) {                  } elsif ($n =~ m#workgroup#i) {
136                          $workgroup = $v;                          $workgroup = $v;
137                    } elsif ($n =~ m#ip#i) {
138                            $ip = $v;
139                  }                  }
140          }          }
141    
142          push @in_backup,$share;          push @in_backup,$share;
143    
         print "working on $share\n";  
144    
145          my $ip = get_ip($share);          my ($host,$dir,$date_dir) = share2host_dir($share);
146            my $bl = "$BACKUP_DEST/$host/$dir/latest";      # latest backup
147            my $bc = "$BACKUP_DEST/$host/$dir/$date_dir";   # current one
148            my $real_bl;
149            if (-l $bl) {
150                    $real_bl=readlink($bl) || die "can't read link $bl: $!";
151                    $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/");
152                    if (-l $bc && $real_bl eq $bc) {
153                            xlog($share,"allready backuped...");
154                            $backup_ok++;
155                            next;
156                    }
157    
158            }
159    
160    
161            xlog($share,"working on $share...");
162    
163            # try to nmblookup IP
164            $ip = get_ip($share) if (! $ip);
165    
166          if ($ip) {          if ($ip) {
167                  xlog($share,"IP is $ip");                  xlog($share,"IP is $ip");
168                  if ($p->ping($ip)) {                  if (host_up($ping, $ip,$PING_TIMEOUT)) {
169                          snap_share($share,$user,$passwd,$workgroup);                          if (snap_share($share,$user,$passwd,$workgroup)) {
170                          $backup_ok++;                                  $backup_ok++;
171                            }
172                  }                  }
173          }          }
174  }  }
# Line 117  xlog("","$backup_ok backups completed of Line 180  xlog("","$backup_ok backups completed of
180    
181  #-------------------------------------------------------------------------  #-------------------------------------------------------------------------
182    
183    
184  # get IP number from share  # get IP number from share
185  sub get_ip {  sub get_ip {
186          my $share = shift;          my $share = shift;
# Line 129  sub get_ip { Line 193  sub get_ip {
193          }          }
194  }  }
195    
196    
197    # write entry to screen and log
198  sub xlog {  sub xlog {
199          my $share = shift;          my $share = shift;
200          my $t = strftime $LOG_TIME_FMT, localtime;          my $t = strftime $LOG_TIME_FMT, localtime;
201          my $m = shift || '[no log entry]';          my $m = shift || '[no log entry]';
202          print STDERR $m,"\n";          my $l = shift || 1;
203            print STDERR $m,"\n" if ($verbose >= $l);
204          print L "$t $share\t$m\n";          print L "$t $share\t$m\n";
205  }  }
206    
207  sub snap_share {  # dump warn and dies into log
208    BEGIN { $SIG{'__WARN__'} = sub { xlog('WARN',$_[0]) ; warn $_[0] } }
209    BEGIN { $SIG{'__DIE__'} = sub { xlog('DIE',$_[0]) ; die $_[0] } }
210    
         my $share = shift;  
   
         my %param = ( debug => 0 );  
   
         $param{username} = shift;  
         $param{password} = shift;  
         $param{workgroup} = shift;  
211    
212    # split share name to host, dir and currnet date dir
213    sub share2host_dir {
214            my $share = shift;
215          my ($host,$dir);          my ($host,$dir);
216          if ($share =~ m#//([^/]+)/(.+)$#) {          if ($share =~ m#//([^/]+)/(.+)$#) {
217                  ($host,$dir) = ($1,$2);                  ($host,$dir) = ($1,$2);
# Line 154  sub snap_share { Line 219  sub snap_share {
219                  $dir =~ s/^_+//;                  $dir =~ s/^_+//;
220                  $dir =~ s/_+$//;                  $dir =~ s/_+$//;
221          } else {          } else {
222                  print "Can't parse share $share into host and directory!\n";                  xlog($share,"Can't parse share $share into host and directory!",1);
223                  return;                  return;
224          }          }
225            return ($host,$dir,strftime $DIR_TIME_FMT, localtime);
226    }
227    
228    
229    # make a snapshot of a share
230    sub snap_share {
231    
232            my $share = shift;
233    
234            my %param = ( debug => 0 );
235    
236            $param{username} = shift || warn "can't find username for share $share";
237            $param{password} = shift || warn "can't find passwod for share $share";
238            $param{workgroup} = shift || warn "can't find workgroup for share $share";
239    
240          my $date_dir = strftime $DIR_TIME_FMT, localtime;          my ($host,$dir,$date_dir) = share2host_dir($share);
241    
242          # latest backup directory          # latest backup directory
243          my $bl = "$BACKUP_DEST/$host/$dir/latest";          my $bl = "$BACKUP_DEST/$host/$dir/latest";
# Line 166  sub snap_share { Line 245  sub snap_share {
245          my $bc = "$BACKUP_DEST/$host/$dir/$date_dir";          my $bc = "$BACKUP_DEST/$host/$dir/$date_dir";
246    
247          my $real_bl;          my $real_bl;
248          if (-e $bl) {          if (-l $bl) {
249                  $real_bl=readlink($bl) || die "can't read link $bl: $!";                  $real_bl=readlink($bl) || die "can't read link $bl: $!";
250                  $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/");                  $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/");
251          } else {          } else {
252                  print "no old backup, this is first run...\n";                  xlog($share,"no old backup, trying to find last backup,");
253                    if (opendir(BL_DIR, "$BACKUP_DEST/$host/$dir")) {
254                            my @bl_dirs = sort grep { !/^\./ && -d "$BACKUP_DEST/$host/$dir/$_" } readdir(BL_DIR);
255                            closedir(BL_DIR);
256                            $real_bl=pop @bl_dirs;
257                            xlog($share,"using $real_bl as latest...");
258                            $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/");
259                            if ($real_bl eq $bc) {
260                                    xlog($share,"latest from today (possible partial backup)");
261                                    rename $real_bl,$real_bl.".partial" || warn "can't reaname partial backup: $!";
262                                    $real_bl .= ".partial";
263                            }
264                    } else {
265                            xlog($share,"this is first run...");
266                    }
267          }          }
268    
269          if (-e $bc && $real_bl && $real_bl eq $bc) {          if (-l $bc && $real_bl && $real_bl eq $bc) {
270                  print "$share allready backuped...\n";                  xlog($share,"allready backuped...");
271                  return;                  return 1;
272          }          }
273    
274          die "You should really create BACKUP_DEST [$BACKUP_DEST] by hand! " if (!-e $BACKUP_DEST);          die "You should really create BACKUP_DEST [$BACKUP_DEST] by hand! " if (!-e $BACKUP_DEST);
275    
276          if (! -e "$BACKUP_DEST/$host") {          if (! -e "$BACKUP_DEST/$host") {
277                  mkdir "$BACKUP_DEST/$host" || die "can't make dir for host $host, $BACKUP_DEST/$host: $!";                  mkdir "$BACKUP_DEST/$host" || die "can't make dir for host $host, $BACKUP_DEST/$host: $!";
278                  print "created host directory $BACKUP_DEST/$host...\n";                  xlog($share,"created host directory $BACKUP_DEST/$host...");
279          }          }
280    
281          if (! -e "$BACKUP_DEST/$host/$dir") {          if (! -e "$BACKUP_DEST/$host/$dir") {
282                  mkdir "$BACKUP_DEST/$host/$dir" || die "can't make dir for share $share, $BACKUP_DEST/$host/$dir $!";                  mkdir "$BACKUP_DEST/$host/$dir" || die "can't make dir for share $share, $BACKUP_DEST/$host/$dir $!";
283                  print "created dir for share $share, $BACKUP_DEST/$host/$dir...\n";                  xlog($share,"created dir for this share $BACKUP_DEST/$host/$dir...");
284          }          }
285    
286          mkdir $bc || die "can't make dir for current backup $bc: $!";          mkdir $bc || die "can't make dir for current backup $bc: $!";
# Line 202  sub snap_share { Line 295  sub snap_share {
295          my %file_size;          my %file_size;
296          my %file_atime;          my %file_atime;
297          my %file_mtime;          my %file_mtime;
298          my %file_md5;          #my %file_md5;
299            %file_md5 = ();
300    
301          my @smb_files;          my @smb_files;
302          my %smb_size;          my %smb_size;
303          #my %smb_atime;          #my %smb_atime;
304          #my %smb_mtime;          #my %smb_mtime;
         my %smb_md5;  
   
305    
306          sub norm_dir {          sub norm_dir {
307                  my $foo = shift;                  my $foo = shift;
# Line 225  sub snap_share { Line 317  sub snap_share {
317          my $di = 0;          my $di = 0;
318          while ($di <= $#dirs && $real_bl) {          while ($di <= $#dirs && $real_bl) {
319                  my $d=$dirs[$di++];                  my $d=$dirs[$di++];
320                  opendir(DIR,"$bl/$d") || warn "opendir($bl/$d): $!\n";                  opendir(DIR,"$real_bl/$d") || warn "opendir($real_bl/$d): $!\n";
321    
322                  # read .backupignore if exists                  # read .backupignore if exists
323                  if (-f "$bl/$d/.backupignore") {                  if (-f "$real_bl/$d/.backupignore") {
324                          open(I,"$bl/$d/.backupignore");                          open(I,"$real_bl/$d/.backupignore");
325                          while(<I>) {                          while(<I>) {
326                                  chomp;                                  chomp;
327                                  push @ignore,norm_dir("$d/$_");                                  push @ignore,norm_dir("$d/$_");
328                          }                          }
329                          close(I);                          close(I);
330  print STDERR "ignore: ",join("|",@ignore),"\n";  #print STDERR "ignore: ",join("|",@ignore),"\n";
331                          link "$bl/$d/.backupignore","$bc/$d/.backupignore" ||                          link "$real_bl/$d/.backupignore","$bc/$d/.backupignore" ||
332                                  warn "can't copy $bl/$d/.backupignore to current backup dir: $!\n";                                  warn "can't copy $real_bl/$d/.backupignore to current backup dir: $!\n";
333                  }                  }
334    
335                  # read .md5sum if exists                  # read .md5sum if exists
336                  if (-f "$bl/$d/.md5sum") {                  if (-f "$real_bl/$d/.md5sum") {
337                          open(I,"$bl/$d/.md5sum");                          open(I,"$real_bl/$d/.md5sum");
338                          while(<I>) {                          while(<I>) {
339                                  chomp;                                  chomp;
340                                  my ($md5,$f) = split(/\s+/,$_,2);                                  my ($md5,$f) = split(/\s+/,$_,2);
# Line 256  print STDERR "ignore: ",join("|",@ignore Line 348  print STDERR "ignore: ",join("|",@ignore
348                          next if ($f eq '.');                          next if ($f eq '.');
349                          next if ($f eq '..');                          next if ($f eq '..');
350                          my $pr = norm_dir("$d/$f");     # path relative                          my $pr = norm_dir("$d/$f");     # path relative
351                          my $pf = norm_dir("$d/$f","$bl/");      # path full                          my $pf = norm_dir("$d/$f","$real_bl/"); # path full
352                          if (grep(/^\Q$pr\E$/,@ignore) == 0) {                          if (grep(/^\Q$pr\E$/,@ignore) == 0) {
353                                  if (-f $pf) {                                  if (-f $pf) {
354                                          push @files,$pr;                                          push @files,$pr;
# Line 266  print STDERR "ignore: ",join("|",@ignore Line 358  print STDERR "ignore: ",join("|",@ignore
358                                  } elsif (-d $pf) {                                  } elsif (-d $pf) {
359                                          push @dirs,$pr;                                          push @dirs,$pr;
360                                  } else {                                  } else {
361                                          print STDERR "unknown type: $pf\n";                                          xlog($share,"not file or directory: $pf",0);
362                                  }                                  }
363                          } else {                          } else {
364                                  print STDERR "ignored: $pr\n";                                  xlog($share,"ignored: $pr");
365                          }                          }
366                  }                  }
367          }          }
368    
369          xlog($share,($#files+1)." files and ".($#dirs+1)." dirs on local disk before backup");          # local dir always include /
370            xlog($share,($#files+1)." files and ".($#dirs)." dirs on local disk before backup");
371    
372          # read smb filesystem          # read smb filesystem
373    
# Line 285  print STDERR "ignore: ",join("|",@ignore Line 378  print STDERR "ignore: ",join("|",@ignore
378    
379          $di = 0;          $di = 0;
380          while ($di <= $#smb_dirs) {          while ($di <= $#smb_dirs) {
381                  my $d=$smb_dirs[$di++];                  my $d=$smb_dirs[$di];
382                  my $pf = norm_dir($d,"smb:$share/");    # path full                  my $pf = norm_dir($d,"smb:$share/");    # path full
383                  my $D = $smb->opendir($pf) || warn "smb->opendir($pf): $!\n";                  my $D = $smb->opendir($pf);
384                    if (! $D) {
385                            xlog($share,"FATAL: $share [$pf]: $!");
386                            # remove failing dir
387                            delete $smb_dirs[$di];
388                            return 0;                       # failed
389                    }
390                    $di++;
391    
392                  my @clutter = $smb->readdir_struct($D);                  my @clutter = $smb->readdir_struct($D);
393                  foreach my $item (@clutter) {                  foreach my $item (@clutter) {
# Line 305  print STDERR "ignore: ",join("|",@ignore Line 405  print STDERR "ignore: ",join("|",@ignore
405                                  } elsif ($item->[0] == main::SMBC_DIR) {                                  } elsif ($item->[0] == main::SMBC_DIR) {
406                                          push @smb_dirs,$pr;                                          push @smb_dirs,$pr;
407                                  } else {                                  } else {
408                                          print STDERR "unknown type: $pf\n";                                          xlog($share,"not file or directory [".$item->[0]."]: $pf",0);
409                                  }                                  }
410                          } else {                          } else {
411                                  print STDERR "smb ignored: $pr\n";                                  xlog($share,"smb ignored: $pr");
412                          }                          }
413                  }                  }
414          }          }
415    
416          xlog($share,($#smb_files+1)." files and ".($#smb_dirs+1)." dirs on remote share");          xlog($share,($#smb_files+1)." files and ".($#smb_dirs)." dirs on remote share");
417    
418          # sync dirs          # sync dirs
419          my $lc = List::Compare->new(\@dirs, \@smb_dirs);          my $lc = List::Compare->new(\@dirs, \@smb_dirs);
# Line 345  print STDERR "ignore: ",join("|",@ignore Line 445  print STDERR "ignore: ",join("|",@ignore
445                                    
446                  foreach my $f (@_) {                  foreach my $f (@_) {
447  #print "smb_copy $from/$f -> $to/$f\n";  #print "smb_copy $from/$f -> $to/$f\n";
448                          if (! open(F,"> $to/$f")) {                          my $md5 = Digest::MD5->new;
                                 print STDERR "can't open new file $to/$f: $!\n";  
                                 next;  
                         }  
449    
450                          my $fd = $smb->open("$from/$f");                          my $fd = $smb->open("$from/$f");
451                          if (! $fd) {                          if (! $fd) {
452                                  print STDERR "can't open smb file $from/$f: $!\n";                                  xlog("WARNING","can't open smb file $from/$f: $!");
453                                    next;
454                            }
455    
456                            if (! open(F,"> $to/$f")) {
457                                    xlog("WARNING","can't open new file $to/$f: $!");
458                                  next;                                  next;
459                          }                          }
460    
461                          while (defined(my $b=$smb->read($fd,4096))) {                          while (defined(my $b=$smb->read($fd,4096))) {
462                                  print F $b;                                  print F $b;
463                                  $l += length($b);                                  $l += length($b);
464                                    $md5->add($b);
465                          }                          }
466    
467                          $smb->close($fd);                          $smb->close($fd);
468                          close(F);                          close(F);
469    
470                            $file_md5{$f} = $md5->hexdigest;
471    
472                          # FIX: this fails with -T                          # FIX: this fails with -T
473                          my ($a,$m) = ($smb->stat("$from/$f"))[10,11];                          my ($a,$m) = ($smb->stat("$from/$f"))[10,11];
474                          utime $a, $m, "$to/$f" ||                          utime $a, $m, "$to/$f" ||
# Line 417  print STDERR "ignore: ",join("|",@ignore Line 522  print STDERR "ignore: ",join("|",@ignore
522          xlog($share,"$transfer bytes transfered...");          xlog($share,"$transfer bytes transfered...");
523    
524          foreach (@ln_files) {          foreach (@ln_files) {
525                  link "$bl/$_","$bc/$_" || warn "link $bl/$_ -> $bc/$_: $!\n";                  link "$real_bl/$_","$bc/$_" || warn "link $real_bl/$_ -> $bc/$_: $!\n";
526          }          }
527    
528          # remove files          # remove files
529          foreach (sort @files2erase) {          foreach (sort @files2erase) {
530                  unlink "$bc/$_" || warn "unlink $_: $!\n";                  unlink "$bc/$_" || warn "unlink $_: $!\n";
531                    delete $file_md5{$_};
532          }          }
533    
534          # remove not needed dirs (after files)          # remove not needed dirs (after files)
# Line 430  print STDERR "ignore: ",join("|",@ignore Line 536  print STDERR "ignore: ",join("|",@ignore
536                  rmdir "$bc/$_" || warn "rmdir $_: $!\n";                  rmdir "$bc/$_" || warn "rmdir $_: $!\n";
537          }          }
538    
539            # remove old .md5sum
540          # FIX: create .md5sum          foreach (sort @dirs) {
541                    unlink "$bc/$_/.md5sum" if (-e "$bc/$_/.md5sum");
542            }
543    
544            # erase stale entries in .md5sum
545            my @md5_files = keys %file_md5;
546            $lc = List::Compare->new(\@md5_files, \@smb_files);
547            foreach my $file ($lc->get_Lonly) {
548                    xlog("NOTICE","removing stale '$file' from .md5sum");
549                    delete $file_md5{$file};
550            }
551    
552            # create .md5sum
553            my $last_dir = '';
554            my $md5;
555            foreach my $f (sort { $file_md5{$a} cmp $file_md5{$b} } keys %file_md5) {
556                    my $dir = dirname($f);
557                    my $file = basename($f);
558    #print "$f -- $dir / $file<--\n";
559                    if ($dir ne $last_dir) {
560                            close($md5) if ($md5);
561                            open($md5, ">> $bc/$dir/.md5sum") || warn "can't create $bc/$dir/.md5sum: $!";
562                            $last_dir = $dir;
563    #print STDERR "writing $last_dir/.md5sum\n";
564                    }
565                    print $md5 $file_md5{$f},"  $file\n";
566            }
567            close($md5) if ($md5);
568    
569          # create leatest link          # create leatest link
570    #print "ln -s $bc $real_bl\n";
571            if (-l $bl) {
572                    unlink $bl || warn "can't remove old latest symlink $bl: $!\n";
573            }
574          symlink $bc,$bl || warn "can't create latest symlink $bl -> $bc: $!\n";          symlink $bc,$bl || warn "can't create latest symlink $bl -> $bc: $!\n";
575    
576            # FIX: sanity check -- remove for speedup
577            xlog($share,"failed to create latest symlink $bl -> $bc...") if (readlink($bl) ne $bc || ! -l $bl);
578    
579          xlog($share,"backup completed...");          xlog($share,"backup completed...");
 }  
580    
581            return 1;
582    }
583    __END__
584  #-------------------------------------------------------------------------  #-------------------------------------------------------------------------
585    
586    
587    =head1 NAME
588    
589    psinib - Perl Snapshot Is Not Incremental Backup
590    
591    =head1 SYNOPSIS
592    
593    ./psinib.pl [OPTION]... [mount script]
594    
595    =head1 DESCRIPTION
596    
597    Option can be one of more of following:
598    
599    =over 8
600    
601    =item C<--backupdest=dir>
602    
603    Specify backup destination directory (defaults is /data/
604    
605    =item C<--noping>
606    
607    Don't use ping to check if host is up (default is ti use tcp syn to cifs
608    port)
609    
610    =item C<--verbose -v>
611    
612    Increase verbosity level. Defailt is 1 which prints moderate amount of data
613    on STDOUT and STDERR.
614    
615    =item C<--quiet -q>
616    
617    Decrease verbosity level
618    
619    =back
620    
621    This script in current version support just backup of Samba (or Micro$oft
622    Winblowz) shares to central disk space. Central disk space is organized in
623    multiple directories named after:
624    
625    =over 4
626    
627    =item *
628    server which is sharing files to be backed up
629    
630    =item *
631    name of share on server
632    
633    =item *
634    dated directory named like standard ISO date format (YYYYMMDD).
635    
636    =back
637    
638    In each dated directory you will find I<snapshot> of all files on
639    exported share on that particular date.
640    
641    You can also use symlink I<latest> which will lead you to
642    last completed backup. After that you can use some other backup
643    software to transfer I<snapshot> to tape, CD-ROM or some other media.
644    
645    =head2 Design considerations
646    
647    Since taking of share snapshot every day requires a lot of disk space and
648    network bandwidth, B<psinib> uses several techniques to keep disk usage and
649    network traffic at acceptable level:
650    
651    =over 3
652    
653    =item - usage of hard-links to provide same files in each snapshot (as opposed
654    to have multiple copies of same file)
655    
656    =item - usage of file size, atime and mtime to find changes of files without
657    transferring whole file over network (just share browsing is transfered
658    over network)
659    
660    =item - usage of C<.md5sum> files (compatible with command-line utility
661    C<md5sum>) to keep file between snapshots hard-linked
662    
663    =back
664    
665    =head1 CONFIGURATION
666    
667    This section is not yet written.
668    
669    =head1 HACKS, TRICKS, BUGS and LIMITATIONS
670    
671    This chapter will have all content that doesn't fit anywhere else.
672    
673    =head2 Can snapshots be more frequent than daily?
674    
675    There is not real reason why you can't take snapshot more often than
676    once a day. Actually, if you are using B<psinib> to backup Windows
677    workstations you already know that they tend to come-and-go during the day
678    (reboots probably ;-), so running B<psinib> several times a day increases
679    your chance of having up-to-date backup (B<psinib> will not make multiple
680    snapshots for same day, nor will it update snapshot for current day if
681    it already exists).
682    
683    However, changing B<psinib> to produce snapshots which are, for example, hourly
684    is a simple change of C<$DIR_TIME_FMT> which is currently set to
685    C<'%Y%m%d'> (see I<strftime> documentation for explanation of that
686    format). If you change that to C<'%Y%m%d-%H> you can have hourly snapshots
687    (if your network is fast enough, that is...). Also, some of messages in
688    program will sound strange, but other than that it should work.
689    I<You have been warned>.
690    
691    =head2 Do I really need to share every directory which I want to snapshot?
692    
693    Actually, no. Due to usage of C<Filesys::SmbClient> module, you can also
694    specify sub-directory inside your share that you want to backup. This feature
695    is most useful if you want to use administrative shares (but, have in mind
696    that you have to enter your Win administrator password in unencrypted file on
697    disk to do that) like this:
698    
699            smbmount //server/c$/WinNT/fonts  /mnt  -o username=administrator%win  
700    
701    After that you will get directories with snapshots like:
702    
703            server/c_WinNT_fonts/yyyymmdd/....
704    
705    =head2 Won't I run out of disk space?
706    
707    Of course you will... Snapshots and logfiles will eventually fill-up your disk.
708    However, you can do two things to stop that:
709    
710    =head3 Clean snapshort older than x days
711    
712    You can add following command to your C<root> crontab:
713    
714            find /backup/isis_backup -type d -mindepth 3 -maxdepth 3 -mtime +11 -exec rm -Rf {} \;
715    
716    I assume that C</backup/isis_backup> is directory in which are your snapshots
717    and that you don't want to keep snapshots older than 11 days (that's
718    C<-mtime +11> part of command).
719    
720    =head3 Rotate your logs
721    
722    I will leave that to you. I relay on GNU/Debian's C<logrotate> to do it for me.
723    
724    =head2 What are I<YYYYMMDD.partial> directories?
725    
726    If there isn't I<latest> symlink in snapshot directory, it's preatty safe to
727    assume that previous backup from that day failed. So, that directory will
728    be renamed to I<YYYYMMDD.partial> and snapshot will be performed again,
729    linking same files (other alternative would be to erase that dir and find
730    second-oldest directory, but this seemed like more correct approach).
731    
732    =head2 I can't connect to any share
733    
734    Please verify that nmblookup (which is part of samba package) is in /bin or
735    /usr/bin. Also verify that nmblookup returns IP address for your server
736    using:
737    
738       $ nmblookup tvhouse
739       querying tvhouse on 192.168.34.255
740       192.168.34.30 tvhouse<00>
741    
742    If you don't get any output, your samba might not listen to correct interface
743    (see interfaces in smb.conf).
744    
745    =head1 AUTHOR
746    
747    Dobrica Pavlinusic <dpavlin@rot13.org>
748    
749    L<http:E<sol>E<sol>www.rot13.orgE<sol>~dpavlinE<sol>>
750    
751    =head1 LICENSE
752    
753    This product is licensed under GNU Public License (GPL) v2 or later.
754    
755    =cut

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.17

  ViewVC Help
Powered by ViewVC 1.1.26