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