2 * Bacula Director -- restore.c -- responsible for restoring files
4 * Kern Sibbald, November MM
6 * This routine is run as a separate thread.
8 * Current implementation is Catalog verification only (i.e. no
9 * verification versus tape).
11 * Basic tasks done here:
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
16 * Update the DB according to what files where restored????
21 Copyright (C) 2000-2005 Kern Sibbald
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.
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.
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";
43 /* Responses received from File daemon */
44 static char OKrestore[] = "2000 OK restore\n";
45 static char OKstore[] = "2000 OK storage\n";
48 * Do a restore of the specified files
50 * Returns: 0 on failure
53 bool do_restore(JCR *jcr)
56 JOB_DBR rjr; /* restore job record */
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);
65 Dmsg0(20, "Updated job start record\n");
67 Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
69 if (!jcr->RestoreBootstrap) {
70 Jmsg0(jcr, M_FATAL, 0, _("Cannot restore without bootstrap file.\n"));
71 restore_cleanup(jcr, JS_ErrorTerminated);
76 /* Print Job Start message */
77 Jmsg(jcr, M_INFO, 0, _("Start Restore Job %s\n"), jcr->Job);
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.
85 Dmsg0(10, "Open connection with storage daemon\n");
86 set_jcr_job_status(jcr, JS_WaitSD);
88 * Start conversation with Storage daemon
90 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
91 restore_cleanup(jcr, JS_ErrorTerminated);
95 * Now start a job with the Storage daemon
97 if (!start_storage_daemon_job(jcr, jcr->storage, SD_READ)) {
98 restore_cleanup(jcr, JS_ErrorTerminated);
102 * Now start a Storage daemon message thread
104 if (!start_storage_daemon_message_thread(jcr)) {
105 restore_cleanup(jcr, JS_ErrorTerminated);
108 Dmsg0(50, "Storage daemon connection OK\n");
111 * Start conversation with File daemon
113 set_jcr_job_status(jcr, JS_WaitFD);
114 if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
115 restore_cleanup(jcr, JS_ErrorTerminated);
119 fd = jcr->file_bsock;
120 set_jcr_job_status(jcr, JS_Running);
123 if (!send_include_list(jcr)) {
124 restore_cleanup(jcr, JS_ErrorTerminated);
128 if (!send_exclude_list(jcr)) {
129 restore_cleanup(jcr, JS_ErrorTerminated);
135 * send Storage daemon address to the File daemon,
136 * then wait for File daemon to make connection
137 * with Storage daemon.
139 if (jcr->store->SDDport == 0) {
140 jcr->store->SDDport = jcr->store->SDport;
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);
150 * Send the bootstrap file -- what Volumes/files to restore
152 if (!send_bootstrap_file(jcr)) {
153 restore_cleanup(jcr, JS_ErrorTerminated);
158 if (!send_run_before_and_after_commands(jcr)) {
159 restore_cleanup(jcr, JS_ErrorTerminated);
163 /* Send restore command */
164 char replace, *where;
167 if (jcr->replace != 0) {
168 replace = jcr->replace;
169 } else if (jcr->job->replace != 0) {
170 replace = jcr->job->replace;
172 replace = REPLACE_ALWAYS; /* always replace */
175 where = jcr->where; /* override */
176 } else if (jcr->job->RestoreWhere) {
177 where = jcr->job->RestoreWhere; /* no override take from job */
179 where = ∅ /* None */
181 jcr->prefix_links = jcr->job->PrefixLinks;
183 bnet_fsend(fd, restorecmd, replace, jcr->prefix_links, where);
184 unbash_spaces(where);
186 if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) {
187 restore_cleanup(jcr, JS_ErrorTerminated);
191 /* Wait for Job Termination */
192 int stat = wait_for_job_termination(jcr);
193 restore_cleanup(jcr, stat);
198 bool do_restore_init(JCR *jcr)
204 * Release resources allocated during restore.
207 void restore_cleanup(JCR *jcr, int TermCode)
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;
216 Dmsg0(20, "In restore_cleanup\n");
217 dequeue_messages(jcr); /* display any queued messages */
218 set_jcr_job_status(jcr, TermCode);
220 if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
221 unlink(jcr->RestoreBootstrap);
222 jcr->unlink_bsr = false;
225 update_job_end_record(jcr);
227 msg_type = M_INFO; /* by default INFO message */
230 if (jcr->ExpectedFiles > jcr->jr.JobFiles) {
231 term_msg = _("Restore OK -- warning file count mismatch");
233 term_msg = _("Restore OK");
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);
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);
257 term_msg = term_code;
258 sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
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));
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));
275 Jmsg(jcr, msg_type, 0, _("Bacula %s (%s): %s\n"
281 " Files Expected: %s\n"
282 " Files Restored: %s\n"
283 " Bytes Restored: %s\n"
286 " FD termination status: %s\n"
287 " SD termination status: %s\n"
288 " Termination: %s\n\n"),
294 jcr->client->hdr.name,
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),
306 Dmsg0(20, "Leaving restore_cleanup\n");