/[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.16 by dpavlin, Sun Oct 26 12:55:56 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;       # deault: use ping to verify that host is up
66    
67    my $result = GetOptions(
68            "ping!" => \$use_ping, "backupdest!" => \$BACKUP_DEST,
69    );
70    
71  my $mounts = shift @ARGV ||  my $mounts = shift @ARGV ||
72          'mountscript';          'mountscript';
73  #       die "usage: $0 mountscript";  #       die "usage: $0 mountscript";
# Line 62  my $mounts = shift @ARGV || Line 75  my $mounts = shift @ARGV ||
75    
76  my @in_backup;  # shares which are backeduped this run  my @in_backup;  # shares which are backeduped this run
77    
78  my $p = new Net::Ping->new();  # init Net::Ping object
79    my $ping;
80    if ($use_ping) {
81            $ping = new Net::Ping->new("syn", 2);
82            # ping will try tcp connect to netbios-ssn (139)
83            $ping->{port_num} = getservbyname("netbios-ssn", "tcp");
84    }
85    
86    # do syn ping to cifs port
87    sub host_up {
88            my $ping = shift || return;
89            my $host_ip = shift || xlog("host_up didn't get IP");
90            my $timeout = shift;
91            return 1 if (! $use_ping);
92    
93            $ping->ping($host_ip,$timeout);
94            my $return = 0;
95    
96            while (my ($host,$rtt,$ip) = $ping->ack) {
97                    xlog("","HOST: $host [$ip] ACKed in $rtt seconds");
98                    $return = 1 if ($ip eq $host_ip);
99            }
100            return $return;
101    }
102    
103  my $backup_ok = 0;  my $backup_ok = 0;
104    
105  my $smb;  my $smb;
106  my %smb_atime;  my %smb_atime;
107  my %smb_mtime;  my %smb_mtime;
108    my %file_md5;
109    
110  open(M, $mounts) || die "can't open $mounts: $!";  open(M, $mounts) || die "can't open $mounts: $!";
111  while(<M>) {  while(<M>) {
# Line 76  while(<M>) { Line 113  while(<M>) {
113          next if !/^\s*smbmount\s/;          next if !/^\s*smbmount\s/;
114          my (undef,$share,undef,$opt) = split(/\s+/,$_,4);          my (undef,$share,undef,$opt) = split(/\s+/,$_,4);
115    
116          my ($user,$passwd,$workgroup);          my ($user,$passwd,$workgroup,$ip);
117    
118          foreach (split(/,/,$opt)) {          foreach (split(/,/,$opt)) {
119                  my ($n,$v) = split(/=/,$_,2);                  my ($n,$v) = split(/=/,$_,2);
# Line 92  while(<M>) { Line 129  while(<M>) {
129                          }                          }
130                  } elsif ($n =~ m#workgroup#i) {                  } elsif ($n =~ m#workgroup#i) {
131                          $workgroup = $v;                          $workgroup = $v;
132                    } elsif ($n =~ m#ip#i) {
133                            $ip = $v;
134                  }                  }
135          }          }
136    
137          push @in_backup,$share;          push @in_backup,$share;
138    
139    
140            my ($host,$dir,$date_dir) = share2host_dir($share);
141            my $bl = "$BACKUP_DEST/$host/$dir/latest";      # latest backup
142            my $bc = "$BACKUP_DEST/$host/$dir/$date_dir";   # current one
143            my $real_bl;
144            if (-l $bl) {
145                    $real_bl=readlink($bl) || die "can't read link $bl: $!";
146                    $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/");
147                    if (-l $bc && $real_bl eq $bc) {
148                            print "$share allready backuped...\n";
149                            $backup_ok++;
150                            next;
151                    }
152    
153            }
154    
155    
156          print "working on $share\n";          print "working on $share\n";
157    
158          my $ip = get_ip($share);          # try to nmblookup IP
159            $ip = get_ip($share) if (! $ip);
160    
161          if ($ip) {          if ($ip) {
162                  xlog($share,"IP is $ip");                  xlog($share,"IP is $ip");
163                  if ($p->ping($ip)) {                  if (host_up($ping, $ip,$PING_TIMEOUT)) {
164                          snap_share($share,$user,$passwd,$workgroup);                          if (snap_share($share,$user,$passwd,$workgroup)) {
165                          $backup_ok++;                                  $backup_ok++;
166                            }
167                  }                  }
168          }          }
169  }  }
# Line 117  xlog("","$backup_ok backups completed of Line 175  xlog("","$backup_ok backups completed of
175    
176  #-------------------------------------------------------------------------  #-------------------------------------------------------------------------
177    
178    
179  # get IP number from share  # get IP number from share
180  sub get_ip {  sub get_ip {
181          my $share = shift;          my $share = shift;
# Line 129  sub get_ip { Line 188  sub get_ip {
188          }          }
189  }  }
190    
191    
192    # write entry to screen and log
193  sub xlog {  sub xlog {
194          my $share = shift;          my $share = shift;
195          my $t = strftime $LOG_TIME_FMT, localtime;          my $t = strftime $LOG_TIME_FMT, localtime;
# Line 137  sub xlog { Line 198  sub xlog {
198          print L "$t $share\t$m\n";          print L "$t $share\t$m\n";
199  }  }
200    
201  sub snap_share {  # dump warn and dies into log
202    BEGIN { $SIG{'__WARN__'} = sub { xlog('WARN',$_[0]) ; warn $_[0] } }
203          my $share = shift;  BEGIN { $SIG{'__DIE__'} = sub { xlog('DIE',$_[0]) ; die $_[0] } }
204    
         my %param = ( debug => 0 );  
   
         $param{username} = shift;  
         $param{password} = shift;  
         $param{workgroup} = shift;  
205    
206    # split share name to host, dir and currnet date dir
207    sub share2host_dir {
208            my $share = shift;
209          my ($host,$dir);          my ($host,$dir);
210          if ($share =~ m#//([^/]+)/(.+)$#) {          if ($share =~ m#//([^/]+)/(.+)$#) {
211                  ($host,$dir) = ($1,$2);                  ($host,$dir) = ($1,$2);
# Line 157  sub snap_share { Line 216  sub snap_share {
216                  print "Can't parse share $share into host and directory!\n";                  print "Can't parse share $share into host and directory!\n";
217                  return;                  return;
218          }          }
219            return ($host,$dir,strftime $DIR_TIME_FMT, localtime);
220    }
221    
222          my $date_dir = strftime $DIR_TIME_FMT, localtime;  
223    # make a snapshot of a share
224    sub snap_share {
225    
226            my $share = shift;
227    
228            my %param = ( debug => 0 );
229    
230            $param{username} = shift || warn "can't find username for share $share";
231            $param{password} = shift || warn "can't find passwod for share $share";
232            $param{workgroup} = shift || warn "can't find workgroup for share $share";
233    
234            my ($host,$dir,$date_dir) = share2host_dir($share);
235    
236          # latest backup directory          # latest backup directory
237          my $bl = "$BACKUP_DEST/$host/$dir/latest";          my $bl = "$BACKUP_DEST/$host/$dir/latest";
# Line 166  sub snap_share { Line 239  sub snap_share {
239          my $bc = "$BACKUP_DEST/$host/$dir/$date_dir";          my $bc = "$BACKUP_DEST/$host/$dir/$date_dir";
240    
241          my $real_bl;          my $real_bl;
242          if (-e $bl) {          if (-l $bl) {
243                  $real_bl=readlink($bl) || die "can't read link $bl: $!";                  $real_bl=readlink($bl) || die "can't read link $bl: $!";
244                  $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 "/");
245          } else {          } else {
246                  print "no old backup, this is first run...\n";                  print "no old backup, trying to find last backup, ";
247                    if (opendir(BL_DIR, "$BACKUP_DEST/$host/$dir")) {
248                            my @bl_dirs = sort grep { !/^\./ && -d "$BACKUP_DEST/$host/$dir/$_" } readdir(BL_DIR);
249                            closedir(BL_DIR);
250                            $real_bl=pop @bl_dirs;
251                            print "using $real_bl as latest...\n";
252                            $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/");
253                            if ($real_bl eq $bc) {
254                                    xlog($share,"latest from today (possible partial backup)");
255                                    rename $real_bl,$real_bl.".partial" || warn "can't reaname partial backup: $!";
256                                    $real_bl .= ".partial";
257                            }
258                    } else {
259                            print "this is first run...\n";
260                    }
261          }          }
262    
263          if (-e $bc && $real_bl && $real_bl eq $bc) {          if (-l $bc && $real_bl && $real_bl eq $bc) {
264                  print "$share allready backuped...\n";                  print "$share allready backuped...\n";
265                  return;                  return 1;
266          }          }
267    
268          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);
# Line 202  sub snap_share { Line 289  sub snap_share {
289          my %file_size;          my %file_size;
290          my %file_atime;          my %file_atime;
291          my %file_mtime;          my %file_mtime;
292          my %file_md5;          #my %file_md5;
293            %file_md5 = ();
294    
295          my @smb_files;          my @smb_files;
296          my %smb_size;          my %smb_size;
297          #my %smb_atime;          #my %smb_atime;
298          #my %smb_mtime;          #my %smb_mtime;
         my %smb_md5;  
   
