2 #============================================================= -*-perl-*-
4 # BackupPC_sendEmail: send status emails to users and admins
8 # BackupPC_sendEmail: send status emails to users and admins.
9 # BackupPC_sendEmail is run by BackupPC_nightly, so it runs
13 # Craig Barratt <cbarratt@users.sourceforge.net>
16 # Copyright (C) 2001 Craig Barratt
18 # This program is free software; you can redistribute it and/or modify
19 # it under the terms of the GNU General Public License as published by
20 # the Free Software Foundation; either version 2 of the License, or
21 # (at your option) any later version.
23 # This program is distributed in the hope that it will be useful,
24 # but WITHOUT ANY WARRANTY; without even the implied warranty of
25 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 # GNU General Public License for more details.
28 # You should have received a copy of the GNU General Public License
29 # along with this program; if not, write to the Free Software
30 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #========================================================================
34 # Version 1.5.0, released 2 Aug 2002.
36 # See http://backuppc.sourceforge.net.
38 #========================================================================
41 use lib "__INSTALLDIR__/lib";
43 use BackupPC::FileZIO;
49 die("BackupPC::Lib->new failed\n") if ( !(my $bpc = BackupPC::Lib->new) );
50 my $TopDir = $bpc->TopDir();
51 my $BinDir = $bpc->BinDir();
52 my %Conf = $bpc->Conf();
56 use vars qw(%UserEmailInfo);
57 do "$TopDir/log/UserEmailInfo.pl";
62 print("usage: $0 [-t]\n");
66 my $err = $bpc->ServerConnect($Conf{ServerHost}, $Conf{ServerPort});
68 print("Can't connect to server ($err)\n");
71 my $reply = $bpc->ServerMesg("status hosts");
72 $reply = $1 if ( $reply =~ /(.*)/s );
73 my(%Status, %Info, %Jobs, @BgQueue, @UserQueue, @CmdQueue);
76 ###########################################################################
77 # Generate sysadmin warning messages
78 ###########################################################################
82 foreach my $host ( sort(keys(%Status)) ) {
83 next if ( $Status{$host}{reason} ne "backup failed"
84 || $Status{$host}{error} =~ /^lost network connection to host/ );
85 push(@badHosts, "$host ($Status{$host}{error})");
88 my $badHosts = join("\n - ", sort(@badHosts));
90 The following hosts had an error that is probably caused by a
91 misconfiguration. Please fix these hosts:
98 # Report if we skipped backups because the disk was too full
100 if ( $Info{DUDailySkipHostCntPrev} > 0 ) {
101 my $n = $Info{DUDailySkipHostCntPrev};
102 my $m = $Conf{DfMaxUsagePct};
104 Yesterday $n hosts were skipped because the file system containing
105 $TopDir was too full. The threshold in the
106 configuration file is $m%, while yesterday the file system was
107 up to $Info{DUDailyMaxPrev}% full. Please find more space on the file system,
108 or reduce the number of full or incremental backups that we keep.
114 # Check for bogus directories (probably PCs that are no longer
115 # on the backup list)
117 my $d = DirHandle->new("$TopDir/pc") or die("Can't read $TopDir/pc: $!");
119 my @files = $d->read;
121 foreach my $host ( @files ) {
122 next if ( $host eq "." || $host eq ".." || defined($Status{$host}) );
123 push(@oldDirs, "$TopDir/pc/$host");
126 my $oldDirs = join("\n - ", sort(@oldDirs));
128 The following directories are bogus and are not being used by
129 BackupPC. This typically happens when PCs are removed from the
130 backup list. If you don't need any old backups from these PCs you
131 should remove these directories. If there are machines on this
132 list that should be backed up then there is a problem with the
139 if ( $mesg ne "" && $Conf{EMailAdminUserName} ne "" ) {
141 To: $Conf{EMailAdminUserName}
142 Subject: BackupPC administrative attention needed
148 print("#" x 75, "\n");
155 ###########################################################################
156 # Generate per-host warning messages sent to each user
157 ###########################################################################
158 my $Hosts = $bpc->HostInfoRead();
160 foreach my $host ( sort(keys(%Status)) ) {
161 next if ( $Hosts->{$host}{user} eq "" );
163 # read any per-PC config settings (allowing per-PC email settings)
165 $bpc->ConfigRead($host);
166 %Conf = $bpc->Conf();
167 my $user = $Hosts->{$host}{user};
168 next if ( time - $UserEmailInfo{$user}{lastTime}
169 < $Conf{EMailNotifyMinDays} * 24*3600 );
170 my @Backups = $bpc->BackupInfoRead($host);
171 my $numBackups = @Backups;
172 if ( $numBackups == 0 ) {
173 my $subj = "BackupPC: no backups of $host have succeeded";
174 sendUserEmail($user, $host, $Conf{EMailNoBackupEverMesg}, $subj, {
175 userName => user2name($user)
176 }) if ( !defined($Jobs{$host}) );
179 my $last = my $lastFull = my $lastIncr = 0;
180 my $lastGoodOutlook = 0;
182 my $numBadOutlook = 0;
183 for ( my $i = 0 ; $i < @Backups ; $i++ ) {
185 $lastNum = $Backups[$i]{num} if ( $lastNum < $Backups[$i]{num} );
186 if ( $Backups[$i]{type} eq "full" ) {
187 $lastFull = $Backups[$i]{startTime}
188 if ( $lastFull < $Backups[$i]{startTime} );
190 $lastIncr = $Backups[$i]{startTime}
191 if ( $lastIncr < $Backups[$i]{startTime} );
193 $last = $Backups[$i]{startTime}
194 if ( $last < $Backups[$i]{startTime} );
196 my $file = "$TopDir/pc/$host/SmbLOG.$Backups[$i]{num}";
199 $file = "$TopDir/pc/$host/XferLOG.$Backups[$i]{num}";
202 $file = "$TopDir/pc/$host/SmbLOG.$Backups[$i]{num}.z";
203 $file = "$TopDir/pc/$host/XferLOG.$Backups[$i]{num}.z"
207 next if ( !defined($fh = BackupPC::FileZIO->open($file, 0, $comp)) );
209 my $s = $fh->readLine();
210 last if ( $s eq "" );
211 if ( $s =~ /^Error reading file.*\.pst : ERRDOS - ERRlock/
212 || $s =~ /^Error reading file.*\.pst\. Got 0 bytes/ ) {
218 $numBadOutlook += $badOutlook;
219 if ( !$badOutlook ) {
220 $lastGoodOutlook = $Backups[$i]{startTime}
221 if ( $lastGoodOutlook < $Backups[$i]{startTime} );
224 if ( time - $last > $Conf{EMailNotifyOldBackupDays} * 24*3600 ) {
225 my $subj = "BackupPC: no recent backups on $host";
226 my $firstTime = sprintf("%.1f",
227 (time - $Backups[0]{startTime}) / (24*3600));
228 my $days = sprintf("%.1f", (time - $last) / (24 * 3600));
229 sendUserEmail($user, $host, $Conf{EMailNoBackupRecentMesg}, $subj, {
230 firstTime => $firstTime,
232 userName => user2name($user),
233 numBackups => $numBackups,
234 }) if ( !defined($Jobs{$host}) );
237 if ( $numBadOutlook > 0
238 && time - $lastGoodOutlook > $Conf{EMailNotifyOldOutlookDays}
241 if ( $lastGoodOutlook == 0 ) {
242 $howLong = "not been backed up successfully";
244 $days = sprintf("%.1f", (time - $lastGoodOutlook) / (24*3600));
245 $howLong = "not been backed up for $days days";
247 my $subj = "BackupPC: Outlook files on $host need to be backed up";
248 my $firstTime = sprintf("%.1f",
249 (time - $Backups[0]{startTime}) / (24*3600));
250 my $lastTime = sprintf("%.1f",
251 (time - $Backups[$#Backups]{startTime}) / (24*3600));
252 sendUserEmail($user, $host, $Conf{EMailOutlookBackupMesg}, $subj, {
253 firstTime => $firstTime,
254 lastTime => $lastTime,
255 numBackups => $numBackups,
256 userName => user2name($user),
258 }) if ( !defined($Jobs{$host}) );
262 $Data::Dumper::Indent = 1;
263 my $dumpStr = Data::Dumper->Dump(
265 [qw(*UserEmailInfo)]);
266 if ( open(HOST, ">$TopDir/log/UserEmailInfo.pl") ) {
267 print(HOST $dumpStr);
275 my($name) = (getpwnam($user))[6];
277 $name = $user if ( $name eq "" );
283 my($user, $host, $mesg, $subj, $vars) = @_;
284 $vars->{user} = $user;
285 $vars->{host} = $host;
286 $vars->{subj} = $subj;
287 $mesg =~ s/\$(\w+)/defined($vars->{$1}) ? $vars->{$1} : \$$1/eg;
289 print("#" x 75, "\n");
294 $UserEmailInfo{$user}{lastTime} = time;
295 $UserEmailInfo{$user}{lastSubj} = $subj;
296 $UserEmailInfo{$user}{lastHost} = $host;
302 my($from) = $Conf{EMailFromUserName};
305 $from = "-f $from" if ( $from ne "" );
306 if ( !open(MAIL, "|$Conf{SendmailPath} -t $from") ) {
307 printf("Can't run sendmail ($Conf{SendmailPath}): $!\n");