2 #============================================================= -*-perl-*-
4 # BackupPC_nightly: Nightly cleanup & statistics script.
7 # BackupPC_nightly performs several administrative tasks:
9 # - monthly aging of per-PC log files
11 # - pruning files from pool no longer used (ie: those with only one
14 # - sending email to users and administrators.
17 # Craig Barratt <cbarratt@users.sourceforge.net>
20 # Copyright (C) 2001-2003 Craig Barratt
22 # This program is free software; you can redistribute it and/or modify
23 # it under the terms of the GNU General Public License as published by
24 # the Free Software Foundation; either version 2 of the License, or
25 # (at your option) any later version.
27 # This program is distributed in the hope that it will be useful,
28 # but WITHOUT ANY WARRANTY; without even the implied warranty of
29 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 # GNU General Public License for more details.
32 # You should have received a copy of the GNU General Public License
33 # along with this program; if not, write to the Free Software
34 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
36 #========================================================================
38 # Version 2.1.0_CVS, released 8 Feb 2004.
40 # See http://backuppc.sourceforge.net.
42 #========================================================================
46 use lib "/usr/local/BackupPC/lib";
48 use BackupPC::FileZIO;
54 die("BackupPC::Lib->new failed\n") if ( !(my $bpc = BackupPC::Lib->new) );
55 my $TopDir = $bpc->TopDir();
56 my $BinDir = $bpc->BinDir();
57 my %Conf = $bpc->Conf();
61 my $err = $bpc->ServerConnect($Conf{ServerHost}, $Conf{ServerPort});
63 print("Can't connect to server ($err)\n");
66 my $reply = $bpc->ServerMesg("status hosts");
67 $reply = $1 if ( $reply =~ /(.*)/s );
68 my(%Status, %Info, %Jobs, @BgQueue, @UserQueue, @CmdQueue);
71 ###########################################################################
72 # When BackupPC_nightly starts, BackupPC will not run any simultaneous
73 # BackupPC_dump commands. We first do things that contend with
74 # BackupPC_dump, eg: aging per-PC log files etc.
75 ###########################################################################
78 # Do per-PC log file aging
80 my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
82 foreach my $host ( keys(%Status) ) {
83 my $lastLog = $Conf{MaxOldPerPCLogFiles} - 1;
84 unlink("$TopDir/pc/$host/LOG.$lastLog")
85 if ( -f "$TopDir/pc/$host/LOG.$lastLog" );
86 unlink("$TopDir/pc/$host/LOG.$lastLog.z")
87 if ( -f "$TopDir/pc/$host/LOG.$lastLog.z" );
88 for ( my $i = $lastLog - 1 ; $i >= 0 ; $i-- ) {
90 if ( -f "$TopDir/pc/$host/LOG.$i" ) {
91 rename("$TopDir/pc/$host/LOG.$i", "$TopDir/pc/$host/LOG.$j");
92 } elsif ( -f "$TopDir/pc/$host/LOG.$i.z" ) {
93 rename("$TopDir/pc/$host/LOG.$i.z",
94 "$TopDir/pc/$host/LOG.$j.z");
98 # Compress the log file LOG -> LOG.0.z (if enabled).
99 # Otherwise, just rename LOG -> LOG.0.
101 BackupPC::FileZIO->compressCopy("$TopDir/pc/$host/LOG",
102 "$TopDir/pc/$host/LOG.0.z",
103 "$TopDir/pc/$host/LOG.0",
104 $Conf{CompressLevel}, 1);
105 open(LOG, ">", "$TopDir/pc/$host/LOG") && close(LOG);
109 ###########################################################################
110 # Get statistics on the pool, and remove files that have only one link.
111 ###########################################################################
113 my $fileCnt; # total number of files
114 my $dirCnt; # total number of directories
115 my $blkCnt; # total block size of files
116 my $fileCntRm; # total number of removed files
117 my $blkCntRm; # total block size of removed files
118 my $blkCnt2; # total block size of files with just 2 links
119 # (ie: files that only occur once among all backups)
120 my $fileCntRep; # total number of file names containing "_", ie: files
121 # that have repeated md5 checksums
122 my $fileRepMax; # worse case number of files that have repeated checksums
123 # (ie: max(nnn+1) for all names xxxxxxxxxxxxxxxx_nnn)
124 my $fileLinkMax; # maximum number of hardlinks on a pool file
125 my $fileCntRename; # number of renamed files (to keep file numbering
127 my %FixList; # list of paths that need to be renamed to avoid
129 for my $pool ( qw(pool cpool) ) {
141 find({wanted => \&GetPoolStats, no_chdir => 1}, "$TopDir/$pool");
142 my $kb = $blkCnt / 2;
143 my $kbRm = $blkCntRm / 2;
144 my $kb2 = $blkCnt2 / 2;
147 # Now make sure that files with repeated checksums are still
148 # sequentially numbered
150 foreach my $name ( sort(keys(%FixList)) ) {
151 my $rmCnt = $FixList{$name} + 1;
153 for ( my $old = -1 ; ; $old++ ) {
155 $oldName .= "_$old" if ( $old >= 0 );
156 if ( !-f $oldName ) {
158 # We know we are done when we have missed at least
159 # the number of files that were removed from this
160 # base name, plus a couple just to be sure
162 last if ( $rmCnt-- <= 0 );
166 $newName .= "_$new" if ( $new >= 0 );
168 next if ( $oldName eq $newName );
169 rename($oldName, $newName);
173 print("BackupPC_stats = $pool,$fileCnt,$dirCnt,$kb,$kb2,$kbRm,$fileCntRm,"
174 . "$fileCntRep,$fileRepMax,$fileCntRename,"
178 ###########################################################################
179 # Tell BackupPC that it is now ok to start running BackupPC_dump
180 # commands. We are guaranteed that no BackupPC_link commands will
181 # run since only a single CmdQueue command runs at a time, and
182 # that means we are safe.
183 ###########################################################################
184 printf("BackupPC_nightly lock_off\n");
186 ###########################################################################
188 ###########################################################################
189 system("$BinDir/BackupPC_sendEmail");
193 my($name) = $File::Find::name;
197 return if ( !-d && !-f );
199 $name = $1 if ( $name =~ /(.*)/ );
201 if ( $name =~ /(.*)_(\d+)$/ ) {
204 $fileRepMax = $2 + 1 if ( $fileRepMax <= $2 );
208 if ( -f && $s[3] == 1 ) {
213 # We must keep repeated files numbered sequential (ie: files
214 # that have the same checksum are appended with _0, _1 etc).
215 # There are two cases: we remove the base file xxxx, but xxxx_0
216 # exists, or we remove any file of the form xxxx_nnn. We remember
217 # the base name and fix it up later (not in the middle of find).
219 $baseName = $name if ( $baseName eq "" );
220 $FixList{$baseName}++;
224 $blkCnt2 += $s[12] if ( -f && $s[3] == 2 );
225 $fileLinkMax = $s[3] if ( $fileLinkMax < $s[3] );