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