299    
300          sub norm_dir {          sub norm_dir {
301                  my $foo = shift;                  my $foo = shift;
# Line 225  sub snap_share { Line 311  sub snap_share {
311          my $di = 0;          my $di = 0;
312          while ($di <= $#dirs && $real_bl) {          while ($di <= $#dirs && $real_bl) {
313                  my $d=$dirs[$di++];                  my $d=$dirs[$di++];
314                  opendir(DIR,"$bl/$d") || warn "opendir($bl/$d): $!\n";                  opendir(DIR,"$real_bl/$d") || warn "opendir($real_bl/$d): $!\n";
315    
316                  # read .backupignore if exists                  # read .backupignore if exists
317                  if (-f "$bl/$d/.backupignore") {                  if (-f "$real_bl/$d/.backupignore") {
318                          open(I,"$bl/$d/.backupignore");                          open(I,"$real_bl/$d/.backupignore");
319                          while(<I>) {                          while(<I>) {
320                                  chomp;                                  chomp;
321                                  push @ignore,norm_dir("$d/$_");                                  push @ignore,norm_dir("$d/$_");
322                          }                          }
323                          close(I);                          close(I);
324  print STDERR "ignore: ",join("|",@ignore),"\n";  #print STDERR "ignore: ",join("|",@ignore),"\n";
325                          link "$bl/$d/.backupignore","$bc/$d/.backupignore" ||                          link "$real_bl/$d/.backupignore","$bc/$d/.backupignore" ||
326                                  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";
327                  }                  }
328    
329                  # read .md5sum if exists                  # read .md5sum if exists
330                  if (-f "$bl/$d/.md5sum") {                  if (-f "$real_bl/$d/.md5sum") {
331                          open(I,"$bl/$d/.md5sum");                          open(I,"$real_bl/$d/.md5sum");
332                          while(<I>) {                          while(<I>) {
333                                  chomp;                                  chomp;
334                                  my ($md5,$f) = split(/\s+/,$_,2);                                  my ($md5,$f) = split(/\s+/,$_,2);
# Line 256  print STDERR "ignore: ",join("|",@ignore Line 342  print STDERR "ignore: ",join("|",@ignore
342                          next if ($f eq '.');                          next if ($f eq '.');
343                          next if ($f eq '..');                          next if ($f eq '..');
344                          my $pr = norm_dir("$d/$f");     # path relative                          my $pr = norm_dir("$d/$f");     # path relative
345                          my $pf = norm_dir("$d/$f","$bl/");      # path full                          my $pf = norm_dir("$d/$f","$real_bl/"); # path full
346                          if (grep(/^\Q$pr\E$/,@ignore) == 0) {                          if (grep(/^\Q$pr\E$/,@ignore) == 0) {
347                                  if (-f $pf) {                                  if (-f $pf) {
348                                          push @files,$pr;                                          push @files,$pr;
# Line 266  print STDERR "ignore: ",join("|",@ignore Line 352  print STDERR "ignore: ",join("|",@ignore
352                                  } elsif (-d $pf) {                                  } elsif (-d $pf) {
353                                          push @dirs,$pr;                                          push @dirs,$pr;
354                                  } else {                                  } else {
355                                          print STDERR "unknown type: $pf\n";                                          print STDERR "not file or directory: $pf\n";
356                                  }                                  }
357                          } else {                          } else {
358                                  print STDERR "ignored: $pr\n";                                  print STDERR "ignored: $pr\n";
# Line 274  print STDERR "ignore: ",join("|",@ignore Line 360  print STDERR "ignore: ",join("|",@ignore
360                  }                  }
361          }          }
362    
363          xlog($share,($#files+1)." files and ".($#dirs+1)." dirs on local disk before backup");          # local dir always include /
364            xlog($share,($#files+1)." files and ".($#dirs)." dirs on local disk before backup");
365    
366          # read smb filesystem          # read smb filesystem
367    
# Line 285  print STDERR "ignore: ",join("|",@ignore Line 372  print STDERR "ignore: ",join("|",@ignore
372    
373          $di = 0;          $di = 0;
374          while ($di <= $#smb_dirs) {          while ($di <= $#smb_dirs) {
375                  my $d=$smb_dirs[$di++];                  my $d=$smb_dirs[$di];
376                  my $pf = norm_dir($d,"smb:$share/");    # path full                  my $pf = norm_dir($d,"smb:$share/");    # path full
377                  my $D = $smb->opendir($pf) || warn "smb->opendir($pf): $!\n";                  my $D = $smb->opendir($pf);
378                    if (! $D) {
379                            xlog($share,"FATAL: $share [$pf]: $!");
380                            # remove failing dir
381                            delete $smb_dirs[$di];
382                            return 0;                       # failed
383                    }
384                    $di++;
385    
386                  my @clutter = $smb->readdir_struct($D);                  my @clutter = $smb->readdir_struct($D);
387                  foreach my $item (@clutter) {                  foreach my $item (@clutter) {
# Line 305  print STDERR "ignore: ",join("|",@ignore Line 399  print STDERR "ignore: ",join("|",@ignore
399                                  } elsif ($item->[0] == main::SMBC_DIR) {                                  } elsif ($item->[0] == main::SMBC_DIR) {
400                                          push @smb_dirs,$pr;                                          push @smb_dirs,$pr;
401                                  } else {                                  } else {
402                                          print STDERR "unknown type: $pf\n";                                          print STDERR "not file or directory [",$item->[0],"]: $pf\n";
403                                  }                                  }
404                          } else {                          } else {
405                                  print STDERR "smb ignored: $pr\n";                                  print STDERR "smb ignored: $pr\n";
# Line 313  print STDERR "ignore: ",join("|",@ignore Line 407  print STDERR "ignore: ",join("|",@ignore
407                  }                  }
408          }          }
409    
410          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");
411    
412          # sync dirs          # sync dirs
413          my $lc = List::Compare->new(\@dirs, \@smb_dirs);          my $lc = List::Compare->new(\@dirs, \@smb_dirs);
# Line 345  print STDERR "ignore: ",join("|",@ignore Line 439  print STDERR "ignore: ",join("|",@ignore
439                                    
440                  foreach my $f (@_) {                  foreach my $f (@_) {
441  #print "smb_copy $from/$f -> $to/$f\n";  #print "smb_copy $from/$f -> $to/$f\n";
442                          if (! open(F,"> $to/$f")) {                          my $md5 = Digest::MD5->new;
                                 print STDERR "can't open new file $to/$f: $!\n";  
                                 next;  
                         }  
443    
444                          my $fd = $smb->open("$from/$f");                          my $fd = $smb->open("$from/$f");
445                          if (! $fd) {                          if (! $fd) {
446                                  print STDERR "can't open smb file $from/$f: $!\n";                                  xlog("WARNING","can't open smb file $from/$f: $!");
447                                    next;
448                            }
449    
450                            if (! open(F,"> $to/$f")) {
451                                    xlog("WARNING","can't open new file $to/$f: $!");
452                                  next;                                  next;
453                          }                          }
454    
455                          while (defined(my $b=$smb->read($fd,4096))) {                          while (defined(my $b=$smb->read($fd,4096))) {
456                                  print F $b;                                  print F $b;
457                                  $l += length($b);                                  $l += length($b);
458                                    $md5->add($b);
459                          }                          }
460    
461                          $smb->close($fd);                          $smb->close($fd);
462                          close(F);                          close(F);
463    
464                            $file_md5{$f} = $md5->hexdigest;
465    
466                          # FIX: this fails with -T                          # FIX: this fails with -T
467                          my ($a,$m) = ($smb->stat("$from/$f"))[10,11];                          my ($a,$m) = ($smb->stat("$from/$f"))[10,11];
468                          utime $a, $m, "$to/$f" ||                          utime $a, $m, "$to/$f" ||
# Line 417  print STDERR "ignore: ",join("|",@ignore Line 516  print STDERR "ignore: ",join("|",@ignore
516          xlog($share,"$transfer bytes transfered...");          xlog($share,"$transfer bytes transfered...");
517    
518          foreach (@ln_files) {          foreach (@ln_files) {
519                  link "$bl/$_","$bc/$_" || warn "link $bl/$_ -> $bc/$_: $!\n";                  link "$real_bl/$_","$bc/$_" || warn "link $real_bl/$_ -> $bc/$_: $!\n";
520          }          }
521    
522          # remove files          # remove files
523          foreach (sort @files2erase) {          foreach (sort @files2erase) {
524                  unlink "$bc/$_" || warn "unlink $_: $!\n";                  unlink "$bc/$_" || warn "unlink $_: $!\n";
525                    delete $file_md5{$_};
526          }          }
527    
528          # remove not needed dirs (after files)          # remove not needed dirs (after files)
# Line 430  print STDERR "ignore: ",join("|",@ignore Line 530  print STDERR "ignore: ",join("|",@ignore
530                  rmdir "$bc/$_" || warn "rmdir $_: $!\n";                  rmdir "$bc/$_" || warn "rmdir $_: $!\n";
531          }          }
532    
533            # remove old .md5sum
534          # FIX: create .md5sum          foreach (sort @dirs) {
535                    unlink "$bc/$_/.md5sum" if (-e "$bc/$_/.md5sum");
536            }
537    
538            # erase stale entries in .md5sum
539            my @md5_files = keys %file_md5;
540            $lc = List::Compare->new(\@md5_files, \@smb_files);
541            foreach my $file ($lc->get_Lonly) {
542                    xlog("NOTICE","removing stale '$file' from .md5sum");
543                    delete $file_md5{$file};
544            }
545    
546            # create .md5sum
547            my $last_dir = '';
548            my $md5;
549            foreach my $f (sort { $file_md5{$a} cmp $file_md5{$b} } keys %file_md5) {
550                    my $dir = dirname($f);
551                    my $file = basename($f);
552    #print "$f -- $dir / $file<--\n";
553                    if ($dir ne $last_dir) {
554                            close($md5) if ($md5);
555                            open($md5, ">> $bc/$dir/.md5sum") || warn "can't create $bc/$dir/.md5sum: $!";
556                            $last_dir = $dir;
557    #print STDERR "writing $last_dir/.md5sum\n";
558                    }
559                    print $md5 $file_md5{$f},"  $file\n";
560            }
561            close($md5) if ($md5);
562    
563          # create leatest link          # create leatest link
564    #print "ln -s $bc $real_bl\n";
565            if (-l $bl) {
566                    unlink $bl || warn "can't remove old latest symlink $bl: $!\n";
567            }
568          symlink $bc,$bl || warn "can't create latest symlink $bl -> $bc: $!\n";          symlink $bc,$bl || warn "can't create latest symlink $bl -> $bc: $!\n";
569    
570            # FIX: sanity check -- remove for speedup
571            xlog($share,"failed to create latest symlink $bl -> $bc...") if (readlink($bl) ne $bc || ! -l $bl);
572    
573          xlog($share,"backup completed...");          xlog($share,"backup completed...");
 }  
574    
575            return 1;
576    }
577    __END__
578  #-------------------------------------------------------------------------  #-------------------------------------------------------------------------
579    
580    
581    =head1 NAME
582    
583    psinib - Perl Snapshot Is Not Incremental Backup
584    
585    =head1 SYNOPSIS
586    
587    ./psinib.pl
588    
589    =head1 DESCRIPTION
590    
591    This script in current version support just backup of Samba (or Micro$oft
592    Winblowz) shares to central disk space. Central disk space is organized in
593    multiple directories named after:
594    
595    =over 4
596    
597    =item *
598    server which is sharing files to be backed up
599    
600    =item *
601    name of share on server
602    
603    =item *
604    dated directory named like standard ISO date format (YYYYMMDD).
605    
606    =back
607    
608    In each dated directory you will find I<snapshot> of all files on
609    exported share on that particular date.
610    
611    You can also use symlink I<latest> which will lead you to
612    last completed backup. After that you can use some other backup
613    software to transfer I<snapshot> to tape, CD-ROM or some other media.
614    
615    =head2 Design considerations
616    
617    Since taking of share snapshot every day requires a lot of disk space and
618    network bandwidth, B<psinib> uses several techniques to keep disk usage and
619    network traffic at acceptable level:
620    
621    =over 3
622    
623    =item - usage of hard-links to provide same files in each snapshot (as opposed
624    to have multiple copies of same file)
625    
626    =item - usage of file size, atime and mtime to find changes of files without
627    transferring whole file over network (just share browsing is transfered
628    over network)
629    
630    =item - usage of C<.md5sum> files (compatible with command-line utility
631    C<md5sum>) to keep file between snapshots hard-linked
632    
633    =back
634    
635    =head1 CONFIGURATION
636    
637    This section is not yet written.
638    
639    =head1 HACKS, TRICKS, BUGS and LIMITATIONS
640    
641    This chapter will have all content that doesn't fit anywhere else.
642    
643    =head2 Can snapshots be more frequent than daily?
644    
645    There is not real reason why you can't take snapshot more often than
646    once a day. Actually, if you are using B<psinib> to backup Windows
647    workstations you already know that they tend to come-and-go during the day
648    (reboots probably ;-), so running B<psinib> several times a day increases
649    your chance of having up-to-date backup (B<psinib> will not make multiple
650    snapshots for same day, nor will it update snapshot for current day if
651    it already exists).
652    
653    However, changing B<psinib> to produce snapshots which are, for example, hourly
654    is a simple change of C<$DIR_TIME_FMT> which is currently set to
655    C<'%Y%m%d'> (see I<strftime> documentation for explanation of that
656    format). If you change that to C<'%Y%m%d-%H> you can have hourly snapshots
657    (if your network is fast enough, that is...). Also, some of messages in
658    program will sound strange, but other than that it should work.
659    I<You have been warned>.
660    
661    =head2 Do I really need to share every directory which I want to snapshot?
662    
663    Actually, no. Due to usage of C<Filesys::SmbClient> module, you can also
664    specify sub-directory inside your share that you want to backup. This feature
665    is most useful if you want to use administrative shares (but, have in mind
666    that you have to enter your Win administrator password in unencrypted file on
667    disk to do that) like this:
668    
669            smbmount //server/c$/WinNT/fonts  /mnt  -o username=administrator%win  
670    
671    After that you will get directories with snapshots like:
672    
673            server/c_WinNT_fonts/yyyymmdd/....
674    
675    =head2 Won't I run out of disk space?
676    
677    Of course you will... Snapshots and logfiles will eventually fill-up your disk.
678    However, you can do two things to stop that:
679    
680    =head3 Clean snapshort older than x days
681    
682    You can add following command to your C<root> crontab:
683    
684            find /backup/isis_backup -type d -mindepth 3 -maxdepth 3 -mtime +11 -exec rm -Rf {} \;
685    
686    I assume that C</backup/isis_backup> is directory in which are your snapshots
687    and that you don't want to keep snapshots older than 11 days (that's
688    C<-mtime +11> part of command).
689    
690    =head3 Rotate your logs
691    
692    I will leave that to you. I relay on GNU/Debian's C<logrotate> to do it for me.
693    
694    =head2 What are I<YYYYMMDD.partial> directories?
695    
696    If there isn't I<latest> symlink in snapshot directory, it's preatty safe to
697    assume that previous backup from that day failed. So, that directory will
698    be renamed to I<YYYYMMDD.partial> and snapshot will be performed again,
699    linking same files (other alternative would be to erase that dir and find
700    second-oldest directory, but this seemed like more correct approach).
701    
702    =head2 I can't connect to any share
703    
704    Please verify that nmblookup (which is part of samba package) is in /bin or
705    /usr/bin. Also verify that nmblookup returns IP address for your server
706    using:
707    
708       $ nmblookup tvhouse
709       querying tvhouse on 192.168.34.255
710       192.168.34.30 tvhouse<00>
711    
712    If you don't get any output, your samba might not listen to correct interface
713    (see interfaces in smb.conf).
714    
715    =head1 AUTHOR
716    
717    Dobrica Pavlinusic <dpavlin@rot13.org>
718    
719    L<http://www.rot13.org/~dpavlin/>
720    
721    =head1 LICENSE
722    
723    This product is licensed under GNU Public License (GPL) v2 or later.
724    
725    =cut

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

  ViewVC Help
Powered by ViewVC 1.1.26