--- psinib.pl 2003/10/26 12:55:56 1.16 +++ psinib.pl 2003/11/08 00:31:14 1.20 @@ -62,16 +62,56 @@ # taint path: nmblookup should be there! $ENV{'PATH'} = "/usr/bin:/bin"; -my $use_ping = 1; # deault: use ping to verify that host is up +my $use_ping = 1; # default: use syn tcp ping to verify that host is up +my $verbose = 1; # default verbosity level +my $quiet = 0; +my $email; my $result = GetOptions( "ping!" => \$use_ping, "backupdest!" => \$BACKUP_DEST, + "verbose+" => \$verbose, "quiet+" => \$quiet, + "email=s" => \$email, ); +$verbose -= $quiet; + my $mounts = shift @ARGV || 'mountscript'; # die "usage: $0 mountscript"; +my $basedir = $0; +$basedir =~ s,/?[^/]+$,,g; + +# default subject for e-mail messages +my @subjects = ('Backup needs your attention!'); +my $sub_nr = 0; +my $email_body; + +if ($email) { + # It will use (and require) Tie::File only if --email=foo@bar.com + # arguement is used! + use Tie::File; + tie @subjects, 'Tie::File', "$basedir/subjects.txt" || xlog("CONFIG","Can't find $basedir/subjects.txt... using default (only one)"); + chdir; # this will change directory to HOME + if (open(SN,".psinib.subject")) { + $sub_nr = ; + chomp($sub_nr); + close(SN); + } + $sub_nr++; + # skip comments in subjects.txt + while($subjects[$sub_nr] =~ m/^#/) { + $sub_nr++; + } + $sub_nr = 0 if (! $subjects[$sub_nr]); + + if (open(SN,"> .psinib.subject")) { + print SN "$sub_nr\n"; + close (SN); + } else { + xlog("CONFIG","Can't open .psinib.subject -- I can't cycle subjects..."); + }; +} my @in_backup; # shares which are backeduped this run @@ -145,7 +185,7 @@ $real_bl=readlink($bl) || die "can't read link $bl: $!"; $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/"); if (-l $bc && $real_bl eq $bc) { - print "$share allready backuped...\n"; + xlog($share,"allready backuped..."); $backup_ok++; next; } @@ -153,7 +193,7 @@ } - print "working on $share\n"; + xlog($share,"working on $share..."); # try to nmblookup IP $ip = get_ip($share) if (! $ip); @@ -169,7 +209,12 @@ } close(M); -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; +my $pcnt = ""; +$pcnt = "(".int($backup_ok*100/$total)." %)" if ($total > 0); +xlog("","$backup_ok backups completed of total $total this time".$pcnt); + +send_email(); 1; @@ -188,19 +233,40 @@ } } +# send e-mail with all messages +sub send_email { + return if (! $email || $email eq "" || !$email_body); + require Mail::Send; + my $msg = new Mail::Send; + $msg->to($email); + $msg->subject($subjects[$sub_nr]); + my $fn=$msg->open; + print $fn $email_body; + $fn->close; +} + # write entry to screen and log sub xlog { my $share = shift; my $t = strftime $LOG_TIME_FMT, localtime; my $m = shift || '[no log entry]'; - print STDERR $m,"\n"; + my $l = shift; + $l = 1 if (! defined $l); # default verbosity is 1 + if ($verbose >= $l) { + if (! $email) { + print STDERR $m,"\n"; + # don't e-mail mesages with verbosity < 1 + } elsif ($l < 1) { + $email_body .= $m."\n"; + } + } print L "$t $share\t$m\n"; } # dump warn and dies into log -BEGIN { $SIG{'__WARN__'} = sub { xlog('WARN',$_[0]) ; warn $_[0] } } -BEGIN { $SIG{'__DIE__'} = sub { xlog('DIE',$_[0]) ; die $_[0] } } +BEGIN { $SIG{'__WARN__'} = sub { xlog('WARN',$_[0],1) ; exit 1 } } +BEGIN { $SIG{'__DIE__'} = sub { xlog('DIE',$_[0],0) ; exit 1 } } # split share name to host, dir and currnet date dir @@ -213,7 +279,7 @@ $dir =~ s/^_+//; $dir =~ s/_+$//; } else { - print "Can't parse share $share into host and directory!\n"; + xlog($share,"Can't parse share $share into host and directory!",1); return; } return ($host,$dir,strftime $DIR_TIME_FMT, localtime); @@ -242,13 +308,19 @@ if (-l $bl) { $real_bl=readlink($bl) || die "can't read link $bl: $!"; $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/"); - } else { - print "no old backup, trying to find last backup, "; + if (! -e $real_bl) { + xlog($share,"latest link $bl -> $real_bl not valid, removing it"); + unlink $bl || die "can't remove link $bl: $!"; + undef $real_bl; + } + } + if (! $real_bl) { + xlog($share,"no old backup, trying to find last backup"); if (opendir(BL_DIR, "$BACKUP_DEST/$host/$dir")) { my @bl_dirs = sort grep { !/^\./ && -d "$BACKUP_DEST/$host/$dir/$_" } readdir(BL_DIR); closedir(BL_DIR); $real_bl=pop @bl_dirs; - print "using $real_bl as latest...\n"; + xlog($share,"using $real_bl as latest..."); $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/"); if ($real_bl eq $bc) { xlog($share,"latest from today (possible partial backup)"); @@ -256,12 +328,12 @@ $real_bl .= ".partial"; } } else { - print "this is first run...\n"; + xlog($share,"this is first run..."); } } if (-l $bc && $real_bl && $real_bl eq $bc) { - print "$share allready backuped...\n"; + xlog($share,"allready backuped..."); return 1; } @@ -269,12 +341,12 @@ if (! -e "$BACKUP_DEST/$host") { mkdir "$BACKUP_DEST/$host" || die "can't make dir for host $host, $BACKUP_DEST/$host: $!"; - print "created host directory $BACKUP_DEST/$host...\n"; + xlog($share,"created host directory $BACKUP_DEST/$host..."); } if (! -e "$BACKUP_DEST/$host/$dir") { mkdir "$BACKUP_DEST/$host/$dir" || die "can't make dir for share $share, $BACKUP_DEST/$host/$dir $!"; - print "created dir for share $share, $BACKUP_DEST/$host/$dir...\n"; + xlog($share,"created dir for this share $BACKUP_DEST/$host/$dir..."); } mkdir $bc || die "can't make dir for current backup $bc: $!"; @@ -352,10 +424,10 @@ } elsif (-d $pf) { push @dirs,$pr; } else { - print STDERR "not file or directory: $pf\n"; + xlog($share,"not file or directory: $pf",0); } } else { - print STDERR "ignored: $pr\n"; + xlog($share,"ignored: $pr"); } } } @@ -376,7 +448,7 @@ my $pf = norm_dir($d,"smb:$share/"); # path full my $D = $smb->opendir($pf); if (! $D) { - xlog($share,"FATAL: $share [$pf]: $!"); + xlog($share,"FATAL: $share [$pf] as $param{username}/$param{workgroup}: $!",0); # remove failing dir delete $smb_dirs[$di]; return 0; # failed @@ -399,10 +471,10 @@ } elsif ($item->[0] == main::SMBC_DIR) { push @smb_dirs,$pr; } else { - print STDERR "not file or directory [",$item->[0],"]: $pf\n"; + xlog($share,"not file or directory [".$item->[0]."]: $pf",0); } } else { - print STDERR "smb ignored: $pr\n"; + xlog($share,"smb ignored: $pr"); } } } @@ -584,10 +656,38 @@ =head1 SYNOPSIS -./psinib.pl +./psinib.pl [OPTION]... [mount script] =head1 DESCRIPTION +Option can be one of more of following: + +=over 8 + +=item C<--backupdest=dir> + +Specify backup destination directory (defaults is /data/ + +=item C<--noping> + +Don't use ping to check if host is up (default is ti use tcp syn to cifs +port) + +=item C<--verbose -v> + +Increase verbosity level. Defailt is 1 which prints moderate amount of data +on STDOUT and STDERR. + +=item C<--quiet -q> + +Decrease verbosity level + +=item C<--email=email@domain> + +Send e-mails instead of dumping errors to STDERR. Useful for cron jobs. + +=back + This script in current version support just backup of Samba (or Micro$oft Winblowz) shares to central disk space. Central disk space is organized in multiple directories named after: @@ -712,11 +812,17 @@ If you don't get any output, your samba might not listen to correct interface (see interfaces in smb.conf). +=head2 Aren't backups boring? + +No! If you have subjects.txt in same directory as C you can get +various funny subjects in your mail. They change over time as long as you +ignore your backup. + =head1 AUTHOR Dobrica Pavlinusic -L +LEwww.rot13.orgE~dpavlinE> =head1 LICENSE