]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/restore.c
kes Enhance error message when restoring without bootstrap file.
[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    free_wstorage(jcr);                /* we don't write */
60
61    memset(&rjr, 0, sizeof(rjr));
62    jcr->jr.JobLevel = L_FULL;         /* Full restore */
63    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
64       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
65       restore_cleanup(jcr, JS_ErrorTerminated);
66       return false;
67    }
68    Dmsg0(20, "Updated job start record\n");
69
70    Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
71
72    if (!jcr->RestoreBootstrap) {
73       Jmsg0(jcr, M_FATAL, 0, _("Cannot restore without a bootstrap file.\n"
74           "You probably ran a restore job directly. All restore jobs must\n"
75           "be run using the restore command.\n"));
76       restore_cleanup(jcr, JS_ErrorTerminated);
77       return false;
78    }
79
80
81    /* Print Job Start message */
82    Jmsg(jcr, M_INFO, 0, _("Start Restore Job %s\n"), jcr->Job);
83
84    /*
85     * Open a message channel connection with the Storage
86     * daemon. This is to let him know that our client
87     * will be contacting him for a backup  session.
88     *
89     */
90    Dmsg0(10, "Open connection with storage daemon\n");
91    set_jcr_job_status(jcr, JS_WaitSD);
92    /*
93     * Start conversation with Storage daemon
94     */
95    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
96       restore_cleanup(jcr, JS_ErrorTerminated);
97       return false;
98    }
99    /*
100     * Now start a job with the Storage daemon
101     */
102    if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL)) {
103       restore_cleanup(jcr, JS_ErrorTerminated);
104       return false;
105    }
106    if (!bnet_fsend(jcr->store_bsock, "run")) {
107       return false;
108    }
109    /*
110     * Now start a Storage daemon message thread
111     */
112    if (!start_storage_daemon_message_thread(jcr)) {
113       restore_cleanup(jcr, JS_ErrorTerminated);
114       return false;
115    }
116    Dmsg0(50, "Storage daemon connection OK\n");
117
118
119    /*
120     * Start conversation with File daemon
121     */
122    set_jcr_job_status(jcr, JS_WaitFD);
123    if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
124       restore_cleanup(jcr, JS_ErrorTerminated);
125       return false;
126    }
127
128    fd = jcr->file_bsock;
129    set_jcr_job_status(jcr, JS_Running);
130
131    /*
132     * send Storage daemon address to the File daemon,
133     *   then wait for File daemon to make connection
134     *   with Storage daemon.
135     */
136    if (jcr->rstore->SDDport == 0) {
137       jcr->rstore->SDDport = jcr->rstore->SDport;
138    }
139    bnet_fsend(fd, storaddr, jcr->rstore->address, jcr->rstore->SDDport);
140    Dmsg1(6, "dird>filed: %s\n", fd->msg);
141    if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
142       restore_cleanup(jcr, JS_ErrorTerminated);
143       return false;
144    }
145
146    /*
147     * Send the bootstrap file -- what Volumes/files to restore
148     */
149    if (!send_bootstrap_file(jcr, fd) ||
150        !response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
151       restore_cleanup(jcr, JS_ErrorTerminated);
152       return false;
153    }
154
155
156    if (!send_runscripts_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    free_wstorage(jcr);
199    return true;
200 }
201
202 /*
203  * Release resources allocated during restore.
204  *
205  */
206 void restore_cleanup(JCR *jcr, int TermCode)
207 {
208    char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
209    char ec1[30], ec2[30], ec3[30];
210    char term_code[100], fd_term_msg[100], sd_term_msg[100];
211    const char *term_msg;
212    int msg_type;
213    double kbps;
214
215    Dmsg0(20, "In restore_cleanup\n");
216    dequeue_messages(jcr);             /* display any queued messages */
217    set_jcr_job_status(jcr, TermCode);
218
219    if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
220       unlink(jcr->RestoreBootstrap);
221       jcr->unlink_bsr = false;
222    }
223
224    update_job_end_record(jcr);
225
226    msg_type = M_INFO;                 /* by default INFO message */
227    switch (TermCode) {
228    case JS_Terminated:
229       if (jcr->ExpectedFiles > jcr->jr.JobFiles) {
230          term_msg = _("Restore OK -- warning file count mismatch");
231       } else {
232          term_msg = _("Restore OK");
233       }
234       break;
235    case JS_FatalError:
236    case JS_ErrorTerminated:
237       term_msg = _("*** Restore Error ***");
238       msg_type = M_ERROR;          /* Generate error message */
239       if (jcr->store_bsock) {
240          bnet_sig(jcr->store_bsock, BNET_TERMINATE);
241          if (jcr->SD_msg_chan) {
242             pthread_cancel(jcr->SD_msg_chan);
243          }
244       }
245       break;
246    case JS_Canceled:
247       term_msg = _("Restore Canceled");
248       if (jcr->store_bsock) {
249          bnet_sig(jcr->store_bsock, BNET_TERMINATE);
250          if (jcr->SD_msg_chan) {
251             pthread_cancel(jcr->SD_msg_chan);
252          }
253       }
254       break;
255    default:
256       term_msg = term_code;
257       sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
258       break;
259    }
260    bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
261    bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
262    if (jcr->jr.EndTime - jcr->jr.StartTime > 0) {
263       kbps = (double)jcr->jr.JobBytes / (1000 * (jcr->jr.EndTime - jcr->jr.StartTime));
264    } else {
265       kbps = 0;
266    }
267    if (kbps < 0.05) {
268       kbps = 0;
269    }
270
271    jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
272    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
273
274    Jmsg(jcr, msg_type, 0, _("Bacula %s (%s): %s\n"
275 "  JobId:                  %d\n"
276 "  Job:                    %s\n"
277 "  Client:                 %s\n"
278 "  Start time:             %s\n"
279 "  End time:               %s\n"
280 "  Files Expected:         %s\n"
281 "  Files Restored:         %s\n"
282 "  Bytes Restored:         %s\n"
283 "  Rate:                   %.1f KB/s\n"
284 "  FD Errors:              %d\n"
285 "  FD termination status:  %s\n"
286 "  SD termination status:  %s\n"
287 "  Termination:            %s\n\n"),
288         VERSION,
289         LSMDATE,
290         edt,
291         jcr->jr.JobId,
292         jcr->jr.Job,
293         jcr->client->hdr.name,
294         sdt,
295         edt,
296         edit_uint64_with_commas((uint64_t)jcr->ExpectedFiles, ec1),
297         edit_uint64_with_commas((uint64_t)jcr->jr.JobFiles, ec2),
298         edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
299         (float)kbps,
300         jcr->Errors,
301         fd_term_msg,
302         sd_term_msg,
303         term_msg);
304
305    Dmsg0(20, "Leaving restore_cleanup\n");
306 }