/[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

Annotation of /trunk/bin/BackupPC_archive

Parent Directory Parent Directory | Revision Log Revision Log


Revision 316 - (hide annotations)
Mon Jan 30 13:37:17 2006 UTC (18 years, 4 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 dpavlin 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 dpavlin 316 # Version 2.1.2, released 5 Sep 2005.
33 dpavlin 1 #
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 dpavlin 316 if ( $Conf{CompressLevel} && !BackupPC::FileZIO->compOk ) {
143     $stat{hostError} = "Compress::Zlib not found";
144     exit(ArchiveCleanup($client));
145     }
146 dpavlin 1 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