/[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.18 by dpavlin, Mon Oct 27 18:58:41 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;
203            $l = 1 if (! defined $l);       # default verbosity is 1
204            print STDERR $m,"\n" if ($verbose >= $l);
205          print L "$t $share\t$m\n";          print L "$t $share\t$m\n";
206  }  }
207    
208  # dump warn and dies into log  # dump warn and dies into log
209  BEGIN { $SIG{'__WARN__'} = sub { xlog('WARN',$_[0]) ; warn $_[0] } }  BEGIN { $SIG{'__WARN__'} = sub { xlog('WARN',$_[0],1) ; warn $_[0] } }
210  BEGIN { $SIG{'__DIE__'} = sub { xlog('DIE',$_[0]) ; die $_[0] } }  BEGIN { $SIG{'__DIE__'} = sub { xlog('DIE',$_[0],0) ; die $_[0] } }
211    
212    
213  # split share name to host, dir and currnet date dir  # split share name to host, dir and currnet date dir
# Line 178  sub share2host_dir { Line 220  sub share2host_dir {
220                  $dir =~ s/^_+//;                  $dir =~ s/^_+//;
221                  $dir =~ s/_+$//;                  $dir =~ s/_+$//;
222          } else {          } else {
223                  print "Can't parse share $share into host and directory!\n";                  xlog($share,"Can't parse share $share into host and directory!",1);
224                  return;                  return;
225          }          }
226          return ($host,$dir,strftime $DIR_TIME_FMT, localtime);          return ($host,$dir,strftime $DIR_TIME_FMT, localtime);
# Line 204  sub snap_share { Line 246  sub snap_share {
246          my $bc = "$BACKUP_DEST/$host/$dir/$date_dir";          my $bc = "$BACKUP_DEST/$host/$dir/$date_dir";
247    
248          my $real_bl;          my $real_bl;
249          if (-e $bl) {          if (-l $bl) {
250                  $real_bl=readlink($bl) || die "can't read link $bl: $!";                  $real_bl=readlink($bl) || die "can't read link $bl: $!";
251                  $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 "/");
252          } else {                  undef $real_bl if (! -e $real_bl);
253                  print "no old backup, trying to find last backup, ";          }
254            if (! $real_bl) {
255                    xlog($share,"no old backup, trying to find last backup,");
256                  if (opendir(BL_DIR, "$BACKUP_DEST/$host/$dir")) {                  if (opendir(BL_DIR, "$BACKUP_DEST/$host/$dir")) {
257                          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);
258                          closedir(BL_DIR);                          closedir(BL_DIR);
259                          $real_bl=pop @bl_dirs;                          $real_bl=pop @bl_dirs;
260                          print "using $real_bl as latest...\n";                          xlog($share,"using $real_bl as latest...");
261                          $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 "/");
262                          if ($real_bl eq $bc) {                          if ($real_bl eq $bc) {
263                                  xlog($share,"latest from today (possible partial backup)");                                  xlog($share,"latest from today (possible partial backup)");
# Line 221  sub snap_share { Line 265  sub snap_share {
265                                  $real_bl .= ".partial";                                  $real_bl .= ".partial";
266                          }                          }
267                  } else {                  } else {
268                          print "this is first run...\n";                          xlog($share,"this is first run...");
269                  }                  }
270          }          }
271    
272          if (-e $bc && $real_bl && $real_bl eq $bc) {          if (-l $bc && $real_bl && $real_bl eq $bc) {
273                  print "$share allready backuped...\n";                  xlog($share,"allready backuped...");
274                  return;                  return 1;
275          }          }
276    
277          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);
278    
279          if (! -e "$BACKUP_DEST/$host") {          if (! -e "$BACKUP_DEST/$host") {
280                  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: $!";
281                  print "created host directory $BACKUP_DEST/$host...\n";                  xlog($share,"created host directory $BACKUP_DEST/$host...");
282          }          }
283    
284          if (! -e "$BACKUP_DEST/$host/$dir") {          if (! -e "$BACKUP_DEST/$host/$dir") {
285                  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 $!";
286                  print "created dir for share $share, $BACKUP_DEST/$host/$dir...\n";                  xlog($share,"created dir for this share $BACKUP_DEST/$host/$dir...");
287          }          }
288    
289          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 299  sub snap_share {
299          my %file_atime;          my %file_atime;
300          my %file_mtime;          my %file_mtime;
301          #my %file_md5;          #my %file_md5;
302            %file_md5 = ();
303    
304          my @smb_files;          my @smb_files;
305          my %smb_size;          my %smb_size;
# Line 285  sub snap_share { Line 330  sub snap_share {
330                                  push @ignore,norm_dir("$d/$_");                                  push @ignore,norm_dir("$d/$_");
331                          }                          }
332                          close(I);                          close(I);
333  print STDERR "ignore: ",join("|",@ignore),"\n";  #print STDERR "ignore: ",join("|",@ignore),"\n";
334                          link "$real_bl/$d/.backupignore","$bc/$d/.backupignore" ||                          link "$real_bl/$d/.backupignore","$bc/$d/.backupignore" ||
335                                  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";
336                  }                  }
# Line 316  print STDERR "ignore: ",join("|",@ignore Line 361  print STDERR "ignore: ",join("|",@ignore
361                                  } elsif (-d $pf) {                                  } elsif (-d $pf) {
362                                          push @dirs,$pr;                                          push @dirs,$pr;
363                                  } else {                                  } else {
364                                          print STDERR "unknown type: $pf\n";                                          xlog($share,"not file or directory: $pf",0);
365                                  }                                  }
366                          } else {                          } else {
367                                  print STDERR "ignored: $pr\n";                                  xlog($share,"ignored: $pr");
368                          }                          }
369                  }                  }
370          }          }
371    
372          xlog($share,($#files+1)." files and ".($#dirs+1)." dirs on local disk before backup");          # local dir always include /
373            xlog($share,($#files+1)." files and ".($#dirs)." dirs on local disk before backup");
374    
375          # read smb filesystem          # read smb filesystem
376    
# Line 335  print STDERR "ignore: ",join("|",@ignore Line 381  print STDERR "ignore: ",join("|",@ignore
381    
382          $di = 0;          $di = 0;
383          while ($di <= $#smb_dirs) {          while ($di <= $#smb_dirs) {
384                  my $d=$smb_dirs[$di++];                  my $d=$smb_dirs[$di];
385                  my $pf = norm_dir($d,"smb:$share/");    # path full                  my $pf = norm_dir($d,"smb:$share/");    # path full
386                  my $D = $smb->opendir($pf) || warn "smb->opendir($pf): $!\n";                  my $D = $smb->opendir($pf);
387                    if (! $D) {
388                            xlog($share,"FATAL: $share [$pf] as $param{username}/$param{workgroup}: $!",0);
389                            # remove failing dir
390                            delete $smb_dirs[$di];
391                            return 0;                       # failed
392                    }
393                    $di++;
394    
395                  my @clutter = $smb->readdir_struct($D);                  my @clutter = $smb->readdir_struct($D);
396                  foreach my $item (@clutter) {                  foreach my $item (@clutter) {
# Line 355  print STDERR "ignore: ",join("|",@ignore Line 408  print STDERR "ignore: ",join("|",@ignore
408                                  } elsif ($item->[0] == main::SMBC_DIR) {                                  } elsif ($item->[0] == main::SMBC_DIR) {
409                                          push @smb_dirs,$pr;                                          push @smb_dirs,$pr;
410                                  } else {                                  } else {
411                                          print STDERR "unknown type: $pf\n";                                          xlog($share,"not file or directory [".$item->[0]."]: $pf",0);
412                                  }                                  }
413                          } else {                          } else {
414                                  print STDERR "smb ignored: $pr\n";                                  xlog($share,"smb ignored: $pr");
415                          }                          }
416                  }                  }
417          }          }
418    
419          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");
420    
421          # sync dirs          # sync dirs
422          my $lc = List::Compare->new(\@dirs, \@smb_dirs);          my $lc = List::Compare->new(\@dirs, \@smb_dirs);
# Line 395  print STDERR "ignore: ",join("|",@ignore Line 448  print STDERR "ignore: ",join("|",@ignore
448                                    
449                  foreach my $f (@_) {                  foreach my $f (@_) {
450  #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;  
                         }  
   
451                          my $md5 = Digest::MD5->new;                          my $md5 = Digest::MD5->new;
452    
453                          my $fd = $smb->open("$from/$f");                          my $fd = $smb->open("$from/$f");
454                          if (! $fd) {                          if (! $fd) {
455                                  print STDERR "can't open smb file $from/$f: $!\n";                                  xlog("WARNING","can't open smb file $from/$f: $!");
456                                    next;
457                            }
458    
459                            if (! open(F,"> $to/$f")) {
460                                    xlog("WARNING","can't open new file $to/$f: $!");
461                                  next;                                  next;
462                          }                          }
463    
# Line 478  print STDERR "ignore: ",join("|",@ignore Line 531  print STDERR "ignore: ",join("|",@ignore
531          # remove files          # remove files
532          foreach (sort @files2erase) {          foreach (sort @files2erase) {
533                  unlink "$bc/$_" || warn "unlink $_: $!\n";                  unlink "$bc/$_" || warn "unlink $_: $!\n";
534                    delete $file_md5{$_};
535          }          }
536    
537          # remove not needed dirs (after files)          # remove not needed dirs (after files)
# Line 490  print STDERR "ignore: ",join("|",@ignore Line 544  print STDERR "ignore: ",join("|",@ignore
544                  unlink "$bc/$_/.md5sum" if (-e "$bc/$_/.md5sum");                  unlink "$bc/$_/.md5sum" if (-e "$bc/$_/.md5sum");
545          }          }
546    
547            # erase stale entries in .md5sum
548            my @md5_files = keys %file_md5;
549            $lc = List::Compare->new(\@md5_files, \@smb_files);
550            foreach my $file ($lc->get_Lonly) {
551                    xlog("NOTICE","removing stale '$file' from .md5sum");
552                    delete $file_md5{$file};
553            }
554    
555          # create .md5sum          # create .md5sum
556          my $last_dir = '';          my $last_dir = '';
557          my $md5;          my $md5;
# Line 505  print STDERR "ignore: ",join("|",@ignore Line 567  print STDERR "ignore: ",join("|",@ignore
567                  }                  }
568                  print $md5 $file_md5{$f},"  $file\n";                  print $md5 $file_md5{$f},"  $file\n";
569          }          }
570          close($md5);          close($md5) if ($md5);
571    
572          # create leatest link          # create leatest link
573  #print "ln -s $bc $real_bl\n";  #print "ln -s $bc $real_bl\n";
574          if (-e $bl) {          if (-l $bl) {
575                  unlink $bl || warn "can't remove old latest symlink $bl: $!\n";                  unlink $bl || warn "can't remove old latest symlink $bl: $!\n";
576          }          }
577          symlink $bc,$bl || warn "can't create latest symlink $bl -> $bc: $!\n";          symlink $bc,$bl || warn "can't create latest symlink $bl -> $bc: $!\n";
578    
579          # FIX: sanity check -- remove for speedup          # FIX: sanity check -- remove for speedup
580          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);
581    
582          xlog($share,"backup completed...");          xlog($share,"backup completed...");
 }  
