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 2.0.0_CVS, released 3 Feb 2003.
36 # See http://backuppc.sourceforge.net.
38 #========================================================================
41 use lib "/usr/local/BackupPC/lib";
43 use BackupPC::FileZIO;
48 use vars qw($Lang $TopDir $BinDir %Conf);
50 die("BackupPC::Lib->new failed\n") if ( !(my $bpc = BackupPC::Lib->new) );
51 $TopDir = $bpc->TopDir();
52 $BinDir = $bpc->BinDir();
58 use vars qw(%UserEmailInfo);
59 do "$TopDir/log/UserEmailInfo.pl";
64 print("usage: $0 [-t]\n");
68 my $err = $bpc->ServerConnect($Conf{ServerHost}, $Conf{ServerPort});
70 print("Can't connect to server ($err)\n");
73 my $reply = $bpc->ServerMesg("status hosts");
74 $reply = $1 if ( $reply =~ /(.*)/s );
75 my(%Status, %Info, %Jobs, @BgQueue, @UserQueue, @CmdQueue);
78 ###########################################################################
79 # Generate sysadmin warning messages
80 ###########################################################################
84 foreach my $host ( sort(keys(%Status)) ) {
85 next if ( $Status{$host}{reason} ne "backup failed"
86 || $Status{$host}{error} =~ /^lost network connection to host/ );
87 push(@badHosts, "$host ($Status{$host}{error})");
90 my $badHosts = join("\n - ", sort(@badHosts));
92 The following hosts had an error that is probably caused by a
93 misconfiguration. Please fix these hosts:
100 # Report if we skipped backups because the disk was too full
102 if ( $Info{DUDailySkipHostCntPrev} > 0 ) {
103 my $n = $Info{DUDailySkipHostCntPrev};
104 my $m = $Conf{DfMaxUsagePct};
106 Yesterday $n hosts were skipped because the file system containing
107 $TopDir was too full. The threshold in the
108 configuration file is $m%, while yesterday the file system was
109 up to $Info{DUDailyMaxPrev}% full. Please find more space on the file system,
110 or reduce the number of full or incremental backups that we keep.
116 # Check for bogus directories (probably PCs that are no longer
117 # on the backup list)
119 my $d = DirHandle->new("$TopDir/pc") or die("Can't read $TopDir/pc: $!");
121 my @files = $d->read;
123 foreach my $host ( @files ) {
124 next if ( $host eq "." || $host eq ".." || defined($Status{$host}) );
125 push(@oldDirs, "$TopDir/pc/$host");
128 my $oldDirs = join("\n - ", sort(@oldDirs));
130 The following directories are bogus and are not being used by
131 BackupPC. This typically happens when PCs are removed from the
132 backup list. If you don't need any old backups from these PCs you
133 should remove these directories. If there are machines on this
134 list that should be backed up then there is a problem with the
141 if ( $mesg ne "" && $Conf{EMailAdminUserName} ne "" ) {
143 To: $Conf{EMailAdminUserName}
144 Subject: BackupPC administrative attention needed
150 print("#" x 75, "\n");
157 ###########################################################################
158 # Generate per-host warning messages sent to each user
159 ###########################################################################
160 my $Hosts = $bpc->HostInfoRead();
162 foreach my $host ( sort(keys(%Status)) ) {
163 next if ( $Hosts->{$host}{user} eq "" );
165 # read any per-PC config settings (allowing per-PC email settings)
167 $bpc->ConfigRead($host);
168 %Conf = $bpc->Conf();
169 my $user = $Hosts->{$host}{user};
170 next if ( time - $UserEmailInfo{$user}{lastTime}
171 < $Conf{EMailNotifyMinDays} * 24*3600 );
172 my @Backups = $bpc->BackupInfoRead($host);
173 my $numBackups = @Backups;
174 if ( $numBackups == 0 ) {
175 my $subj = defined($Conf{EMailNoBackupEverSubj})
176 ? $Conf{EMailNoBackupEverSubj}
177 : $Lang->{EMailNoBackupEverSubj};
178 my $mesg = defined($Conf{EMailNoBackupEverMesg})
179 ? $Conf{EMailNoBackupEverMesg}
180 : $Lang->{EMailNoBackupEverMesg};
181 sendUserEmail($user, $host, $mesg, $subj, {
182 userName => user2name($user)
183 }) if ( !defined($Jobs{$host}) );
186 my $last = my $lastFull = my $lastIncr = 0;
187 my $lastGoodOutlook = 0;
189 my $numBadOutlook = 0;
190 for ( my $i = 0 ; $i < @Backups ; $i++ ) {
192 $lastNum = $Backups[$i]{num} if ( $lastNum < $Backups[$i]{num} );
193 if ( $Backups[$i]{type} eq "full" ) {
194 $lastFull = $Backups[$i]{startTime}
195 if ( $lastFull < $Backups[$i]{startTime} );
197 $lastIncr = $Backups[$i]{startTime}
198 if ( $lastIncr < $Backups[$i]{startTime} );
200 $last = $Backups[$i]{startTime}
201 if ( $last < $Backups[$i]{startTime} );
203 my $file = "$TopDir/pc/$host/SmbLOG.$Backups[$i]{num}";
206 $file = "$TopDir/pc/$host/XferLOG.$Backups[$i]{num}";
209 $file = "$TopDir/pc/$host/SmbLOG.$Backups[$i]{num}.z";
210 $file = "$TopDir/pc/$host/XferLOG.$Backups[$i]{num}.z"
214 next if ( !defined($fh = BackupPC::FileZIO->open($file, 0, $comp)) );
216 my $s = $fh->readLine();
217 last if ( $s eq "" );
218 if ( $s =~ /^Error reading file.*\.pst : ERRDOS - ERRlock/
219 || $s =~ /^Error reading file.*\.pst\. Got 0 bytes/ ) {
225 $numBadOutlook += $badOutlook;
226 if ( !$badOutlook ) {
227 $lastGoodOutlook = $Backups[$i]{startTime}
228 if ( $lastGoodOutlook < $Backups[$i]{startTime} );
231 if ( time - $last > $Conf{EMailNotifyOldBackupDays} * 24*3600 ) {
232 my $subj = defined($Conf{EMailNoBackupRecentSubj})
233 ? $Conf{EMailNoBackupRecentSubj}
234 : $Lang->{EMailNoBackupRecentSubj};
235 my $mesg = defined($Conf{EMailNoBackupRecentMesg})
236 ? $Conf{EMailNoBackupRecentMesg}
237 : $Lang->{EMailNoBackupRecentMesg};
238 my $firstTime = sprintf("%.1f",
239 (time - $Backups[0]{startTime}) / (24*3600));
240 my $days = sprintf("%.1f", (time - $last) / (24 * 3600));
241 sendUserEmail($user, $host, $mesg, $subj, {
242 firstTime => $firstTime,
244 userName => user2name($user),
245 numBackups => $numBackups,
246 }) if ( !defined($Jobs{$host}) );
249 if ( $numBadOutlook > 0
250 && time - $lastGoodOutlook > $Conf{EMailNotifyOldOutlookDays}
253 if ( $lastGoodOutlook == 0 ) {
254 $howLong = eval("qq{$Lang->{howLong_not_been_backed_up}}");
256 $days = sprintf("%.1f", (time - $lastGoodOutlook) / (24*3600));
257 $howLong = eval("qq{$Lang->{howLong_not_been_backed_up_for_days_days}}");
259 my $subj = defined($Conf{EMailOutlookBackupSubj})
260 ? $Conf{EMailOutlookBackupSubj}
261 : $Lang->{EMailOutlookBackupSubj};
262 my $mesg = defined($Conf{EMailOutlookBackupMesg})
263 ? $Conf{EMailOutlookBackupMesg}
264 : $Lang->{EMailOutlookBackupMesg};
265 my $firstTime = sprintf("%.1f",
266 (time - $Backups[0]{startTime}) / (24*3600));
267 my $lastTime = sprintf("%.1f",
268 (time - $Backups[$#Backups]{startTime}) / (24*3600));
269 sendUserEmail($user, $host, $mesg, $subj, {
271 firstTime => $firstTime,
272 lastTime => $lastTime,
273 numBackups => $numBackups,
274 userName => user2name($user),
276 serverHost => $Conf{ServerHost},
277 }) if ( !defined($Jobs{$host}) );
281 $Data::Dumper::Indent = 1;
282 my $dumpStr = Data::Dumper->Dump(
284 [qw(*UserEmailInfo)]);
285 if ( open(HOST, ">", "$TopDir/log/UserEmailInfo.pl") ) {
286 print(HOST $dumpStr);
294 my($name) = (getpwnam($user))[6];
296 $name = $user if ( $name eq "" );
302 my($user, $host, $mesg, $subj, $vars) = @_;
303 $vars->{user} = $user;
304 $vars->{host} = $host;
305 $vars->{domain} = $Conf{EMailUserDestDomain};
306 $vars->{CgiURL} = $Conf{CgiURL};
307 $subj =~ s/\$(\w+)/defined($vars->{$1}) ? $vars->{$1} : "\$$1"/eg;
308 $vars->{subj} = $subj;
309 $mesg =~ s/\$(\w+)/defined($vars->{$1}) ? $vars->{$1} : "\$$1"/eg;
311 print("#" x 75, "\n");
316 $UserEmailInfo{$user}{lastTime} = time;
317 $UserEmailInfo{$user}{lastSubj} = $subj;
318 $UserEmailInfo{$user}{lastHost} = $host;
324 my($from) = $Conf{EMailFromUserName};
327 $from = "-f $from" if ( $from ne "" );
328 if ( !open(MAIL, "|$Conf{SendmailPath} -t $from") ) {
329 printf("Can't run sendmail ($Conf{SendmailPath}): $!\n");