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-2006 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";
46 static char OKbootstrap[] = "2000 OK bootstrap\n";
49 * Do a restore of the specified files
51 * Returns: 0 on failure
54 bool do_restore(JCR *jcr)
57 JOB_DBR rjr; /* restore job record */
59 free_wstorage(jcr); /* we don't write */
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);
68 Dmsg0(20, "Updated job start record\n");
70 Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
72 if (!jcr->RestoreBootstrap) {
73 Jmsg0(jcr, M_FATAL, 0, _("Cannot restore without bootstrap file.\n"));
74 restore_cleanup(jcr, JS_ErrorTerminated);
79 /* Print Job Start message */
80 Jmsg(jcr, M_INFO, 0, _("Start Restore Job %s\n"), jcr->Job);
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.
88 Dmsg0(10, "Open connection with storage daemon\n");
89 set_jcr_job_status(jcr, JS_WaitSD);
91 * Start conversation with Storage daemon
93 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
94 restore_cleanup(jcr, JS_ErrorTerminated);
98 * Now start a job with the Storage daemon
100 if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL)) {
101 restore_cleanup(jcr, JS_ErrorTerminated);
104 if (!bnet_fsend(jcr->store_bsock, "run")) {
108 * Now start a Storage daemon message thread
110 if (!start_storage_daemon_message_thread(jcr)) {
111 restore_cleanup(jcr, JS_ErrorTerminated);
114 Dmsg0(50, "Storage daemon connection OK\n");
118 * Start conversation with File daemon
120 set_jcr_job_status(jcr, JS_WaitFD);
121 if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
122 restore_cleanup(jcr, JS_ErrorTerminated);
126 fd = jcr->file_bsock;
127 set_jcr_job_status(jcr, JS_Running);
130 * send Storage daemon address to the File daemon,
131 * then wait for File daemon to make connection
132 * with Storage daemon.
134 if (jcr->rstore->SDDport == 0) {
135 jcr->rstore->SDDport = jcr->rstore->SDport;
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);
145 * Send the bootstrap file -- what Volumes/files to restore
147 if (!send_bootstrap_file(jcr, fd) ||
148 !response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
149 restore_cleanup(jcr, JS_ErrorTerminated);
154 if (!send_runscripts_commands(jcr)) {
155 restore_cleanup(jcr, JS_ErrorTerminated);
159 /* Send restore command */
160 char replace, *where;
163 if (jcr->replace != 0) {
164 replace = jcr->replace;
165 } else if (jcr->job->replace != 0) {
166 replace = jcr->job->replace;
168 replace = REPLACE_ALWAYS; /* always replace */
171 where = jcr->where; /* override */
172 } else if (jcr->job->RestoreWhere) {
173 where = jcr->job->RestoreWhere; /* no override take from job */
175 where = ∅ /* None */
177 jcr->prefix_links = jcr->job->PrefixLinks;
179 bnet_fsend(fd, restorecmd, replace, jcr->prefix_links, where);
180 unbash_spaces(where);
182 if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) {
183 restore_cleanup(jcr, JS_ErrorTerminated);
187 /* Wait for Job Termination */
188 int stat = wait_for_job_termination(jcr);
189 restore_cleanup(jcr, stat);
194 bool do_restore_init(JCR *jcr)
201 * Release resources allocated during restore.
204 void restore_cleanup(JCR *jcr, int TermCode)
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;
213 Dmsg0(20, "In restore_cleanup\n");
214 dequeue_messages(jcr); /* display any queued messages */
215 set_jcr_job_status(jcr, TermCode);
217 if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
218 unlink(jcr->RestoreBootstrap);
219 jcr->unlink_bsr = false;
222 update_job_end_record(jcr);
224 msg_type = M_INFO; /* by default INFO message */
227 if (jcr->ExpectedFiles > jcr->jr.JobFiles) {
228 term_msg = _("Restore OK -- warning file count mismatch");
230 term_msg = _("Restore OK");
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);
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);
254 term_msg = term_code;
255 sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
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));
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));
272 Jmsg(jcr, msg_type, 0, _("Bacula %s (%s): %s\n"
278 " Files Expected: %s\n"
279 " Files Restored: %s\n"
280 " Bytes Restored: %s\n"
283 " FD termination status: %s\n"
284 " SD termination status: %s\n"
285 " Termination: %s\n\n"),
291 jcr->client->hdr.name,
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),
303 Dmsg0(20, "Leaving restore_cleanup\n");