]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/restore.c
434842255fe3eb94d2428c93cc0986375143c441
[bacula/bacula] / bacula / src / dird / restore.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *   Bacula Director -- restore.c -- responsible for restoring files
30  *
31  *     Kern Sibbald, November MM
32  *
33  *    This routine is run as a separate thread.
34  *
35  * Current implementation is Catalog verification only (i.e. no
36  *  verification versus tape).
37  *
38  *  Basic tasks done here:
39  *     Open DB
40  *     Open Message Channel with Storage daemon to tell him a job will be starting.
41  *     Open connection with File daemon and pass him commands
42  *       to do the restore.
43  *     Update the DB according to what files where restored????
44  *
45  *   Version $Id$
46  */
47
48
49 #include "bacula.h"
50 #include "dird.h"
51
52 /* Commands sent to File daemon */
53 static char restorecmd[]  = "restore replace=%c prelinks=%d where=%s\n";
54 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
55 static char storaddr[]    = "storage address=%s port=%d ssl=0\n";
56
57 /* Responses received from File daemon */
58 static char OKrestore[]   = "2000 OK restore\n";
59 static char OKstore[]     = "2000 OK storage\n";
60
61 /* Responses received from the Storage daemon */
62 static char OKbootstrap[] = "3000 OK bootstrap\n";
63
64 /*
65  * Do a restore of the specified files
66  *
67  *  Returns:  0 on failure
68  *            1 on success
69  */
70 bool do_restore(JCR *jcr)
71 {
72    BSOCK   *fd, *sd;
73    JOB_DBR rjr;                       /* restore job record */
74    char replace, *where, *cmd;
75    char empty = '\0';
76    int stat;
77
78    free_wstorage(jcr);                /* we don't write */
79
80    if (!allow_duplicate_job(jcr)) {
81       goto bail_out;
82    }
83
84    memset(&rjr, 0, sizeof(rjr));
85    jcr->jr.JobLevel = L_FULL;         /* Full restore */
86    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
87       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
88       goto bail_out;
89    }
90    Dmsg0(20, "Updated job start record\n");
91
92    Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
93
94    if (!jcr->RestoreBootstrap) {
95       Jmsg0(jcr, M_FATAL, 0, _("Cannot restore without a bootstrap file.\n"
96           "You probably ran a restore job directly. All restore jobs must\n"
97           "be run using the restore command.\n"));
98       goto bail_out;
99    }
100
101
102    /* Print Job Start message */
103    Jmsg(jcr, M_INFO, 0, _("Start Restore Job %s\n"), jcr->Job);
104
105    /*
106     * Open a message channel connection with the Storage
107     * daemon. This is to let him know that our client
108     * will be contacting him for a backup  session.
109     *
110     */
111    Dmsg0(10, "Open connection with storage daemon\n");
112    set_jcr_job_status(jcr, JS_WaitSD);
113    /*
114     * Start conversation with Storage daemon
115     */
116    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
117       goto bail_out;
118    }
119    sd = jcr->store_bsock;
120    /*
121     * Now start a job with the Storage daemon
122     */
123    if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL)) {
124       goto bail_out;
125    }
126
127    /*
128     * Send the bootstrap file -- what Volumes/files to restore
129     */
130    if (!send_bootstrap_file(jcr, sd) ||
131        !response(jcr, sd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
132       goto bail_out;
133    }
134
135    if (!sd->fsend("run")) {
136       goto bail_out;
137    }
138    /*
139     * Now start a Storage daemon message thread
140     */
141    if (!start_storage_daemon_message_thread(jcr)) {
142       goto bail_out;
143    }
144    Dmsg0(50, "Storage daemon connection OK\n");
145
146
147    /*
148     * Start conversation with File daemon
149     */
150    set_jcr_job_status(jcr, JS_WaitFD);
151    if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
152       goto bail_out;
153    }
154
155    fd = jcr->file_bsock;
156    set_jcr_job_status(jcr, JS_Running);
157
158    /*
159     * send Storage daemon address to the File daemon,
160     *   then wait for File daemon to make connection
161     *   with Storage daemon.
162     */
163    if (jcr->rstore->SDDport == 0) {
164       jcr->rstore->SDDport = jcr->rstore->SDport;
165    }
166    fd->fsend(storaddr, jcr->rstore->address, jcr->rstore->SDDport);
167    Dmsg1(6, "dird>filed: %s\n", fd->msg);
168    if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
169       goto bail_out;
170    }
171
172    if (!send_runscripts_commands(jcr)) {
173       goto bail_out;
174    }
175
176    /* Send restore command */
177
178    if (jcr->replace != 0) {
179       replace = jcr->replace;
180    } else if (jcr->job->replace != 0) {
181       replace = jcr->job->replace;
182    } else {
183       replace = REPLACE_ALWAYS;       /* always replace */
184    }
185    
186    if (jcr->RegexWhere) {
187       where = jcr->RegexWhere;             /* override */
188       cmd = restorecmdR;
189    } else if (jcr->job->RegexWhere) {
190       where = jcr->job->RegexWhere;   /* no override take from job */
191       cmd = restorecmdR;
192
193    } else if (jcr->where) {
194       where = jcr->where;             /* override */
195       cmd = restorecmd;
196    } else if (jcr->job->RestoreWhere) {
197       where = jcr->job->RestoreWhere; /* no override take from job */
198       cmd = restorecmd;
199
200    } else {                           /* nothing was specified */
201       where = ∅                 /* use default */
202       cmd   = restorecmd;                    
203    }
204    
205    jcr->prefix_links = jcr->job->PrefixLinks;
206
207    bash_spaces(where);
208    fd->fsend(cmd, replace, jcr->prefix_links, where);
209    unbash_spaces(where);
210
211    if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) {
212       goto bail_out;
213    }
214
215    /* Wait for Job Termination */
216    stat = wait_for_job_termination(jcr);
217    restore_cleanup(jcr, stat);
218    return true;
219
220 bail_out:
221    restore_cleanup(jcr, JS_ErrorTerminated);
222    return false;
223 }
224
225 bool do_restore_init(JCR *jcr) 
226 {
227    free_wstorage(jcr);
228    return true;
229 }
230
231 /*
232  * Release resources allocated during restore.
233  *
234  */
235 void restore_cleanup(JCR *jcr, int TermCode)
236 {
237    char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
238    char ec1[30], ec2[30], ec3[30];
239    char term_code[100], fd_term_msg[100], sd_term_msg[100];
240    const char *term_msg;
241    int msg_type = M_INFO;
242    double kbps;
243
244    Dmsg0(20, "In restore_cleanup\n");
245    update_job_end(jcr, TermCode);
246
247    if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
248       unlink(jcr->RestoreBootstrap);
249       jcr->unlink_bsr = false;
250    }
251
252    if (job_canceled(jcr)) {
253       cancel_storage_daemon_job(jcr);
254    }  
255
256    switch (TermCode) {
257    case JS_Terminated:
258       if (jcr->ExpectedFiles > jcr->jr.JobFiles) {
259          term_msg = _("Restore OK -- warning file count mismatch");
260       } else {
261          term_msg = _("Restore OK");
262       }
263       break;
264    case JS_Warnings:
265          term_msg = _("Restore OK -- with warnings");
266          break;
267    case JS_FatalError:
268    case JS_ErrorTerminated:
269       term_msg = _("*** Restore Error ***");
270       msg_type = M_ERROR;          /* Generate error message */
271       if (jcr->store_bsock) {
272          jcr->store_bsock->signal(BNET_TERMINATE);
273          if (jcr->SD_msg_chan) {
274             pthread_cancel(jcr->SD_msg_chan);
275          }
276       }
277       break;
278    case JS_Canceled:
279       term_msg = _("Restore Canceled");
280       if (jcr->store_bsock) {
281          jcr->store_bsock->signal(BNET_TERMINATE);
282          if (jcr->SD_msg_chan) {
283             pthread_cancel(jcr->SD_msg_chan);
284          }
285       }
286       break;
287    default:
288       term_msg = term_code;
289       sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
290       break;
291    }
292    bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
293    bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
294    if (jcr->jr.EndTime - jcr->jr.StartTime > 0) {
295       kbps = (double)jcr->jr.JobBytes / (1000 * (jcr->jr.EndTime - jcr->jr.StartTime));
296    } else {
297       kbps = 0;
298    }
299    if (kbps < 0.05) {
300       kbps = 0;
301    }
302
303    jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
304    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
305
306    Jmsg(jcr, msg_type, 0, _("%s %s %s (%s): %s\n"
307 "  Build OS:               %s %s %s\n"
308 "  JobId:                  %d\n"
309 "  Job:                    %s\n"
310 "  Restore Client:         %s\n"
311 "  Start time:             %s\n"
312 "  End time:               %s\n"
313 "  Files Expected:         %s\n"
314 "  Files Restored:         %s\n"
315 "  Bytes Restored:         %s\n"
316 "  Rate:                   %.1f KB/s\n"
317 "  FD Errors:              %d\n"
318 "  FD termination status:  %s\n"
319 "  SD termination status:  %s\n"
320 "  Termination:            %s\n\n"),
321         BACULA, my_name, VERSION, LSMDATE, edt,
322         HOST_OS, DISTNAME, DISTVER,
323         jcr->jr.JobId,
324         jcr->jr.Job,
325         jcr->client->name(),
326         sdt,
327         edt,
328         edit_uint64_with_commas((uint64_t)jcr->ExpectedFiles, ec1),
329         edit_uint64_with_commas((uint64_t)jcr->jr.JobFiles, ec2),
330         edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
331         (float)kbps,
332         jcr->JobErrors,
333         fd_term_msg,
334         sd_term_msg,
335         term_msg);
336
337    Dmsg0(20, "Leaving restore_cleanup\n");
338 }