/[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.8 by dpavlin, Tue Mar 4 21:08:43 2003 UTC revision 1.17 by dpavlin, Sun Oct 26 14:04:17 2003 UTC
# Line 24  use Filesys::SmbClient; Line 24  use Filesys::SmbClient;
24  use Fcntl qw(LOCK_EX LOCK_NB);  use Fcntl qw(LOCK_EX LOCK_NB);
25  use Digest::MD5;  use Digest::MD5;
26  use File::Basename;  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 = '/backup/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');
# Line 50  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 64  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("tcp", 2);  # init Net::Ping object
84  # ping will try tcp connect to netbios-ssn (139)  my $ping;
85  $p->{port_num} = getservbyname("netbios-ssn", "tcp");  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    
# Line 81  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 97  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    
# Line 107  while(<M>) { Line 146  while(<M>) {
146          my $bl = "$BACKUP_DEST/$host/$dir/latest";      # latest backup          my $bl = "$BACKUP_DEST/$host/$dir/latest";      # latest backup
147          my $bc = "$BACKUP_DEST/$host/$dir/$date_dir";   # current one          my $bc = "$BACKUP_DEST/$host/$dir/$date_dir";   # current one
148          my $real_bl;          my $real_bl;
149          if (-e $bl) {          if (-l $bl) {
150                  $real_bl=readlink($bl) || die "can't read link $bl: $!";                  $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 "/");                  $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/");
152                  if (-e $bc && $real_bl eq $bc) {                  if (-l $bc && $real_bl eq $bc) {
153                          print "$share allready backuped...\n";                          xlog($share,"allready backuped...");
154                          $backup_ok++;                          $backup_ok++;
155                          next;                          next;
156                  }                  }
# Line 119  while(<M>) { Line 158  while(<M>) {
158          }          }
159    
160    
161          print "working on $share\n";          xlog($share,"working on $share...");
   
162    
163          my $ip = get_ip($share);          # 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 159  sub xlog { Line 199  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    
# Line 178  sub share2host_dir { Line 219  sub share2host_dir {
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);          return ($host,$dir,strftime $DIR_TIME_FMT, localtime);
# Line 204  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, trying to find last backup, ";                  xlog($share,"no old backup, trying to find last backup,");
253                  if (opendir(BL_DIR, "$BACKUP_DEST/$host/$dir")) {                  if (opendir(BL_DIR, "$BACKUP_DEST/$host/$dir")) {
254                          my @bl_dirs = sort grep { !/^\./ && -d "$BACKUP_DEST/$host/$dir/$_" } readdir(BL_DIR);                          my @bl_dirs = sort grep { !/^\./ && -d "$BACKUP_DEST/$host/$dir/$_" } readdir(BL_DIR);
255                          closedir(BL_DIR);                          closedir(BL_DIR);
256                          $real_bl=pop @bl_dirs;                          $real_bl=pop @bl_dirs;
257                          print "using $real_bl as latest...\n";                          xlog($share,"using $real_bl as latest...");
258                          $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 "/");
259                          if ($real_bl eq $bc) {                          if ($real_bl eq $bc) {
260                                  xlog($share,"latest from today (possible partial backup)");                                  xlog($share,"latest from today (possible partial backup)");
# Line 221  sub snap_share { Line 262  sub snap_share {
262                                  $real_bl .= ".partial";                                  $real_bl .= ".partial";
263                          }                          }
264                  } else {                  } else {
265                          print "this is first run...\n";                          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 255  sub snap_share { Line 296  sub snap_share {
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;
# Line 285  sub snap_share { Line 327  sub snap_share {
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 "$real_bl/$d/.backupignore","$bc/$d/.backupignore" ||                          link "$real_bl/$d/.backupignore","$bc/$d/.backupignore" ||
332                                  warn "can't copy $real_bl/$d/.backupignore to current backup dir: $!\n";                                  warn "can't copy $real_bl/$d/.backupignore to current backup dir: $!\n";
333                  }                  }
# Line 316  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 335  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 355  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 395  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";
                         if (! open(F,"> $to/$f")) {  
                                 print STDERR "can't open new file $to/$f: $!\n";  
                                 next;  
                         }  
   
448                          my $md5 = Digest::MD5->new;                          my $md5 = Digest::MD5->new;
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    
# Line 478  print STDERR "ignore: ",join("|",@ignore Line 528  print STDERR "ignore: ",join("|",@ignore
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 490  print STDERR "ignore: ",join("|",@ignore Line 541  print STDERR "ignore: ",join("|",@ignore
541                  unlink "$bc/$_/.md5sum" if (-e "$bc/$_/.md5sum");                  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          # create .md5sum
553          my $last_dir = '';          my $last_dir = '';
554          my $md5;          my $md5;
# Line 505  print STDERR "ignore: ",join("|",@ignore Line 564  print STDERR "ignore: ",join("|",@ignore
564                  }                  }
565                  print $md5 $file_md5{$f},"  $file\n";                  print $md5 $file_md5{$f},"  $file\n";
566          }          }
567          close($md5);          close($md5) if ($md5);
568    
569          # create leatest link          # create leatest link
570  #print "ln -s $bc $real_bl\n";  #print "ln -s $bc $real_bl\n";
571          if (-e $bl) {          if (-l $bl) {
572                  unlink $bl || warn "can't remove old latest symlink $bl: $!\n";                  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          # FIX: sanity check -- remove for speedup
577          xlog($share,"failed to create latest symlink...") if (readlink($bl) ne $bc || ! -e $bl);          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__  __END__
584  #-------------------------------------------------------------------------  #-------------------------------------------------------------------------
585    
# Line 530  psinib - Perl Snapshot Is Not Incrementa Line 590  psinib - Perl Snapshot Is Not Incrementa
590    
591  =head1 SYNOPSIS  =head1 SYNOPSIS
592    
593  ./psinib.pl  ./psinib.pl [OPTION]... [mount script]
594    
595  =head1 DESCRIPTION  =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  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  Winblowz) shares to central disk space. Central disk space is organized in
623  multiple directories named after:  multiple directories named after:
# Line 645  be renamed to I<YYYYMMDD.partial> and sn Line 729  be renamed to I<YYYYMMDD.partial> and sn
729  linking same files (other alternative would be to erase that dir and find  linking same files (other alternative would be to erase that dir and find
730  second-oldest directory, but this seemed like more correct approach).  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  =head1 AUTHOR
746    
747  Dobrica Pavlinusic <dpavlin@rot13.org>  Dobrica Pavlinusic <dpavlin@rot13.org>
748    
749  L<http://www.rot13.org/~dpavlin/>  L<http:E<sol>E<sol>www.rot13.orgE<sol>~dpavlinE<sol>>
750    
751  =head1 LICENSE  =head1 LICENSE
752    

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

  ViewVC Help
Powered by ViewVC 1.1.26