/[BackupPC]/upstream/2.1.0/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 /upstream/2.1.0/bin/BackupPC_archive

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Jun 22 19:12:04 2005 UTC (18 years, 10 months ago) by dpavlin
File size: 10278 byte(s)
import of version 2.1.0

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.0, released 20 Jun 2004.
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 $Conf{CompressLevel} = 0 if ( !BackupPC::FileZIO->compOk );
143 my $fileExt = $Conf{CompressLevel} > 0 ? ".z" : "";
144 my $ArchiveLOG = BackupPC::FileZIO->open("$Dir/ArchiveLOG$fileExt", 1,
145 $Conf{CompressLevel});
146 my($logMsg, $xfer);
147
148 $stat{xferOK} = 1;
149 $stat{hostAbort} = undef;
150 $stat{hostError} = $stat{lastOutputLine} = undef;
151 local(*RH, *WH);
152
153 #
154 # Run an optional pre-archive command
155 #
156 UserCommandRun("ArchivePreUserCmd");
157 $NeedPostCmd = 1;
158
159 $xfer = BackupPC::Xfer::Archive->new($bpc);
160
161 #
162 # Run the transport program
163 #
164
165 my $xferArgs = {
166 client => $client,
167 host => $host,
168 user => $ArchiveReq{user},
169 type => "archive",
170 XferLOG => $ArchiveLOG,
171 XferMethod => $Conf{XferMethod},
172 pathHdrSrc => $ArchiveReq{pathHdrSrc},
173 pathHdrDest => $ArchiveReq{pathHdrDest},
174 HostList => \@{$ArchiveReq{HostList}},
175 BackupList => \@{$ArchiveReq{BackupList}},
176 archiveloc => $ArchiveReq{archiveloc},
177 parfile => $ArchiveReq{parfile},
178 compression => $ArchiveReq{compression},
179 compext => $ArchiveReq{compext},
180 splitsize => $ArchiveReq{splitsize},
181 pidHandler => \&pidHandler,
182 };
183
184 $xfer->args($xferArgs);
185
186 if ( !defined($logMsg = $xfer->start()) ) {
187 UserCommandRun("ArchivePostUserCmd") if ( $NeedPostCmd );
188 $stat{hostError} = "xfer start failed: ", $xfer->errStr;
189 exit(ArchiveCleanup($client));
190 }
191
192 print(LOG $bpc->timeStamp, "Starting archive\n");
193 print("started_archive\n");
194 $xfer->run();
195 $stat{xferOK} = 0 if ( defined($stat{hostError} = $xfer->errStr) );
196 alarm(0);
197
198 exit(ArchiveCleanup($client));
199
200 ###########################################################################
201 # Subroutines
202 ###########################################################################
203
204 sub catch_signal
205 {
206 my $signame = shift;
207
208 #
209 # Children quit quietly on ALRM
210 #
211 exit(1) if ( $Pid != $$ && $signame eq "ALRM" );
212
213 #
214 # Ignore signals in children
215 #
216 return if ( $Pid != $$ );
217
218 #
219 # Note: needs to be tested for each kind of XferMethod
220 #
221 print(LOG $bpc->timeStamp, "cleaning up after signal $signame\n");
222 $SIG{$signame} = 'IGNORE';
223 $ArchiveLOG->write(\"exiting after signal $signame\n");
224 $stat{xferOK} = 0;
225 if ( $signame eq "INT" ) {
226 $stat{hostError} = "aborted by user (signal=$signame)";
227 } else {
228 $stat{hostError} = "aborted by signal=$signame";
229 }
230 exit(ArchiveCleanup($client));
231 }
232
233 #
234 # Cleanup and update the archive status
235 #
236 sub ArchiveCleanup
237 {
238 my($client) = @_;
239
240 $stat{xferOK} = 0 if ( $stat{hostError} || $stat{hostAbort} );
241
242 if ( !$stat{xferOK} ) {
243 #
244 # Kill off the tranfer program, first nicely then forcefully.
245 # We use negative PIDs to make sure all processes in each
246 # group get the signal.
247 #
248 if ( @xferPid ) {
249 foreach my $pid ( @xferPid ) {
250 kill($bpc->sigName2num("INT"), -$pid);
251 }
252 sleep(1);
253 foreach my $pid ( @xferPid ) {
254 kill($bpc->sigName2num("KILL"), -$pid);
255 }
256 }
257 }
258
259 my $lastNum = -1;
260 my @Archives;
261
262 @Archives = $bpc->ArchiveInfoRead($client);
263 for ( my $i = 0 ; $i < @Archives ; $i++ ) {
264 $lastNum = $Archives[$i]{num} if ( $lastNum < $Archives[$i]{num} );
265 }
266 $lastNum++;
267
268 #
269 # Run an optional post-archive command
270 #
271 UserCommandRun("ArchivePostUserCmd") if ( $NeedPostCmd );
272
273 rename("$Dir/ArchiveLOG$fileExt", "$Dir/ArchiveLOG.$lastNum$fileExt");
274 rename("$Dir/$reqFileName", "$Dir/ArchiveInfo.$lastNum");
275 my $endTime = time();
276
277 #
278 # If the archive failed, clean up
279 #
280 if ( !$stat{xferOK} ) {
281 $stat{hostError} = $stat{lastOutputLine} if ( $stat{hostError} eq "" );
282 $stat{hostAbort} = 1;
283 $ArchiveLOG->write(\"Archive failed: $stat{hostError}")
284 if ( defined($ArchiveLOG) );
285 }
286
287 $ArchiveLOG->close() if ( defined($ArchiveLOG) );
288
289 #
290 # Add the new archive information to the archive file
291 #
292 @Archives = $bpc->ArchiveInfoRead($client);
293 my $i = @Archives;
294 $Archives[$i]{num} = $lastNum;
295 $Archives[$i]{startTime} = $startTime;
296 $Archives[$i]{endTime} = $endTime;
297 $Archives[$i]{result} = $stat{xferOK} ? "ok" : "failed";
298 $Archives[$i]{errorMsg} = $stat{hostError};
299
300 while ( @Archives > $Conf{ArchiveInfoKeepCnt} ) {
301 my $num = $Archives[0]{num};
302 unlink("$Dir/ArchiveLOG.$num.z");
303 unlink("$Dir/ArchiveLOG.$num");
304 unlink("$Dir/ArchiveInfo.$num");
305 shift(@Archives);
306 }
307 $bpc->ArchiveInfoWrite($client, @Archives);
308
309 if ( !$stat{xferOK} ) {
310 print(LOG $bpc->timeStamp, "Archive failed ($stat{hostError})\n");
311 print("archive failed: $stat{hostError}\n");
312 return 1;
313 } else {
314 print(LOG $bpc->timeStamp, "Archive Complete\n");
315 print("archive complete\n");
316 return;
317 }
318 }
319
320 #
321 # The Xfer method might tell us from time to time about processes
322 # it forks. We tell BackupPC about this (for status displays) and
323 # keep track of the pids in case we cancel the backup
324 #
325 sub pidHandler
326 {
327 @xferPid = @_;
328 @xferPid = grep(/./, @xferPid);
329 return if ( !@xferPid );
330 my @pids = @xferPid;
331 my $str = join(",", @pids);
332 $ArchiveLOG->write(\"Xfer PIDs are now $str\n") if ( defined($ArchiveLOG) );
333 print("xferPids $str\n");
334 }
335
336 #
337 # Run an optional pre- or post-dump command
338 #
339 sub UserCommandRun
340 {
341 my($cmdType) = @_;
342
343 return if ( !defined($Conf{$cmdType}) );
344 my $vars = {
345 xfer => $xfer,
346 client => $client,
347 host => $host,
348 user => $user,
349 share => $ArchiveReq{shareDest},
350 XferMethod => $Conf{XferMethod},
351 HostList => \@{$ArchiveReq{HostList}},
352 BackupList => \@{$ArchiveReq{BackupList}},
353 archiveloc => $ArchiveReq{archiveloc},
354 parfile => $ArchiveReq{parfile},
355 compression => $ArchiveReq{compression},
356 compext => $ArchiveReq{compext},
357 splitsize => $ArchiveReq{splitsize},
358 sshPath => $Conf{SshPath},
359 LOG => *LOG,
360 XferLOG => $ArchiveLOG,
361 stat => \%stat,
362 xferOK => $stat{xferOK} || 0,
363 type => "archive",
364 cmdType => $cmdType,
365 };
366 my $cmd = $bpc->cmdVarSubstitute($Conf{$cmdType}, $vars);
367 $ArchiveLOG->write(\"Executing $cmdType: @$cmd\n");
368 #
369 # Run the user's command, dumping the stdout/stderr into the
370 # Xfer log file. Also supply the optional $vars and %Conf in
371 # case the command is really perl code instead of a shell
372 # command.
373 #
374 $bpc->cmdSystemOrEval($cmd,
375 sub {
376 $ArchiveLOG->write(\$_[0]);
377 },
378 $vars, \%Conf);
379 }

Properties

Name Value
svn:executable

  ViewVC Help
Powered by ViewVC 1.1.26