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