/[BackupPC]/trunk/bin/BackupPC_archive
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/bin/BackupPC_archive

Parent Directory Parent Directory | Revision Log Revision Log


Revision 316 - (show annotations)
Mon Jan 30 13:37:17 2006 UTC (18 years, 3 months ago) by dpavlin
File size: 10365 byte(s)
 r9152@llin:  dpavlin | 2006-01-30 14:11:45 +0100
 update to upstream 2.1.2

1 #!/bin/perl
2 #============================================================= -*-perl-*-
3 #
4 # BackupPC_archive: Archive files for an archive client.
5 #
6 # DESCRIPTION
7 #
8 # Usage: BackupPC_archive <user> <archiveclient> <reqFileName>
9 #
10 # AUTHOR
11 # Josh Marshall
12 #
13 # COPYRIGHT
14 # Copyright (C) 2001-2004 Craig Barratt
15 #
16 # This program is free software; you can redistribute it and/or modify
17 # it under the terms of the GNU General Public License as published by
18 # the Free Software Foundation; either version 2 of the License, or
19 # (at your option) any later version.
20 #
21 # This program is distributed in the hope that it will be useful,
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 # GNU General Public License for more details.
25 #
26 # You should have received a copy of the GNU General Public License
27 # along with this program; if not, write to the Free Software
28 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #
30 #========================================================================
31 #
32 # Version 2.1.2, released 5 Sep 2005.
33 #
34 # See http://backuppc.sourceforge.net.
35 #
36 #========================================================================
37
38 use strict;
39 no utf8;
40 use lib "__INSTALLDIR__/lib";
41 use BackupPC::Lib;
42 use BackupPC::FileZIO;
43 use BackupPC::Xfer::Archive;
44
45 use vars qw( %ArchiveReq );
46
47 ###########################################################################
48 # Initialize
49 ###########################################################################
50
51 die("BackupPC::Lib->new failed\n") if ( !(my $bpc = BackupPC::Lib->new) );
52 my $TopDir = $bpc->TopDir();
53 my $BinDir = $bpc->BinDir();
54 my %Conf = $bpc->Conf();
55 my $NeedPostCmd;
56
57 my($user, $host, $client, $reqFileName, %stat);
58
59 $bpc->ChildInit();
60
61 if ( @ARGV != 3 ) {
62 print("usage: $0 <user> <archiveclient> <reqFileName>\n");
63 exit(1);
64 }
65 $user = $1 if ( $ARGV[0] =~ /(.+)/ );
66 $client = $1 if ( $ARGV[1] =~ /(.+)/ );
67 if ( $ARGV[2] !~ /^([\w.]+)$/ ) {
68 print("$0: bad reqFileName (arg #3): $ARGV[2]\n");
69 exit(1);
70 }
71 $reqFileName = $1;
72
73 my $startTime = time();
74
75 my $Dir = "$TopDir/pc/$client";
76 my @xferPid = ();
77
78 #
79 # Catch various signals
80 #
81 $SIG{INT} = \&catch_signal;
82 $SIG{ALRM} = \&catch_signal;
83 $SIG{TERM} = \&catch_signal;
84 $SIG{PIPE} = \&catch_signal;
85 $SIG{STOP} = \&catch_signal;
86 $SIG{TSTP} = \&catch_signal;
87 $SIG{TTIN} = \&catch_signal;
88 my $Pid = $$;
89
90 mkpath($Dir, 0, 0777) if ( !-d $Dir );
91 if ( !-f "$Dir/LOCK" ) {
92 open(LOCK, ">", "$Dir/LOCK") && close(LOCK);
93 }
94 open(LOG, ">>", "$Dir/LOG");
95 select(LOG); $| = 1; select(STDOUT);
96
97
98 #
99 # Read the request file
100 #
101
102 if ( !(my $ret = do "$Dir/$reqFileName") ) {
103 my $err;
104 if ( $@ ) {
105 $err = "couldn't parse $Dir/$reqFileName: $@";
106 } elsif ( !defined($ret) ) {
107 $err = "couldn't do $Dir/$reqFileName: $!";
108 } else {
109 $err = "couldn't run $Dir/$reqFileName";
110 }
111 $stat{hostError} = $err;
112 exit(ArchiveCleanup($client));
113 }
114
115 #
116 # Re-read config file, so we can include the PC-specific config
117 #
118 if ( defined(my $error = $bpc->ConfigRead($client)) ) {
119 $stat{hostError} = "Can't read PC's config file: $error";
120 exit(ArchiveCleanup($client));
121 }
122 %Conf = $bpc->Conf();
123
124 #
125 # Make sure we eventually timeout if there is no activity from
126 # the data transport program.
127 #
128 alarm($Conf{ClientTimeout});
129
130 #
131 # See if the host name is aliased
132 #
133 if ( $Conf{ClientNameAlias} ne "" ) {
134 $host = $Conf{ClientNameAlias};
135 } else {
136 $host = $client;
137 }
138
139 #
140 # Setup file extension for compression and open ArchiveLOG output file
141 #
142 if ( $Conf{CompressLevel} && !BackupPC::FileZIO->compOk ) {
143 $stat{hostError} = "Compress::Zlib not found";
144 exit(ArchiveCleanup($client));
145 }
146 my $fileExt = $Conf{CompressLevel} > 0 ? ".z" : "";
147 my $ArchiveLOG = BackupPC::FileZIO->open("$Dir/ArchiveLOG$fileExt", 1,
148 $Conf{CompressLevel});
149 my($logMsg, $xfer);
150
151 $stat{xferOK} = 1;
152 $stat{hostAbort} = undef;
153 $stat{hostError} = $stat{lastOutputLine} = undef;
154 local(*RH, *WH);
155
156 #
157 # Run an optional pre-archive command
158 #
159 UserCommandRun("ArchivePreUserCmd");
160 $NeedPostCmd = 1;
161
162 $xfer = BackupPC::Xfer::Archive->new($bpc);
163
164 #
165 # Run the transport program
166 #
167
168 my $xferArgs = {
169 client => $client,
170 host => $host,
171 user => $ArchiveReq{user},
172 type => "archive",
173 XferLOG => $ArchiveLOG,
174 XferMethod => $Conf{XferMethod},
175 pathHdrSrc => $ArchiveReq{pathHdrSrc},
176 pathHdrDest => $ArchiveReq{pathHdrDest},
177 HostList => \@{$ArchiveReq{HostList}},
178 BackupList => \@{$ArchiveReq{BackupList}},
179 archiveloc => $ArchiveReq{archiveloc},
180 parfile => $ArchiveReq{parfile},
181 compression => $ArchiveReq{compression},
182 compext => $ArchiveReq{compext},
183 splitsize => $ArchiveReq{splitsize},
184 pidHandler => \&pidHandler,
185 };
186
187 $xfer->args($xferArgs);
188
189 if ( !defined($logMsg = $xfer->start()) ) {
190 UserCommandRun("ArchivePostUserCmd") if ( $NeedPostCmd );
191 $stat{hostError} = "xfer start failed: ", $xfer->errStr;
192 exit(ArchiveCleanup($client));
193 }
194
195 print(LOG $bpc->timeStamp, "Starting archive\n");
196 print("started_archive\n");
197 $xfer->run();
198 $stat{xferOK} = 0 if ( defined($stat{hostError} = $xfer->errStr) );
199 alarm(0);
200
201 exit(ArchiveCleanup($client));
202
203 ###########################################################################
204 # Subroutines
205 ###########################################################################
206
207 sub catch_signal
208 {
209 my $signame = shift;
210
211 #
212 # Children quit quietly on ALRM
213 #
214 exit(1) if ( $Pid != $$ && $signame eq "ALRM" );
215
216 #
217 # Ignore signals in children
218 #
219 return if ( $Pid != $$ );
220
221 #
222 # Note: needs to be tested for each kind of XferMethod
223 #
224 print(LOG $bpc->timeStamp, "cleaning up after signal $signame\n");
225 $SIG{$signame} = 'IGNORE';
226 $ArchiveLOG->write(\"exiting after signal $signame\n");
227 $stat{xferOK} = 0;
228 if ( $signame eq "INT" ) {
229 $stat{hostError} = "aborted by user (signal=$signame)";
230 } else {
231 $stat{hostError} = "aborted by signal=$signame";
232 }
233 exit(ArchiveCleanup($client));
234 }
235
236 #
237 # Cleanup and update the archive status
238 #
239 sub ArchiveCleanup
240 {
241 my($client) = @_;
242
243 $stat{xferOK} = 0 if ( $stat{hostError} || $stat{hostAbort} );
244
245 if ( !$stat{xferOK} ) {
246 #
247 # Kill off the tranfer program, first nicely then forcefully.
248 # We use negative PIDs to make sure all processes in each
249 # group get the signal.
250 #
251 if ( @xferPid ) {
252 foreach my $pid ( @xferPid ) {
253 kill($bpc->sigName2num("INT"), -$pid);
254 }
255 sleep(1);
256 foreach my $pid ( @xferPid ) {
257 kill($bpc->sigName2num("KILL"), -$pid);
258 }
259 }
260 }
261
262 my $lastNum = -1;
263 my @Archives;
264
265 @Archives = $bpc->ArchiveInfoRead($client);
266 for ( my $i = 0 ; $i < @Archives ; $i++ ) {
267 $lastNum = $Archives[$i]{num} if ( $lastNum < $Archives[$i]{num} );
268 }
269 $lastNum++;
270
271 #
272 # Run an optional post-archive command
273 #
274 UserCommandRun("ArchivePostUserCmd") if ( $NeedPostCmd );
275
276 rename("$Dir/ArchiveLOG$fileExt", "$Dir/ArchiveLOG.$lastNum$fileExt");
277 rename("$Dir/$reqFileName", "$Dir/ArchiveInfo.$lastNum");
278 my $endTime = time();
279
280 #
281 # If the archive failed, clean up
282 #
283 if ( !$stat{xferOK} ) {
284 $stat{hostError} = $stat{lastOutputLine} if ( $stat{hostError} eq "" );
285 $stat{hostAbort} = 1;
286 $ArchiveLOG->write(\"Archive failed: $stat{hostError}")
287 if ( defined($ArchiveLOG) );
288 }
289
290 $ArchiveLOG->close() if ( defined($ArchiveLOG) );
291
292 #
293 # Add the new archive information to the archive file
294 #
295 @Archives = $bpc->ArchiveInfoRead($client);
296 my $i = @Archives;
297 $Archives[$i]{num} = $lastNum;
298 $Archives[$i]{startTime} = $startTime;
299 $Archives[$i]{endTime} = $endTime;
300 $Archives[$i]{result} = $stat{xferOK} ? "ok" : "failed";
301 $Archives[$i]{errorMsg} = $stat{hostError};
302
303 while ( @Archives > $Conf{ArchiveInfoKeepCnt} ) {
304 my $num = $Archives[0]{num};
305 unlink("$Dir/ArchiveLOG.$num.z");
306 unlink("$Dir/ArchiveLOG.$num");
307 unlink("$Dir/ArchiveInfo.$num");
308 shift(@Archives);
309 }
310 $bpc->ArchiveInfoWrite($client, @Archives);
311
312 if ( !$stat{xferOK} ) {
313 print(LOG $bpc->timeStamp, "Archive failed ($stat{hostError})\n");
314 print("archive failed: $stat{hostError}\n");
315 return 1;
316 } else {
317 print(LOG $bpc->timeStamp, "Archive Complete\n");
318 print("archive complete\n");
319 return;
320 }
321 }
322
323 #
324 # The Xfer method might tell us from time to time about processes
325 # it forks. We tell BackupPC about this (for status displays) and
326 # keep track of the pids in case we cancel the backup
327 #
328 sub pidHandler
329 {
330 @xferPid = @_;
331 @xferPid = grep(/./, @xferPid);
332 return if ( !@xferPid );
333 my @pids = @xferPid;
334 my $str = join(",", @pids);
335 $ArchiveLOG->write(\"Xfer PIDs are now $str\n") if ( defined($ArchiveLOG) );
336 print("xferPids $str\n");
337 }
338
339 #
340 # Run an optional pre- or post-dump command
341 #
342 sub UserCommandRun
343 {
344 my($cmdType) = @_;
345
346 return if ( !defined($Conf{$cmdType}) );
347 my $vars = {
348 xfer => $xfer,
349 client => $client,
350 host => $host,
351 user => $user,
352 share => $ArchiveReq{shareDest},
353 XferMethod => $Conf{XferMethod},
354 HostList => \@{$ArchiveReq{HostList}},
355 BackupList => \@{$ArchiveReq{BackupList}},
356 archiveloc => $ArchiveReq{archiveloc},
357 parfile => $ArchiveReq{parfile},
358 compression => $ArchiveReq{compression},
359 compext => $ArchiveReq{compext},
360 splitsize => $ArchiveReq{splitsize},
361 sshPath => $Conf{SshPath},
362 LOG => *LOG,
363 XferLOG => $ArchiveLOG,
364 stat => \%stat,
365 xferOK => $stat{xferOK} || 0,
366 type => "archive",
367 cmdType => $cmdType,
368 };
369 my $cmd = $bpc->cmdVarSubstitute($Conf{$cmdType}, $vars);
370 $ArchiveLOG->write(\"Executing $cmdType: @$cmd\n");
371 #
372 # Run the user's command, dumping the stdout/stderr into the
373 # Xfer log file. Also supply the optional $vars and %Conf in
374 # case the command is really perl code instead of a shell
375 # command.
376 #
377 $bpc->cmdSystemOrEval($cmd,
378 sub {
379 $ArchiveLOG->write(\$_[0]);
380 },
381 $vars, \%Conf);
382 }

Properties

Name Value
svn:executable

  ViewVC Help
Powered by ViewVC 1.1.26