f8552c063bb50efa2cc175adf5170291caca625d
[BackupPC.git] / lib / BackupPC / Xfer / BackupPCd.pm
1 #============================================================= -*-perl-*-
2 #
3 # BackupPC::Xfer::BackupPCd package
4 #
5 # DESCRIPTION
6 #
7 #   This library defines a BackupPC::Xfer::BackupPCd class for managing
8 #   the backuppcd-based transport of backup data from the client.
9 #
10 # AUTHOR
11 #   Craig Barratt  <cbarratt@users.sourceforge.net>
12 #
13 # COPYRIGHT
14 #   Copyright (C) 2006-2007  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 3.1.0, released 25 Nov 2007.
33 #
34 # See http://backuppc.sourceforge.net.
35 #
36 #========================================================================
37
38 package BackupPC::Xfer::BackupPCd;
39
40 use strict;
41
42 sub new
43 {
44     my($class, $bpc, $args) = @_;
45
46     $args ||= {};
47     my $t = bless {
48         bpc       => $bpc,
49         conf      => { $bpc->Conf },
50         host      => "",
51         hostIP    => "",
52         shareName => "",
53         badFiles  => [],
54
55         #
56         # Various stats
57         #
58         byteCnt         => 0,
59         fileCnt         => 0,
60         xferErrCnt      => 0,
61         xferBadShareCnt => 0,
62         xferBadFileCnt  => 0,
63         xferOK          => 0,
64
65         #
66         # User's args
67         #
68         %$args,
69     }, $class;
70
71     return $t;
72 }
73
74 sub args
75 {
76     my($t, $args) = @_;
77
78     foreach my $arg ( keys(%$args) ) {
79         $t->{$arg} = $args->{$arg};
80     }
81 }
82
83 sub useTar
84 {
85     return 0;
86 }
87
88 sub start
89 {
90     my($t) = @_;
91     my $bpc = $t->{bpc};
92     my $conf = $t->{conf};
93     my(@fileList, $bpcdCmd, $bpcdArgs, $logMsg, $incrDate,
94         $incrFlag, $restoreDir);
95
96     #
97     # We add a slash to the share name we pass to bpcd
98     #
99     ($t->{shareNameSlash} = "$t->{shareName}/") =~ s{//+$}{/};
100
101     if ( $t->{type} eq "restore" ) {
102         $bpcdCmd = $conf->{BackupPCdRestoreCmd};
103         $restoreDir = "$t->{shareName}/$t->{pathHdrDest}";
104         $restoreDir    =~ s{//+}{/}g;
105         $logMsg = "restore started below directory $t->{shareName}"
106                 . " to host $t->{host}";
107     } else {
108         if ( $t->{type} eq "full" ) {
109             if ( $t->{partialNum} ) {
110                 $logMsg = "full backup started for directory $t->{shareName};"
111                         . " updating partial $t->{partialNum}";
112             } else {
113                 $logMsg = "full backup started for directory $t->{shareName}";
114             }
115             $incrFlag = 0;
116         } else {
117             #
118             # TODO: fix this message - just refer to the backup, not time?
119             #
120             $incrDate = $bpc->timeStamp($t->{incrBaseTime} - 3600, 1);
121             $logMsg = "incr backup started back to $incrDate"
122                     . " (backup #$t->{incrBaseBkupNum}) for directory"
123                     . " $t->{shareName}";
124             $incrFlag = 1;
125         }
126         $bpcdCmd = $conf->{BackupPCdCmd};
127     }
128
129     #
130     # Merge variables into $bpcdCmd
131     #
132     my $args = {
133         host           => $t->{host},
134         hostIP         => $t->{hostIP},
135         client         => $t->{client},
136         shareName      => $t->{shareName},
137         shareNameSlash => $t->{shareNameSlash},
138         restoreDir     => $restoreDir,
139         bpcdPath       => $conf->{BackupPCdPath},
140         sshPath        => $conf->{SshPath},
141         topDir         => $bpc->TopDir(),
142         poolDir        => $t->{compress} ? $bpc->{CPoolDir} : $bpc->{PoolDir},
143         poolCompress   => $t->{compress} + 0,
144         incrFlag       => $incrFlag,
145     };
146     $bpcdCmd = $bpc->cmdVarSubstitute($bpcdCmd, $args);
147
148     $t->{bpcdCmd} = $bpcdCmd;
149
150     delete($t->{_errStr});
151
152     return $logMsg;
153 }
154
155 sub run
156 {
157     my($t) = @_;
158     my $bpc = $t->{bpc};
159     my $conf = $t->{conf};
160     my($remoteSend, $remoteDir, $remoteDirDaemon);
161     my $error;
162     my $stats;
163
164     # NO: alarm($conf->{ClientTimeout});
165
166     #
167     # Run backupcd command
168     #
169     my $str = "Running: "
170             . $t->{bpc}->execCmd2ShellCmd(@{$t->{bpcdCmd}})
171             . "\n";
172     $t->{XferLOG}->write(\$str);
173
174     #
175     #
176     #
177     
178     $bpc->cmdSystemOrEvalLong($t->{bpcdCmd},
179         sub {
180             # write stdout to the XferLOG
181             my($str) = @_;
182             $t->{XferLOG}->write(\$str);
183         }, 
184         0,                  # also catch stderr
185         $t->{pidHandler} 
186     );
187
188     #
189     # TODO: generate sensible stats by parsing the output of
190     # backuppcd.  Get error and fail status.
191     #
192     if ( !defined($error) && defined($stats) ) {
193         $t->{xferOK} = 1;
194     } else {
195         $t->{xferOK} = 0;
196     }
197     $t->{xferErrCnt} = $stats->{errorCnt};
198     $t->{byteCnt}    = $stats->{TotalFileSize};
199     $t->{fileCnt}    = $stats->{TotalFileCnt};
200     my $str = "Done: $t->{fileCnt} files, $t->{byteCnt} bytes\n";
201     $t->{XferLOG}->write(\$str);
202
203     $t->{hostError} = $error if ( defined($error) );
204
205     if ( $t->{type} eq "restore" ) {
206         return (
207             $t->{fileCnt},
208             $t->{byteCnt},
209             0,
210             0
211         );
212     } else {
213         return (
214             0,
215             $stats->{ExistFileCnt},
216             $stats->{ExistFileSize},
217             $stats->{ExistFileCompSize},
218             $stats->{TotalFileCnt},
219             $stats->{TotalFileSize}
220         );
221     }
222 }
223
224 sub abort
225 {
226     my($t, $reason) = @_;
227
228     # TODO
229     return 1;
230 }
231
232 sub errStr
233 {
234     my($t) = @_;
235
236     return $t->{_errStr};
237 }
238
239 sub xferPid
240 {
241     my($t) = @_;
242
243     return ();
244 }
245
246 #
247 # Returns a hash ref giving various status information about
248 # the transfer.
249 #
250 sub getStats
251 {
252     my($t) = @_;
253
254     return { map { $_ => $t->{$_} }
255             qw(byteCnt fileCnt xferErrCnt xferBadShareCnt xferBadFileCnt
256                xferOK hostAbort hostError lastOutputLine)
257     };
258 }
259
260 sub getBadFiles
261 {
262     my($t) = @_;
263
264     return @{$t->{badFiles}};
265 }
266
267 1;