/[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.13 by dpavlin, Sun Oct 12 17:44:21 2003 UTC revision 1.22 by dpavlin, Mon Mar 1 19:38:16 2004 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    
# Line 58  my $c = 0; Line 62  my $c = 0;
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    my $email;
69    
70    my $result = GetOptions(
71            "ping!" => \$use_ping, "backupdest!" => \$BACKUP_DEST,
72            "verbose+" => \$verbose, "quiet+" => \$quiet,
73            "email=s" => \$email,
74    );
75    
76    $verbose -= $quiet;
77    
78  my $mounts = shift @ARGV ||  my $mounts = shift @ARGV ||
79          'mountscript';          'mountscript';
80  #       die "usage: $0 mountscript";  #       die "usage: $0 mountscript";
81    
82    my $basedir = $0;
83    $basedir =~ s,/?[^/]+$,,g;
84    
85    # default subject for e-mail messages
86    my @subjects = ('Backup needs your attention!');
87    my $sub_nr = 0;
88    my $email_body;
89    
90    my $home_dir=$ENV{'HOME'};
91    $home_dir = '/tmp' if (! -w $home_dir);
92    
93    if ($email) {
94            # It will use (and require) Tie::File only if --email=foo@bar.com
95            # arguement is used!
96            use Tie::File;
97            tie @subjects, 'Tie::File', "$basedir/subjects.txt" || xlog("CONFIG","Can't find $basedir/subjects.txt... using default (only one)");
98            chdir; # this will change directory to HOME
99            if (open(SN,"$home_dir/.psinib.subject")) {
100                    $sub_nr = <SN>;
101                    chomp($sub_nr);
102                    close(SN);
103            }
104            $sub_nr++;
105            # skip comments in subjects.txt
106            while($subjects[$sub_nr] && $subjects[$sub_nr] =~ m/^#/) {
107                    $sub_nr++;
108            }
109            $sub_nr = 0 if (! $subjects[$sub_nr]);
110    
111            if (open(SN,"> $home_dir/.psinib.subject")) {
112                    print SN "$sub_nr\n";
113                    close (SN);
114            } else {
115                    xlog("CONFIG","Can't open $home_dir/.psinib.subject -- I can't cycle subjects...");
116            };
117    }
118    
119  my @in_backup;  # shares which are backeduped this run  my @in_backup;  # shares which are backeduped this run
120    
121  my $p = new Net::Ping->new("tcp", 2);  # init Net::Ping object
122  # ping will try tcp connect to netbios-ssn (139)  my $ping;
123  $p->{port_num} = getservbyname("netbios-ssn", "tcp");  if ($use_ping) {
124            $ping = new Net::Ping->new("syn", 2);
125            # ping will try tcp connect to netbios-ssn (139)
126            $ping->{port_num} = getservbyname("netbios-ssn", "tcp");
127    }
128    
129    # do syn ping to cifs port
130    sub host_up {
131            my $ping = shift || return;
132            my $host_ip = shift || xlog("host_up didn't get IP");
133            my $timeout = shift;
134            return 1 if (! $use_ping);
135    
136            $ping->ping($host_ip,$timeout);
137            my $return = 0;
138    
139            while (my ($host,$rtt,$ip) = $ping->ack) {
140                    xlog("","HOST: $host [$ip] ACKed in $rtt seconds");
141                    $return = 1 if ($ip eq $host_ip);
142            }
143            return $return;
144    }
145    
146  my $backup_ok = 0;  my $backup_ok = 0;
147    
# Line 114  while(<M>) { Line 188  while(<M>) {
188                  $real_bl=readlink($bl) || die "can't read link $bl: $!";                  $real_bl=readlink($bl) || die "can't read link $bl: $!";
189                  $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 "/");
190                  if (-l $bc && $real_bl eq $bc) {                  if (-l $bc && $real_bl eq $bc) {
191                          print "$share allready backuped...\n";                          xlog($share,"allready backuped...");
192                          $backup_ok++;                          $backup_ok++;
193                          next;                          next;
194                  }                  }
# Line 122  while(<M>) { Line 196  while(<M>) {
196          }          }
197    
198    
199          print "working on $share\n";          xlog($share,"working on $share...");
200    
201          # try to nmblookup IP          # try to nmblookup IP
202          $ip = get_ip($share) if (! $ip);          $ip = get_ip($share) if (! $ip);
203    
204          if ($ip) {          if ($ip) {
205                  xlog($share,"IP is $ip");                  xlog($share,"IP is $ip");
206                  if ($p->ping($ip)) {                  if (host_up($ping, $ip,$PING_TIMEOUT)) {
207                          if (snap_share($share,$user,$passwd,$workgroup)) {                          if (snap_share($share,$user,$passwd,$workgroup)) {
208                                  $backup_ok++;                                  $backup_ok++;
209                          }                          }
# Line 138  while(<M>) { Line 212  while(<M>) {
212  }  }
213  close(M);  close(M);
214    
215  xlog("","$backup_ok backups completed of total ".($#in_backup+1)." this time (".int($backup_ok*100/($#in_backup+1))." %)");  my $total = ($#in_backup + 1) || 0;
216    my $pcnt = "";
217    $pcnt = "(".int($backup_ok*100/$total)." %)" if ($total > 0);
218    xlog("","$backup_ok backups completed of total $total this time".$pcnt);
219    
220    send_email();
221    
222  1;  1;
223    
# Line 157  sub get_ip { Line 236  sub get_ip {
236          }          }
237  }  }
238    
239    # send e-mail with all messages
240    sub send_email {
241            return if (! $email || $email eq "" || !$email_body);
242            require Mail::Send;
243            my $msg = new Mail::Send;
244            $msg->to($email);
245            $msg->subject($subjects[$sub_nr]);
246            my $fn=$msg->open;
247            print $fn $email_body;
248            $fn->close;
249    }
250            
251    
252  # write entry to screen and log  # write entry to screen and log
253  sub xlog {  sub xlog {
254          my $share = shift;          my $share = shift;
255          my $t = strftime $LOG_TIME_FMT, localtime;          my $t = strftime $LOG_TIME_FMT, localtime;
256          my $m = shift || '[no log entry]';          my $m = shift || '[no log entry]';
257          print STDERR $m,"\n";          my $l = shift;
258            $l = 1 if (! defined $l);       # default verbosity is 1
259            if ($verbose >= $l) {
260                    if (! $email) {
261                            print STDERR $m,"\n";
262                    # don't e-mail mesages with verbosity < 1
263                    } elsif ($l < 1) {
264                            $email_body .= $m."\n";
265                    }
266            }
267          print L "$t $share\t$m\n";          print L "$t $share\t$m\n";
268  }  }
269    
270  # dump warn and dies into log  # dump warn and dies into log
271  BEGIN { $SIG{'__WARN__'} = sub { xlog('WARN',$_[0]) ; warn $_[0] } }  BEGIN { $SIG{'__WARN__'} = sub { xlog('WARN',$_[0],1) ; exit 1 } }
272  BEGIN { $SIG{'__DIE__'} = sub { xlog('DIE',$_[0]) ; die $_[0] } }  BEGIN { $SIG{'__DIE__'} = sub { xlog('DIE',$_[0],0) ; exit 1 } }
273    
274    
275  # split share name to host, dir and currnet date dir  # split share name to host, dir and currnet date dir
# Line 182  sub share2host_dir { Line 282  sub share2host_dir {
282                  $dir =~ s/^_+//;                  $dir =~ s/^_+//;
283                  $dir =~ s/_+$//;                  $dir =~ s/_+$//;
284          } else {          } else {
285                  print "Can't parse share $share into host and directory!\n";                  xlog($share,"Can't parse share $share into host and directory!",1);
286                  return;                  return;
287          }          }
288          return ($host,$dir,strftime $DIR_TIME_FMT, localtime);          return ($host,$dir,strftime $DIR_TIME_FMT, localtime);
# Line 211  sub snap_share { Line 311  sub snap_share {
311          if (-l $bl) {          if (-l $bl) {
312                  $real_bl=readlink($bl) || die "can't read link $bl: $!";                  $real_bl=readlink($bl) || die "can't read link $bl: $!";
313                  $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 "/");
314          } else {                  if (! -e $real_bl) {
315                  print "no old backup, trying to find last backup, ";                          xlog($share,"latest link $bl -> $real_bl not valid, removing it");
316                            unlink $bl || die "can't remove link $bl: $!";
317                            undef $real_bl;
318                    }
319            }
320            if (! $real_bl) {
321                    xlog($share,"no old backup, trying to find last backup");
322                  if (opendir(BL_DIR, "$BACKUP_DEST/$host/$dir")) {                  if (opendir(BL_DIR, "$BACKUP_DEST/$host/$dir")) {
323                          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);
324                          closedir(BL_DIR);                          closedir(BL_DIR);
325                          $real_bl=pop @bl_dirs;                          $real_bl=pop @bl_dirs;
326                          print "using $real_bl as latest...\n";                          xlog($share,"using $real_bl as latest...");
327                          $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 "/");
328                          if ($real_bl eq $bc) {                          if ($real_bl eq $bc) {
329                                  xlog($share,"latest from today (possible partial backup)");                                  xlog($share,"latest from today (possible partial backup)");
# Line 225  sub snap_share { Line 331  sub snap_share {
331                                  $real_bl .= ".partial";                                  $real_bl .= ".partial";
332                          }                          }
333                  } else {                  } else {
334                          print "this is first run...\n";                          xlog($share,"this is first run...");
335                  }                  }
336          }          }
337    
338          if (-l $bc && $real_bl && $real_bl eq $bc) {          if (-l $bc && $real_bl && $real_bl eq $bc) {
339                  print "$share allready backuped...\n";                  xlog($share,"allready backuped...");
340                  return 1;                  return 1;
341          }          }
342    
# Line 238  sub snap_share { Line 344  sub snap_share {
344    
345          if (! -e "$BACKUP_DEST/$host") {          if (! -e "$BACKUP_DEST/$host") {
346                  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: $!";
347                  print "created host directory $BACKUP_DEST/$host...\n";                  xlog($share,"created host directory $BACKUP_DEST/$host...");
348          }          }
349    
350          if (! -e "$BACKUP_DEST/$host/$dir") {          if (! -e "$BACKUP_DEST/$host/$dir") {
351                  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 $!";
352                  print "created dir for share $share, $BACKUP_DEST/$host/$dir...\n";                  xlog($share,"created dir for this share $BACKUP_DEST/$host/$dir...");
353          }          }
354    
355          mkdir $bc || die "can't make dir for current backup $bc: $!";          mkdir $bc || die "can't make dir for current backup $bc: $!";
# Line 321  sub snap_share { Line 427  sub snap_share {
427                                  } elsif (-d $pf) {                                  } elsif (-d $pf) {
428                                          push @dirs,$pr;                                          push @dirs,$pr;
429                                  } else {                                  } else {
430                                          print STDERR "not file or directory: $pf\n";                                          xlog($share,"not file or directory: $pf",0);
431                                  }                                  }
432                          } else {                          } else {
433                                  print STDERR "ignored: $pr\n";                                  xlog($share,"ignored: $pr");
434                          }                          }
435                  }                  }
436          }          }
# Line 345  sub snap_share { Line 451  sub snap_share {
451                  my $pf = norm_dir($d,"smb:$share/");    # path full                  my $pf = norm_dir($d,"smb:$share/");    # path full
452                  my $D = $smb->opendir($pf);                  my $D = $smb->opendir($pf);
453                  if (! $D) {                  if (! $D) {
454                          xlog($share,"FATAL: $share [$pf]: $!");                          xlog($share,"FATAL: $share [$pf] as $param{username}/$param{workgroup}: $!",0);
455                          # remove failing dir                          # remove failing dir
456                          delete $smb_dirs[$di];                          delete $smb_dirs[$di];
457                          return 0;                       # failed                          return 0;                       # failed
# Line 368  sub snap_share { Line 474  sub snap_share {
474                                  } elsif ($item->[0] == main::SMBC_DIR) {                                  } elsif ($item->[0] == main::SMBC_DIR) {
475                                          push @smb_dirs,$pr;                                          push @smb_dirs,$pr;
476                                  } else {                                  } else {
477                                          print STDERR "not file or directory [",$item->[0],"]: $pf\n";                                          xlog($share,"not file or directory [".$item->[0]."]: $pf",0);
478                                  }                                  }
479                          } else {                          } else {
480                                  print STDERR "smb ignored: $pr\n";                                  xlog($share,"smb ignored: $pr");
481                          }                          }
482                  }                  }
483          }          }
# Line 553  psinib - Perl Snapshot Is Not Incrementa Line 659  psinib - Perl Snapshot Is Not Incrementa
659    
660  =head1 SYNOPSIS  =head1 SYNOPSIS
661    
662  ./psinib.pl  ./psinib.pl [OPTION]... [mount script]
663    
664  =head1 DESCRIPTION  =head1 DESCRIPTION
665    
666    Option can be one of more of following:
667    
668    =over 8
669    
670    =item C<--backupdest=dir>
671    
672    Specify backup destination directory (defaults is /data/
673    
674    =item C<--noping>
675    
676    Don't use ping to check if host is up (default is ti use tcp syn to cifs
677    port)
678    
679    =item C<--verbose -v>
680    
681    Increase verbosity level. Defailt is 1 which prints moderate amount of data
682    on STDOUT and STDERR.
683    
684    =item C<--quiet -q>
685    
686    Decrease verbosity level
687    
688    =item C<--email=email@domain>
689    
690    Send e-mails instead of dumping errors to STDERR. Useful for cron jobs.
691    
692    =back
693    
694  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
695  Winblowz) shares to central disk space. Central disk space is organized in  Winblowz) shares to central disk space. Central disk space is organized in
696  multiple directories named after:  multiple directories named after:
# Line 668  be renamed to I<YYYYMMDD.partial> and sn Line 802  be renamed to I<YYYYMMDD.partial> and sn
802  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
803  second-oldest directory, but this seemed like more correct approach).  second-oldest directory, but this seemed like more correct approach).
804    
805    =head2 I can't connect to any share
806    
807    Please verify that nmblookup (which is part of samba package) is in /bin or
808    /usr/bin. Also verify that nmblookup returns IP address for your server
809    using:
810    
811       $ nmblookup tvhouse
812       querying tvhouse on 192.168.34.255
813       192.168.34.30 tvhouse<00>
814    
815    If you don't get any output, your samba might not listen to correct interface
816    (see interfaces in smb.conf).
817    
818    =head2 Aren't backups boring?
819    
820    No! If you have subjects.txt in same directory as C<psinib.pl> you can get
821    various funny subjects in your mail. They change over time as long as you
822    ignore your backup.
823    
824  =head1 AUTHOR  =head1 AUTHOR
825    
826  Dobrica Pavlinusic <dpavlin@rot13.org>  Dobrica Pavlinusic <dpavlin@rot13.org>
827    
828  L<http://www.rot13.org/~dpavlin/>  L<http:E<sol>E<sol>www.rot13.orgE<sol>~dpavlinE<sol>>
829    
830  =head1 LICENSE  =head1 LICENSE
831    

Legend:
Removed from v.1.13  
changed lines
  Added in v.1.22

  ViewVC Help
Powered by ViewVC 1.1.26