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