583    
584            return 1;
585    }
586  __END__  __END__
587  #-------------------------------------------------------------------------  #-------------------------------------------------------------------------
588    
# Line 530  psinib - Perl Snapshot Is Not Incrementa Line 593  psinib - Perl Snapshot Is Not Incrementa
593    
594  =head1 SYNOPSIS  =head1 SYNOPSIS
595    
596  ./psinib.pl  ./psinib.pl [OPTION]... [mount script]
597    
598  =head1 DESCRIPTION  =head1 DESCRIPTION
599    
600    Option can be one of more of following:
601    
602    =over 8
603    
604    =item C<--backupdest=dir>
605    
606    Specify backup destination directory (defaults is /data/
607    
608    =item C<--noping>
609    
610    Don't use ping to check if host is up (default is ti use tcp syn to cifs
611    port)
612    
613    =item C<--verbose -v>
614    
615    Increase verbosity level. Defailt is 1 which prints moderate amount of data
616    on STDOUT and STDERR.
617    
618    =item C<--quiet -q>
619    
620    Decrease verbosity level
621    
622    =back
623    
624  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
625  Winblowz) shares to central disk space. Central disk space is organized in  Winblowz) shares to central disk space. Central disk space is organized in
626  multiple directories named after:  multiple directories named after:
# Line 645  be renamed to I<YYYYMMDD.partial> and sn Line 732  be renamed to I<YYYYMMDD.partial> and sn
732  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
733  second-oldest directory, but this seemed like more correct approach).  second-oldest directory, but this seemed like more correct approach).
734    
735    =head2 I can't connect to any share
736    
737    Please verify that nmblookup (which is part of samba package) is in /bin or
738    /usr/bin. Also verify that nmblookup returns IP address for your server
739    using:
740    
741       $ nmblookup tvhouse
742       querying tvhouse on 192.168.34.255
743       192.168.34.30 tvhouse<00>
744    
745    If you don't get any output, your samba might not listen to correct interface
746    (see interfaces in smb.conf).
747    
748  =head1 AUTHOR  =head1 AUTHOR
749    
750  Dobrica Pavlinusic <dpavlin@rot13.org>  Dobrica Pavlinusic <dpavlin@rot13.org>
751    
752  L<http://www.rot13.org/~dpavlin/>  L<http:E<sol>E<sol>www.rot13.orgE<sol>~dpavlinE<sol>>
753    
754  =head1 LICENSE  =head1 LICENSE
755    

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

  ViewVC Help
Powered by ViewVC 1.1.26