]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/restore.c
ebl Fix #955 bug which was introduce with regexwhere relocation.
[bacula/bacula] / bacula / src / dird / restore.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 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 John Walker.
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 static char OKbootstrap[] = "2000 OK bootstrap\n";
61
62 /*
63  * Do a restore of the specified files
64  *
65  *  Returns:  0 on failure
66  *            1 on success
67  */
68 bool do_restore(JCR *jcr)
69 {
70    BSOCK   *fd;
71    JOB_DBR rjr;                       /* restore job record */
72
73    free_wstorage(jcr);                /* we don't write */
74
75    memset(&rjr, 0, sizeof(rjr));
76    jcr->jr.JobLevel = L_FULL;         /* Full restore */
77    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
78       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
79       restore_cleanup(jcr, JS_ErrorTerminated);
80       return false;
81    }
82    Dmsg0(20, "Updated job start record\n");
83
84    Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
85
86    if (!jcr->RestoreBootstrap) {
87       Jmsg0(jcr, M_FATAL, 0, _("Cannot restore without a bootstrap file.\n"
88           "You probably ran a restore job directly. All restore jobs must\n"
89           "be run using the restore command.\n"));
90       restore_cleanup(jcr, JS_ErrorTerminated);
91       return false;
92    }
93
94
95    /* Print Job Start message */
96    Jmsg(jcr, M_INFO, 0, _("Start Restore Job %s\n"), jcr->Job);
97
98    /*
99     * Open a message channel connection with the Storage
100     * daemon. This is to let him know that our client
101     * will be contacting him for a backup  session.
102     *
103     */
104    Dmsg0(10, "Open connection with storage daemon\n");
105    set_jcr_job_status(jcr, JS_WaitSD);
106    /*
107     * Start conversation with Storage daemon
108     */
109    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
110       restore_cleanup(jcr, JS_ErrorTerminated);
111       return false;
112    }
113    /*
114     * Now start a job with the Storage daemon
115     */
116    if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL)) {
117       restore_cleanup(jcr, JS_ErrorTerminated);
118       return false;
119    }
120    if (!bnet_fsend(jcr->store_bsock, "run")) {
121       return false;
122    }
123    /*
124     * Now start a Storage daemon message thread
125     */
126    if (!start_storage_daemon_message_thread(jcr)) {
127       restore_cleanup(jcr, JS_ErrorTerminated);
128       return false;
129    }
130    Dmsg0(50, "Storage daemon connection OK\n");
131
132
133    /*
134     * Start conversation with File daemon
135     */
136    set_jcr_job_status(jcr, JS_WaitFD);
137    if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
138       restore_cleanup(jcr, JS_ErrorTerminated);
139       return false;
140    }
141
142    fd = jcr->file_bsock;
143    set_jcr_job_status(jcr, JS_Running);
144
145    /*
146     * send Storage daemon address to the File daemon,
147     *   then wait for File daemon to make connection
148     *   with Storage daemon.
149     */
150    if (jcr->rstore->SDDport == 0) {
151       jcr->rstore->SDDport = jcr->rstore->SDport;
152    }
153    bnet_fsend(fd, storaddr, jcr->rstore->address, jcr->rstore->SDDport);
154    Dmsg1(6, "dird>filed: %s\n", fd->msg);
155    if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
156       restore_cleanup(jcr, JS_ErrorTerminated);
157       return false;
158    }
159
160    /*
161     * Send the bootstrap file -- what Volumes/files to restore
162     */
163    if (!send_bootstrap_file(jcr, fd) ||
164        !response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
165       restore_cleanup(jcr, JS_ErrorTerminated);
166       return false;
167    }
168
169
170    if (!send_runscripts_commands(jcr)) {
171       restore_cleanup(jcr, JS_ErrorTerminated);
172       return false;
173    }
174
175    /* Send restore command */
176    char replace, *where, *cmd;
177    char empty = '\0';
178
179    if (jcr->replace != 0) {
180       replace = jcr->replace;
181    } else if (jcr->job->replace != 0) {
182       replace = jcr->job->replace;
183    } else {
184       replace = REPLACE_ALWAYS;       /* always replace */
185    }
186    
187    if (jcr->RegexWhere) {
188       where = jcr->RegexWhere;             /* override */
189       cmd = restorecmdR;
190    } else if (jcr->job->RegexWhere) {
191       where = jcr->job->RegexWhere;   /* no override take from job */
192       cmd = restorecmdR;
193
194    } else if (jcr->where) {
195       where = jcr->where;             /* override */
196       cmd = restorecmd;
197    } else if (jcr->job->RestoreWhere) {
198       where = jcr->job->RestoreWhere; /* no override take from job */
199       cmd = restorecmd;
200
201    } else {                           /* nothing was specified */
202       where = ∅                 /* use default */
203       cmd   = restorecmd;                    
204    }
205    
206    jcr->prefix_links = jcr->job->PrefixLinks;
207
208    bash_spaces(where);
209    bnet_fsend(fd, cmd, replace, jcr->prefix_links, where);
210    unbash_spaces(where);
211
212    if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) {
213       restore_cleanup(jcr, JS_ErrorTerminated);
214       return false;
215    }
216
217    /* Wait for Job Termination */
218    int stat = wait_for_job_termination(jcr);
219    restore_cleanup(jcr, stat);
220
221    return true;
222 }
223
224 bool do_restore_init(JCR *jcr) 
225 {
226    free_wstorage(jcr);
227    return true;
228 }
229
230 /*
231  * Release resources allocated during restore.
232  *
233  */
234 void restore_cleanup(JCR *jcr, int TermCode)
235 {
236    char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
237    char ec1[30], ec2[30], ec3[30];
238    char term_code[100], fd_term_msg[100], sd_term_msg[100];
239    const char *term_msg;
240    int msg_type = M_INFO;
241    double kbps;
242
243    Dmsg0(20, "In restore_cleanup\n");
244    update_job_end(jcr, TermCode);
245
246    if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
247       unlink(jcr->RestoreBootstrap);
248       jcr->unlink_bsr = false;
249    }
250
251    if (job_canceled(jcr)) {
252       cancel_storage_daemon_job(jcr);
253    }  
254
255    switch (TermCode) {
256    case JS_Terminated:
257       if (jcr->ExpectedFiles > jcr->jr.JobFiles) {
258          term_msg = _("Restore OK -- warning file count mismatch");
259       } else {
260          term_msg = _("Restore OK");
261       }
262       break;
263    case JS_FatalError:
264    case JS_ErrorTerminated:
265       term_msg = _("*** Restore Error ***");
266       msg_type = M_ERROR;          /* Generate error message */
267       if (jcr->store_bsock) {
268          bnet_sig(jcr->store_bsock, BNET_TERMINATE);
269          if (jcr->SD_msg_chan) {
270             pthread_cancel(jcr->SD_msg_chan);
271          }
272       }
273       break;
274    case JS_Canceled:
275       term_msg = _("Restore Canceled");
276       if (jcr->store_bsock) {
277          bnet_sig(jcr->store_bsock, BNET_TERMINATE);
278          if (jcr->SD_msg_chan) {
279             pthread_cancel(jcr->SD_msg_chan);
280          }
281       }
282       break;
283    default:
284       term_msg = term_code;
285       sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
286       break;
287    }
288    bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
289    bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
290    if (jcr->jr.EndTime - jcr->jr.StartTime > 0) {
291       kbps = (double)jcr->jr.JobBytes / (1000 * (jcr->jr.EndTime - jcr->jr.StartTime));
292    } else {
293       kbps = 0;
294    }
295    if (kbps < 0.05) {
296       kbps = 0;
297    }
298
299    jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
300    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
301
302    Jmsg(jcr, msg_type, 0, _("Bacula %s %s (%s): %s\n"
303 "  Build OS:               %s %s %s\n"
304 "  JobId:                  %d\n"
305 "  Job:                    %s\n"
306 "  Restore Client:         %s\n"
307 "  Start time:             %s\n"
308 "  End time:               %s\n"
309 "  Files Expected:         %s\n"
310 "  Files Restored:         %s\n"
311 "  Bytes Restored:         %s\n"
312 "  Rate:                   %.1f KB/s\n"
313 "  FD Errors:              %d\n"
314 "  FD termination status:  %s\n"
315 "  SD termination status:  %s\n"
316 "  Termination:            %s\n\n"),
317         my_name, VERSION, LSMDATE, edt,
318         HOST_OS, DISTNAME, DISTVER,
319         jcr->jr.JobId,
320         jcr->jr.Job,
321         jcr->client->name(),
322         sdt,
323         edt,
324         edit_uint64_with_commas((uint64_t)jcr->ExpectedFiles, ec1),
325         edit_uint64_with_commas((uint64_t)jcr->jr.JobFiles, ec2),
326         edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
327         (float)kbps,
328         jcr->Errors,
329         fd_term_msg,
330         sd_term_msg,
331         term_msg);
332
333    Dmsg0(20, "Leaving restore_cleanup\n");
334 }