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