/[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.15 by dpavlin, Sun Oct 12 21:46:42 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  my $LOG = '/var/log/backup.log';        # add path here...  my $LOG = '/var/log/backup.log';        # add path here...
34  $LOG = '/tmp/backup.log';  #$LOG = '/tmp/backup.log';
35    
36  # store backups in which directory  # store backups in which directory
37  my $BACKUP_DEST = '/data/isis_backup';  my $BACKUP_DEST = '/backup/isis_backup';
38    #my $BACKUP_DEST = '/tmp/backup/';
39    
40  # files to ignore in backup  # files to ignore in backup
41  my @ignore = ('.md5sum', '.backupignore', 'backupignore.txt');  my @ignore = ('.md5sum', '.backupignore', 'backupignore.txt');
42    
43  # open log  # open log
44  open(L, "> $LOG") || die "can't open log $LOG: $!";  open(L, ">> $LOG") || die "can't open log $LOG: $!";
45  select((select(L), $|=1)[0]);   # flush output  select((select(L), $|=1)[0]);   # flush output
46    
47  # make a lock on logfile  # make a lock on logfile
# Line 48  my $c = 0; Line 52  my $c = 0;
52          sleep 1;          sleep 1;
53          redo if ++$c < 10;          redo if ++$c < 10;
54          # no response for 10 sec, bail out          # no response for 10 sec, bail out
55          print STDERR "can't take lock on $LOG -- another $0 running?\n";          xlog("ABORT","can't take lock on $LOG -- another $0 running?");
56          exit 1;          exit 1;
57  }  }
58    
59  # taint path: nmblookup should be there!  # taint path: nmblookup should be there!
60  $ENV{'PATH'} = "/usr/bin:/bin";  $ENV{'PATH'} = "/usr/bin:/bin";
61    
62    my $use_ping = 1;       # deault: use ping to verify that host is up
63    
64    my $result = GetOptions(
65            "ping!" => \$use_ping, "backupdest!" => \$BACKUP_DEST,
66    );
67    
68  my $mounts = shift @ARGV ||  my $mounts = shift @ARGV ||
69          'mountscript';          'mountscript';
70  #       die "usage: $0 mountscript";  #       die "usage: $0 mountscript";
# Line 62  my $mounts = shift @ARGV || Line 72  my $mounts = shift @ARGV ||
72    
73  my @in_backup;  # shares which are backeduped this run  my @in_backup;  # shares which are backeduped this run
74    
75  my $p = new Net::Ping->new();  my $ping;
76    if ($use_ping) {
77            $ping = new Net::Ping->new("tcp", 2);
78            # ping will try tcp connect to netbios-ssn (139)
79            $ping->{port_num} = getservbyname("netbios-ssn", "tcp");
80    }
81    
82  my $backup_ok = 0;  my $backup_ok = 0;
83    
84  my $smb;  my $smb;
85  my %smb_atime;  my %smb_atime;
86  my %smb_mtime;  my %smb_mtime;
87    my %file_md5;
88    
89  open(M, $mounts) || die "can't open $mounts: $!";  open(M, $mounts) || die "can't open $mounts: $!";
90  while(<M>) {  while(<M>) {
# Line 76  while(<M>) { Line 92  while(<M>) {
92          next if !/^\s*smbmount\s/;          next if !/^\s*smbmount\s/;
93          my (undef,$share,undef,$opt) = split(/\s+/,$_,4);          my (undef,$share,undef,$opt) = split(/\s+/,$_,4);
94    
95          my ($user,$passwd,$workgroup);          my ($user,$passwd,$workgroup,$ip);
96    
97          foreach (split(/,/,$opt)) {          foreach (split(/,/,$opt)) {
98                  my ($n,$v) = split(/=/,$_,2);                  my ($n,$v) = split(/=/,$_,2);
# Line 92  while(<M>) { Line 108  while(<M>) {
108                          }                          }
109                  } elsif ($n =~ m#workgroup#i) {                  } elsif ($n =~ m#workgroup#i) {
110                          $workgroup = $v;                          $workgroup = $v;
111                    } elsif ($n =~ m#ip#i) {
112                            $ip = $v;
113                  }                  }
114          }          }
115    
116          push @in_backup,$share;          push @in_backup,$share;
117    
118    
119            my ($host,$dir,$date_dir) = share2host_dir($share);
120            my $bl = "$BACKUP_DEST/$host/$dir/latest";      # latest backup
121            my $bc = "$BACKUP_DEST/$host/$dir/$date_dir";   # current one
122            my $real_bl;
123            if (-l $bl) {
124                    $real_bl=readlink($bl) || die "can't read link $bl: $!";
125                    $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/");
126                    if (-l $bc && $real_bl eq $bc) {
127                            print "$share allready backuped...\n";
128                            $backup_ok++;
129                            next;
130                    }
131    
132            }
133    
134    
135          print "working on $share\n";          print "working on $share\n";
136    
137          my $ip = get_ip($share);          # try to nmblookup IP
138            $ip = get_ip($share) if (! $ip);
139    
140          if ($ip) {          if ($ip) {
141                  xlog($share,"IP is $ip");                  xlog($share,"IP is $ip");
142                  if ($p->ping($ip)) {                  if (($use_ping && $ping->ping($ip)) || 1) {
143                          snap_share($share,$user,$passwd,$workgroup);                          if (snap_share($share,$user,$passwd,$workgroup)) {
144                          $backup_ok++;                                  $backup_ok++;
145                            }
146                  }                  }
147          }          }
148  }  }
# Line 117  xlog("","$backup_ok backups completed of Line 154  xlog("","$backup_ok backups completed of
154    
155  #-------------------------------------------------------------------------  #-------------------------------------------------------------------------
156    
157    
158  # get IP number from share  # get IP number from share
159  sub get_ip {  sub get_ip {
160          my $share = shift;          my $share = shift;
# Line 129  sub get_ip { Line 167  sub get_ip {
167          }          }
168  }  }
169    
170    
171    # write entry to screen and log
172  sub xlog {  sub xlog {
173          my $share = shift;          my $share = shift;
174          my $t = strftime $LOG_TIME_FMT, localtime;          my $t = strftime $LOG_TIME_FMT, localtime;
# Line 137  sub xlog { Line 177  sub xlog {
177          print L "$t $share\t$m\n";          print L "$t $share\t$m\n";
178  }  }
179    
180  sub snap_share {  # dump warn and dies into log
181    BEGIN { $SIG{'__WARN__'} = sub { xlog('WARN',$_[0]) ; warn $_[0] } }
182    BEGIN { $SIG{'__DIE__'} = sub { xlog('DIE',$_[0]) ; die $_[0] } }
183    
         my $share = shift;  
   
         my %param = ( debug => 0 );  
   
         $param{username} = shift;  
         $param{password} = shift;  
         $param{workgroup} = shift;  
184    
185    # split share name to host, dir and currnet date dir
186    sub share2host_dir {
187            my $share = shift;
188          my ($host,$dir);          my ($host,$dir);
189          if ($share =~ m#//([^/]+)/(.+)$#) {          if ($share =~ m#//([^/]+)/(.+)$#) {
190                  ($host,$dir) = ($1,$2);                  ($host,$dir) = ($1,$2);
# Line 157  sub snap_share { Line 195  sub snap_share {
195                  print "Can't parse share $share into host and directory!\n";                  print "Can't parse share $share into host and directory!\n";
196                  return;                  return;
197          }          }
198            return ($host,$dir,strftime $DIR_TIME_FMT, localtime);
199    }
200    
201          my $date_dir = strftime $DIR_TIME_FMT, localtime;  
202    # make a snapshot of a share
203    sub snap_share {
204    
205            my $share = shift;
206    
207            my %param = ( debug => 0 );
208    
209            $param{username} = shift || warn "can't find username for share $share";
210            $param{password} = shift || warn "can't find passwod for share $share";
211            $param{workgroup} = shift || warn "can't find workgroup for share $share";
212    
213            my ($host,$dir,$date_dir) = share2host_dir($share);
214    
215          # latest backup directory          # latest backup directory
216          my $bl = "$BACKUP_DEST/$host/$dir/latest";          my $bl = "$BACKUP_DEST/$host/$dir/latest";
# Line 166  sub snap_share { Line 218  sub snap_share {
218          my $bc = "$BACKUP_DEST/$host/$dir/$date_dir";          my $bc = "$BACKUP_DEST/$host/$dir/$date_dir";
219    
220          my $real_bl;          my $real_bl;
221          if (-e $bl) {          if (-l $bl) {
222                  $real_bl=readlink($bl) || die "can't read link $bl: $!";                  $real_bl=readlink($bl) || die "can't read link $bl: $!";
223                  $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 "/");
224          } else {          } else {
225                  print "no old backup, this is first run...\n";                  print "no old backup, trying to find last backup, ";
226                    if (opendir(BL_DIR, "$BACKUP_DEST/$host/$dir")) {
227                            my @bl_dirs = sort grep { !/^\./ && -d "$BACKUP_DEST/$host/$dir/$_" } readdir(BL_DIR);
228                            closedir(BL_DIR);
229                            $real_bl=pop @bl_dirs;
230                            print "using $real_bl as latest...\n";
231                            $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/");
232                            if ($real_bl eq $bc) {
233                                    xlog($share,"latest from today (possible partial backup)");
234                                    rename $real_bl,$real_bl.".partial" || warn "can't reaname partial backup: $!";
235                                    $real_bl .= ".partial";
236                            }
237                    } else {
238                            print "this is first run...\n";
239                    }
240          }          }
241    
242          if (-e $bc && $real_bl && $real_bl eq $bc) {          if (-l $bc && $real_bl && $real_bl eq $bc) {
243                  print "$share allready backuped...\n";                  print "$share allready backuped...\n";
244                  return;                  return 1;
245          }          }
246    
247          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 268  sub snap_share {
268          my %file_size;          my %file_size;
269          my %file_atime;          my %file_atime;
270          my %file_mtime;          my %file_mtime;
271          my %file_md5;          #my %file_md5;
272            %file_md5 = ();
273    
274          my @smb_files;          my @smb_files;
275          my %smb_size;          my %smb_size;
276          #my %smb_atime;          #my %smb_atime;
277          #my %smb_mtime;          #my %smb_mtime;
         my %smb_md5;  
   
278    
279          sub norm_dir {          sub norm_dir {
280                  my $foo = shift;                  my $foo = shift;
# Line 225  sub snap_share { Line 290  sub snap_share {
290          my $di = 0;          my $di = 0;
291          while ($di <= $#dirs && $real_bl) {          while ($di <= $#dirs && $real_bl) {
292                  my $d=$dirs[$di++];                  my $d=$dirs[$di++];
293                  opendir(DIR,"$bl/$d") || warn "opendir($bl/$d): $!\n";                  opendir(DIR,"$real_bl/$d") || warn "opendir($real_bl/$d): $!\n";
294    
295                  # read .backupignore if exists                  # read .backupignore if exists
296                  if (-f "$bl/$d/.backupignore") {                  if (-f "$real_bl/$d/.backupignore") {
297                          open(I,"$bl/$d/.backupignore");                          open(I,"$real_bl/$d/.backupignore");
298                          while(<I>) {                          while(<I>) {
299                                  chomp;                                  chomp;
300                                  push @ignore,norm_dir("$d/$_");                                  push @ignore,norm_dir("$d/$_");
301                          }                          }
302                          close(I);                          close(I);
303  print STDERR "ignore: ",join("|",@ignore),"\n";  #print STDERR "ignore: ",join("|",@ignore),"\n";
304                          link "$bl/$d/.backupignore","$bc/$d/.backupignore" ||                          link "$real_bl/$d/.backupignore","$bc/$d/.backupignore" ||
305                                  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";
306                  }                  }
307    
308                  # read .md5sum if exists                  # read .md5sum if exists
309                  if (-f "$bl/$d/.md5sum") {                  if (-f "$real_bl/$d/.md5sum") {
310                          open(I,"$bl/$d/.md5sum");                          open(I,"$real_bl/$d/.md5sum");
311                          while(<I>) {                          while(<I>) {
312                                  chomp;                                  chomp;
313                                  my ($md5,$f) = split(/\s+/,$_,2);                                  my ($md5,$f) = split(/\s+/,$_,2);
# Line 256  print STDERR "ignore: ",join("|",@ignore Line 321  print STDERR "ignore: ",join("|",@ignore
321                          next if ($f eq '.');                          next if ($f eq '.');
322                          next if ($f eq '..');                          next if ($f eq '..');
323                          my $pr = norm_dir("$d/$f");     # path relative                          my $pr = norm_dir("$d/$f");     # path relative
324                          my $pf = norm_dir("$d/$f","$bl/");      # path full                          my $pf = norm_dir("$d/$f","$real_bl/"); # path full
325                          if (grep(/^\Q$pr\E$/,@ignore) == 0) {                          if (grep(/^\Q$pr\E$/,@ignore) == 0) {
326                                  if (-f $pf) {                                  if (-f $pf) {
327                                          push @files,$pr;                                          push @files,$pr;
# Line 266  print STDERR "ignore: ",join("|",@ignore Line 331  print STDERR "ignore: ",join("|",@ignore
331                                  } elsif (-d $pf) {                                  } elsif (-d $pf) {
332                                          push @dirs,$pr;                                          push @dirs,$pr;
333                                  } else {                                  } else {
334                                          print STDERR "unknown type: $pf\n";                                          print STDERR "not file or directory: $pf\n";
335                                  }                                  }
336                          } else {                          } else {
337                                  print STDERR "ignored: $pr\n";                                  print STDERR "ignored: $pr\n";
# Line 274  print STDERR "ignore: ",join("|",@ignore Line 339  print STDERR "ignore: ",join("|",@ignore
339                  }                  }
340          }          }
341    
342          xlog($share,($#files+1)." files and ".($#dirs+1)." dirs on local disk before backup");          # local dir always include /
343            xlog($share,($#files+1)." files and ".($#dirs)." dirs on local disk before backup");
344    
345          # read smb filesystem          # read smb filesystem
346    
# Line 285  print STDERR "ignore: ",join("|",@ignore Line 351  print STDERR "ignore: ",join("|",@ignore
351    
352          $di = 0;          $di = 0;
353          while ($di <= $#smb_dirs) {          while ($di <= $#smb_dirs) {
354                  my $d=$smb_dirs[$di++];                  my $d=$smb_dirs[$di];
355                  my $pf = norm_dir($d,"smb:$share/");    # path full                  my $pf = norm_dir($d,"smb:$share/");    # path full
356                  my $D = $smb->opendir($pf) || warn "smb->opendir($pf): $!\n";                  my $D = $smb->opendir($pf);
357                    if (! $D) {
358                            xlog($share,"FATAL: $share [$pf]: $!");
359                            # remove failing dir
360                            delete $smb_dirs[$di];
361                            return 0;                       # failed
362                    }
363                    $di++;
364    
365                  my @clutter = $smb->readdir_struct($D);                  my @clutter = $smb->readdir_struct($D);
366                  foreach my $item (@clutter) {                  foreach my $item (@clutter) {
# Line 305  print STDERR "ignore: ",join("|",@ignore Line 378  print STDERR "ignore: ",join("|",@ignore
378                                  } elsif ($item->[0] == main::SMBC_DIR) {                                  } elsif ($item->[0] == main::SMBC_DIR) {
379                                          push @smb_dirs,$pr;                                          push @smb_dirs,$pr;
380                                  } else {                                  } else {
381                                          print STDERR "unknown type: $pf\n";                                          print STDERR "not file or directory [",$item->[0],"]: $pf\n";
382                                  }                                  }
383                          } else {                          } else {
384                                  print STDERR "smb ignored: $pr\n";                                  print STDERR "smb ignored: $pr\n";
# Line 313  print STDERR "ignore: ",join("|",@ignore Line 386  print STDERR "ignore: ",join("|",@ignore
386                  }                  }
387          }          }
388    
389          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");
390    
391          # sync dirs          # sync dirs
392          my $lc = List::Compare->new(\@dirs, \@smb_dirs);          my $lc = List::Compare->new(\@dirs, \@smb_dirs);
# Line 345  print STDERR "ignore: ",join("|",@ignore Line 418  print STDERR "ignore: ",join("|",@ignore
418                                    
419                  foreach my $f (@_) {                  foreach my $f (@_) {
420  #print "smb_copy $from/$f -> $to/$f\n";  #print "smb_copy $from/$f -> $to/$f\n";
421                          if (! open(F,"> $to/$f")) {                          my $md5 = Digest::MD5->new;
                                 print STDERR "can't open new file $to/$f: $!\n";  
                                 next;  
                         }  
422    
423                          my $fd = $smb->open("$from/$f");                          my $fd = $smb->open("$from/$f");
424                          if (! $fd) {                          if (! $fd) {
425                                  print STDERR "can't open smb file $from/$f: $!\n";                                  xlog("WARNING","can't open smb file $from/$f: $!");
426                                    next;
427                            }
428    
429                            if (! open(F,"> $to/$f")) {
430                                    xlog("WARNING","can't open new file $to/$f: $!");
431                                  next;                                  next;
432                          }                          }
433    
434                          while (defined(my $b=$smb->read($fd,4096))) {                          while (defined(my $b=$smb->read($fd,4096))) {
435                                  print F $b;                                  print F $b;
436                                  $l += length($b);                                  $l += length($b);
437                                    $md5->add($b);
438                          }                          }
439    
440                          $smb->close($fd);                          $smb->close($fd);
441                          close(F);                          close(F);
442    
443                            $file_md5{$f} = $md5->hexdigest;
444    
445                          # FIX: this fails with -T                          # FIX: this fails with -T
446                          my ($a,$m) = ($smb->stat("$from/$f"))[10,11];                          my ($a,$m) = ($smb->stat("$from/$f"))[10,11];
447                          utime $a, $m, "$to/$f" ||                          utime $a, $m, "$to/$f" ||
# Line 417  print STDERR "ignore: ",join("|",@ignore Line 495  print STDERR "ignore: ",join("|",@ignore
495          xlog($share,"$transfer bytes transfered...");          xlog($share,"$transfer bytes transfered...");
496    
497          foreach (@ln_files) {          foreach (@ln_files) {
498                  link "$bl/$_","$bc/$_" || warn "link $bl/$_ -> $bc/$_: $!\n";                  link "$real_bl/$_","$bc/$_" || warn "link $real_bl/$_ -> $bc/$_: $!\n";
499          }          }
500    
501          # remove files          # remove files
502          foreach (sort @files2erase) {          foreach (sort @files2erase) {
503                  unlink "$bc/$_" || warn "unlink $_: $!\n";                  unlink "$bc/$_" || warn "unlink $_: $!\n";
504                    delete $file_md5{$_};
505          }          }
506    
507          # remove not needed dirs (after files)          # remove not needed dirs (after files)
# Line 430  print STDERR "ignore: ",join("|",@ignore Line 509  print STDERR "ignore: ",join("|",@ignore
509                  rmdir "$bc/$_" || warn "rmdir $_: $!\n";                  rmdir "$bc/$_" || warn "rmdir $_: $!\n";
510          }          }
511    
512            # remove old .md5sum
513          # FIX: create .md5sum          foreach (sort @dirs) {
514                    unlink "$bc/$_/.md5sum" if (-e "$bc/$_/.md5sum");
515            }
516    
517            # erase stale entries in .md5sum
518            my @md5_files = keys %file_md5;
519            $lc = List::Compare->new(\@md5_files, \@smb_files);
520            foreach my $file ($lc->get_Lonly) {
521                    xlog("NOTICE","removing stale '$file' from .md5sum");
522                    delete $file_md5{$file};
523            }
524    
525            # create .md5sum
526            my $last_dir = '';
527            my $md5;
528            foreach my $f (sort { $file_md5{$a} cmp $file_md5{$b} } keys %file_md5) {
529                    my $dir = dirname($f);
530                    my $file = basename($f);
531    #print "$f -- $dir / $file<--\n";
532                    if ($dir ne $last_dir) {
533                            close($md5) if ($md5);
534                            open($md5, ">> $bc/$dir/.md5sum") || warn "can't create $bc/$dir/.md5sum: $!";
535                            $last_dir = $dir;
536    #print STDERR "writing $last_dir/.md5sum\n";
537                    }
538                    print $md5 $file_md5{$f},"  $file\n";
539            }
540            close($md5) if ($md5);
541    
542          # create leatest link          # create leatest link
543    #print "ln -s $bc $real_bl\n";
544            if (-l $bl) {
545                    unlink $bl || warn "can't remove old latest symlink $bl: $!\n";
546            }
547          symlink $bc,$bl || warn "can't create latest symlink $bl -> $bc: $!\n";          symlink $bc,$bl || warn "can't create latest symlink $bl -> $bc: $!\n";
548    
549            # FIX: sanity check -- remove for speedup
550            xlog($share,"failed to create latest symlink $bl -> $bc...") if (readlink($bl) ne $bc || ! -l $bl);
551    
552          xlog($share,"backup completed...");          xlog($share,"backup completed...");
 }  
553    
554            return 1;
555    }
556    __END__
557  #-------------------------------------------------------------------------  #-------------------------------------------------------------------------
558    
559    
560    =head1 NAME
561    
562    psinib - Perl Snapshot Is Not Incremental Backup
563    
564    =head1 SYNOPSIS
565    
566    ./psinib.pl
567    
568    =head1 DESCRIPTION
569    
570    This script in current version support just backup of Samba (or Micro$oft
571    Winblowz) shares to central disk space. Central disk space is organized in
572    multiple directories named after:
573    
574    =over 4
575    
576    =item *
577    server which is sharing files to be backed up
578    
579    =item *
580    name of share on server
581    
582    =item *
583    dated directory named like standard ISO date format (YYYYMMDD).
584    
585    =back
586    
587    In each dated directory you will find I<snapshot> of all files on
588    exported share on that particular date.
589    
590    You can also use symlink I<latest> which will lead you to
591    last completed backup. After that you can use some other backup
592    software to transfer I<snapshot> to tape, CD-ROM or some other media.
593    
594    =head2 Design considerations
595    
596    Since taking of share snapshot every day requires a lot of disk space and
597    network bandwidth, B<psinib> uses several techniques to keep disk usage and
598    network traffic at acceptable level:
599    
600    =over 3
601    
602    =item - usage of hard-links to provide same files in each snapshot (as opposed
603    to have multiple copies of same file)
604    
605    =item - usage of file size, atime and mtime to find changes of files without
606    transferring whole file over network (just share browsing is transfered
607    over network)
608    
609    =item - usage of C<.md5sum> files (compatible with command-line utility
610    C<md5sum>) to keep file between snapshots hard-linked
611    
612    =back
613    
614    =head1 CONFIGURATION
615    
616    This section is not yet written.
617    
618    =head1 HACKS, TRICKS, BUGS and LIMITATIONS
619    
620    This chapter will have all content that doesn't fit anywhere else.
621    
622    =head2 Can snapshots be more frequent than daily?
623    
624    There is not real reason why you can't take snapshot more often than
625    once a day. Actually, if you are using B<psinib> to backup Windows
626    workstations you already know that they tend to come-and-go during the day
627    (reboots probably ;-), so running B<psinib> several times a day increases
628    your chance of having up-to-date backup (B<psinib> will not make multiple
629    snapshots for same day, nor will it update snapshot for current day if
630    it already exists).
631    
632    However, changing B<psinib> to produce snapshots which are, for example, hourly
633    is a simple change of C<$DIR_TIME_FMT> which is currently set to
634    C<'%Y%m%d'> (see I<strftime> documentation for explanation of that
635    format). If you change that to C<'%Y%m%d-%H> you can have hourly snapshots
636    (if your network is fast enough, that is...). Also, some of messages in
637    program will sound strange, but other than that it should work.
638    I<You have been warned>.
639    
640    =head2 Do I really need to share every directory which I want to snapshot?
641    
642    Actually, no. Due to usage of C<Filesys::SmbClient> module, you can also
643    specify sub-directory inside your share that you want to backup. This feature
644    is most useful if you want to use administrative shares (but, have in mind
645    that you have to enter your Win administrator password in unencrypted file on
646    disk to do that) like this:
647    
648            smbmount //server/c$/WinNT/fonts  /mnt  -o username=administrator%win  
649    
650    After that you will get directories with snapshots like:
651    
652            server/c_WinNT_fonts/yyyymmdd/....
653    
654    =head2 Won't I run out of disk space?
655    
656    Of course you will... Snapshots and logfiles will eventually fill-up your disk.
657    However, you can do two things to stop that:
658    
659    =head3 Clean snapshort older than x days
660    
661    You can add following command to your C<root> crontab:
662    
663            find /backup/isis_backup -type d -mindepth 3 -maxdepth 3 -mtime +11 -exec rm -Rf {} \;
664    
665    I assume that C</backup/isis_backup> is directory in which are your snapshots
666    and that you don't want to keep snapshots older than 11 days (that's
667    C<-mtime +11> part of command).
668    
669    =head3 Rotate your logs
670    
671    I will leave that to you. I relay on GNU/Debian's C<logrotate> to do it for me.
672    
673    =head2 What are I<YYYYMMDD.partial> directories?
674    
675    If there isn't I<latest> symlink in snapshot directory, it's preatty safe to
676    assume that previous backup from that day failed. So, that directory will
677    be renamed to I<YYYYMMDD.partial> and snapshot will be performed again,
678    linking same files (other alternative would be to erase that dir and find
679    second-oldest directory, but this seemed like more correct approach).
680    
681    =head2 I can't connect to any share
682    
683    Please verify that nmblookup (which is part of samba package) is in /bin or
684    /usr/bin. Also verify that nmblookup returns IP address for your server
685    using:
686    
687       $ nmblookup tvhouse
688       querying tvhouse on 192.168.34.255
689       192.168.34.30 tvhouse<00>
690    
691    If you don't get any output, your samba might not listen to correct interface
692    (see interfaces in smb.conf).
693    
694    =head1 AUTHOR
695    
696    Dobrica Pavlinusic <dpavlin@rot13.org>
697    
698    L<http://www.rot13.org/~dpavlin/>
699    
700    =head1 LICENSE
701    
702    This product is licensed under GNU Public License (GPL) v2 or later.
703    
704    =cut

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

  ViewVC Help
Powered by ViewVC 1.1.26