e6dd5b054acd84ba4322720085def31771ba72d2
[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 use base qw(BackupPC::Xfer::Protocol);
42
43 sub new
44 {
45     my($class, $bpc, $args) = @_;
46
47     $args ||= {};
48     my $t = bless {
49         bpc       => $bpc,
50         conf      => { $bpc->Conf },
51         host      => "",
52         hostIP    => "",
53         shareName => "",
54         badFiles  => [],
55
56         #
57         # Various stats
58         #
59         byteCnt         => 0,
60         fileCnt         => 0,
61         xferErrCnt      => 0,
62         xferBadShareCnt => 0,
63         xferBadFileCnt  => 0,
64         xferOK          => 0,
65
66         #
67         # User's args
68         #
69         %$args,
70     }, $class;
71
72     return $t;
73 }
74
75 sub start
76 {
77     my($t) = @_;
78     my $bpc = $t->{bpc};
79     my $conf = $t->{conf};
80     my(@fileList, $bpcdCmd, $bpcdArgs, $logMsg, $incrDate,
81         $incrFlag, $restoreDir);
82
83     #
84     # We add a slash to the share name we pass to bpcd
85     #
86     ($t->{shareNameSlash} = "$t->{shareName}/") =~ s{//+$}{/};
87
88     if ( $t->{type} eq "restore" ) {
89         $bpcdCmd = $conf->{BackupPCdRestoreCmd};
90         $restoreDir = "$t->{shareName}/$t->{pathHdrDest}";
91         $restoreDir    =~ s{//+}{/}g;
92         $logMsg = "restore started below directory $t->{shareName}"
93                 . " to host $t->{host}";
94     } else {
95         if ( $t->{type} eq "full" ) {
96             if ( $t->{partialNum} ) {
97                 $logMsg = "full backup started for directory $t->{shareName};"
98                         . " updating partial $t->{partialNum}";
99             } else {
100                 $logMsg = "full backup started for directory $t->{shareName}";
101             }
102             $incrFlag = 0;
103         } else {
104             #
105             # TODO: fix this message - just refer to the backup, not time?
106             #
107             $incrDate = $bpc->timeStamp($t->{incrBaseTime} - 3600, 1);
108             $logMsg = "incr backup started back to $incrDate"
109                     . " (backup #$t->{incrBaseBkupNum}) for directory"
110                     . " $t->{shareName}";
111             $incrFlag = 1;
112         }
113         $bpcdCmd = $conf->{BackupPCdCmd};
114     }
115
116     #
117     # Merge variables into $bpcdCmd
118     #
119     my $args = {
120         host           => $t->{host},
121         hostIP         => $t->{hostIP},
122         client         => $t->{client},
123         shareName      => $t->{shareName},
124         shareNameSlash => $t->{shareNameSlash},
125         restoreDir     => $restoreDir,
126         bpcdPath       => $conf->{BackupPCdPath},
127         sshPath        => $conf->{SshPath},
128         topDir         => $bpc->TopDir(),
129         poolDir        => $t->{compress} ? $bpc->{CPoolDir} : $bpc->{PoolDir},
130         poolCompress   => $t->{compress} + 0,
131         incrFlag       => $incrFlag,
132     };
133     $bpcdCmd = $bpc->cmdVarSubstitute($bpcdCmd, $args);
134
135     $t->{bpcdCmd} = $bpcdCmd;
136
137     delete($t->{_errStr});
138
139     return $logMsg;
140 }
141
142 sub run
143 {
144     my($t) = @_;
145     my $bpc = $t->{bpc};
146     my $conf = $t->{conf};
147     my($remoteSend, $remoteDir, $remoteDirDaemon);
148     my $error;
149     my $stats;
150
151     # NO: alarm($conf->{ClientTimeout});
152
153     #
154     # Run backupcd command
155     #
156     my $str = "Running: "
157             . $t->{bpc}->execCmd2ShellCmd(@{$t->{bpcdCmd}})
158             . "\n";
159     $t->{XferLOG}->write(\$str);
160
161     #
162     #
163     #
164     
165     $bpc->cmdSystemOrEvalLong($t->{bpcdCmd},
166         sub {
167             # write stdout to the XferLOG
168             my($str) = @_;
169             $t->{XferLOG}->write(\$str);
170         }, 
171         0,                  # also catch stderr
172         $t->{pidHandler} 
173     );
174
175     #
176     # TODO: generate sensible stats by parsing the output of
177     # backuppcd.  Get error and fail status.
178     #
179     if ( !defined($error) && defined($stats) ) {
180         $t->{xferOK} = 1;
181     } else {
182         $t->{xferOK} = 0;
183     }
184     $t->{xferErrCnt} = $stats->{errorCnt};
185     $t->{byteCnt}    = $stats->{TotalFileSize};
186     $t->{fileCnt}    = $stats->{TotalFileCnt};
187     my $str = "Done: $t->{fileCnt} files, $t->{byteCnt} bytes\n";
188     $t->{XferLOG}->write(\$str);
189
190     $t->{hostError} = $error if ( defined($error) );
191
192     if ( $t->{type} eq "restore" ) {
193         return (
194             $t->{fileCnt},
195             $t->{byteCnt},
196             0,
197             0
198         );
199     } else {
200         return (
201             0,
202             $stats->{ExistFileCnt},
203             $stats->{ExistFileSize},
204             $stats->{ExistFileCompSize},
205             $stats->{TotalFileCnt},
206             $stats->{TotalFileSize}
207         );
208     }
209 }
210
211 1;