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);
122 if (!send_include_list(jcr)) {
123 restore_cleanup(jcr, JS_ErrorTerminated);
127 if (!send_exclude_list(jcr)) {
128 restore_cleanup(jcr, JS_ErrorTerminated);
133 * send Storage daemon address to the File daemon,
134 * then wait for File daemon to make connection
135 * with Storage daemon.
137 if (jcr->store->SDDport == 0) {
138 jcr->store->SDDport = jcr->store->SDport;
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);
148 * Send the bootstrap file -- what Volumes/files to restore
150 if (!send_bootstrap_file(jcr)) {
151 restore_cleanup(jcr, JS_ErrorTerminated);
156 if (!send_run_before_and_after_commands(jcr)) {
157 restore_cleanup(jcr, JS_ErrorTerminated);
161 /* Send restore command */
162 char replace, *where;
165 if (jcr->replace != 0) {
166 replace = jcr->replace;
167 } else if (jcr->job->replace != 0) {
168 replace = jcr->job->replace;
170 replace = REPLACE_ALWAYS; /* always replace */
173 where = jcr->where; /* override */
174 } else if (jcr->job->RestoreWhere) {
175 where = jcr->job->RestoreWhere; /* no override take from job */
177 where = ∅ /* None */
179 jcr->prefix_links = jcr->job->PrefixLinks;
181 bnet_fsend(fd, restorecmd, replace, jcr->prefix_links, where);
182 unbash_spaces(where);
184 if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) {
185 restore_cleanup(jcr, JS_ErrorTerminated);
189 /* Wait for Job Termination */
190 int stat = wait_for_job_termination(jcr);
191 restore_cleanup(jcr, stat);
196 bool do_restore_init(JCR *jcr)
202 * Release resources allocated during restore.
205 void restore_cleanup(JCR *jcr, int TermCode)
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;
214 Dmsg0(20, "In restore_cleanup\n");
215 dequeue_messages(jcr); /* display any queued messages */
216 set_jcr_job_status(jcr, TermCode);
218 if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
219 unlink(jcr->RestoreBootstrap);
220 jcr->unlink_bsr = false;
223 update_job_end_record(jcr);
225 msg_type = M_INFO; /* by default INFO message */
228 if (jcr->ExpectedFiles > jcr->jr.JobFiles) {
229 term_msg = _("Restore OK -- warning file count mismatch");
231 term_msg = _("Restore OK");
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);
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);
255 term_msg = term_code;
256 sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
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));
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));
273 Jmsg(jcr, msg_type, 0, _("Bacula " VERSION " (" LSMDATE "): %s\n"
279 " Files Expected: %s\n"
280 " Files Restored: %s\n"
281 " Bytes Restored: %s\n"
284 " FD termination status: %s\n"
285 " SD termination status: %s\n"
286 " Termination: %s\n\n"),
290 jcr->client->hdr.name,
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),
302 Dmsg0(20, "Leaving restore_cleanup\n");