]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/restore.c
- Put Dmsg() on inside if() to avoid calling subroutine.
[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 ammended 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    if (!send_include_list(jcr)) {
123       restore_cleanup(jcr, JS_ErrorTerminated);
124       return false;
125    }
126
127    if (!send_exclude_list(jcr)) {
128       restore_cleanup(jcr, JS_ErrorTerminated);
129       return false;
130    }
131
132    /*
133     * send Storage daemon address to the File daemon,
134     *   then wait for File daemon to make connection
135     *   with Storage daemon.
136     */
137    if (jcr->store->SDDport == 0) {
138       jcr->store->SDDport = jcr->store->SDport;
139    }
140    bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport);
141    Dmsg1(6, "dird>filed: %s\n", fd->msg);
142    if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
143       restore_cleanup(jcr, JS_ErrorTerminated);
144       return false;
145    }
146
147    /*
148     * Send the bootstrap file -- what Volumes/files to restore
149     */
150    if (!send_bootstrap_file(jcr)) {
151       restore_cleanup(jcr, JS_ErrorTerminated);
152       return false;
153    }
154
155
156    if (!send_run_before_and_after_commands(jcr)) {
157       restore_cleanup(jcr, JS_ErrorTerminated);
158       return false;
159    }
160
161    /* Send restore command */
162    char replace, *where;
163    char empty = '\0';
164
165    if (jcr->replace != 0) {
166       replace = jcr->replace;
167    } else if (jcr->job->replace != 0) {
168       replace = jcr->job->replace;
169    } else {
170       replace = REPLACE_ALWAYS;       /* always replace */
171    }
172    if (jcr->where) {
173       where = jcr->where;             /* override */
174    } else if (jcr->job->RestoreWhere) {
175       where = jcr->job->RestoreWhere; /* no override take from job */
176    } else {
177       where = ∅                 /* None */
178    }
179    jcr->prefix_links = jcr->job->PrefixLinks;
180    bash_spaces(where);
181    bnet_fsend(fd, restorecmd, replace, jcr->prefix_links, where);
182    unbash_spaces(where);
183
184    if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) {
185       restore_cleanup(jcr, JS_ErrorTerminated);
186       return false;
187    }
188
189    /* Wait for Job Termination */
190    int stat = wait_for_job_termination(jcr);
191    restore_cleanup(jcr, stat);
192
193    return true;
194 }
195
196 bool do_restore_init(JCR *jcr) 
197 {
198    return true;
199 }
200
201 /*
202  * Release resources allocated during restore.
203  *
204  */
205 void restore_cleanup(JCR *jcr, int TermCode)
206 {
207    char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
208    char ec1[30], ec2[30], ec3[30];
209    char term_code[100], fd_term_msg[100], sd_term_msg[100];
210    const char *term_msg;
211    int msg_type;
212    double kbps;
213
214    Dmsg0(20, "In restore_cleanup\n");
215    dequeue_messages(jcr);             /* display any queued messages */
216    set_jcr_job_status(jcr, TermCode);
217
218    if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
219       unlink(jcr->RestoreBootstrap);
220       jcr->unlink_bsr = false;
221    }
222
223    update_job_end_record(jcr);
224
225    msg_type = M_INFO;                 /* by default INFO message */
226    switch (TermCode) {
227    case JS_Terminated:
228       if (jcr->ExpectedFiles > jcr->jr.JobFiles) {
229          term_msg = _("Restore OK -- warning file count mismatch");
230       } else {
231          term_msg = _("Restore OK");
232       }
233       break;
234    case JS_FatalError:
235    case JS_ErrorTerminated:
236       term_msg = _("*** Restore Error ***");
237       msg_type = M_ERROR;          /* Generate error message */
238       if (jcr->store_bsock) {
239          bnet_sig(jcr->store_bsock, BNET_TERMINATE);
240          if (jcr->SD_msg_chan) {
241             pthread_cancel(jcr->SD_msg_chan);
242          }
243       }
244       break;
245    case JS_Canceled:
246       term_msg = _("Restore Canceled");
247       if (jcr->store_bsock) {
248          bnet_sig(jcr->store_bsock, BNET_TERMINATE);
249          if (jcr->SD_msg_chan) {
250             pthread_cancel(jcr->SD_msg_chan);
251          }
252       }
253       break;
254    default:
255       term_msg = term_code;
256       sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
257       break;
258    }
259    bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
260    bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
261    if (jcr->jr.EndTime - jcr->jr.StartTime > 0) {
262       kbps = (double)jcr->jr.JobBytes / (1000 * (jcr->jr.EndTime - jcr->jr.StartTime));
263    } else {
264       kbps = 0;
265    }
266    if (kbps < 0.05) {
267       kbps = 0;
268    }
269
270    jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
271    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
272
273    Jmsg(jcr, msg_type, 0, _("Bacula " VERSION " (" LSMDATE "): %s\n"
274 "  JobId:                  %d\n"
275 "  Job:                    %s\n"
276 "  Client:                 %s\n"
277 "  Start time:             %s\n"
278 "  End time:               %s\n"
279 "  Files Expected:         %s\n"
280 "  Files Restored:         %s\n"
281 "  Bytes Restored:         %s\n"
282 "  Rate:                   %.1f KB/s\n"
283 "  FD Errors:              %d\n"
284 "  FD termination status:  %s\n"
285 "  SD termination status:  %s\n"
286 "  Termination:            %s\n\n"),
287         edt,
288         jcr->jr.JobId,
289         jcr->jr.Job,
290         jcr->client->hdr.name,
291         sdt,
292         edt,
293         edit_uint64_with_commas((uint64_t)jcr->ExpectedFiles, ec1),
294         edit_uint64_with_commas((uint64_t)jcr->jr.JobFiles, ec2),
295         edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
296         (float)kbps,
297         jcr->Errors,
298         fd_term_msg,
299         sd_term_msg,
300         term_msg);
301
302    Dmsg0(20, "Leaving restore_cleanup\n");
303 }