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 memset(&rjr, 0, sizeof(rjr));
60 jcr->jr.JobLevel = L_FULL; /* Full restore */
61 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
62 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
63 restore_cleanup(jcr, JS_ErrorTerminated);
66 Dmsg0(20, "Updated job start record\n");
68 Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
70 if (!jcr->RestoreBootstrap) {
71 Jmsg0(jcr, M_FATAL, 0, _("Cannot restore without bootstrap file.\n"));
72 restore_cleanup(jcr, JS_ErrorTerminated);
77 /* Print Job Start message */
78 Jmsg(jcr, M_INFO, 0, _("Start Restore Job %s\n"), jcr->Job);
81 * Open a message channel connection with the Storage
82 * daemon. This is to let him know that our client
83 * will be contacting him for a backup session.
86 Dmsg0(10, "Open connection with storage daemon\n");
87 set_jcr_job_status(jcr, JS_WaitSD);
89 * Start conversation with Storage daemon
91 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
92 restore_cleanup(jcr, JS_ErrorTerminated);
96 * Now start a job with the Storage daemon
98 if (!start_storage_daemon_job(jcr, jcr->storage, NULL)) {
99 restore_cleanup(jcr, JS_ErrorTerminated);
103 * Now start a Storage daemon message thread
105 if (!start_storage_daemon_message_thread(jcr)) {
106 restore_cleanup(jcr, JS_ErrorTerminated);
109 Dmsg0(50, "Storage daemon connection OK\n");
111 if (!bnet_fsend(jcr->store_bsock, "run")) {
116 * Start conversation with File daemon
118 set_jcr_job_status(jcr, JS_WaitFD);
119 if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
120 restore_cleanup(jcr, JS_ErrorTerminated);
124 fd = jcr->file_bsock;
125 set_jcr_job_status(jcr, JS_Running);
128 * send Storage daemon address to the File daemon,
129 * then wait for File daemon to make connection
130 * with Storage daemon.
132 if (jcr->store->SDDport == 0) {
133 jcr->store->SDDport = jcr->store->SDport;
135 bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport);
136 Dmsg1(6, "dird>filed: %s\n", fd->msg);
137 if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
138 restore_cleanup(jcr, JS_ErrorTerminated);
143 * Send the bootstrap file -- what Volumes/files to restore
145 if (!send_bootstrap_file(jcr, fd) ||
146 !response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
147 restore_cleanup(jcr, JS_ErrorTerminated);
152 if (!send_run_before_and_after_commands(jcr)) {
153 restore_cleanup(jcr, JS_ErrorTerminated);
157 /* Send restore command */
158 char replace, *where;
161 if (jcr->replace != 0) {
162 replace = jcr->replace;
163 } else if (jcr->job->replace != 0) {
164 replace = jcr->job->replace;
166 replace = REPLACE_ALWAYS; /* always replace */
169 where = jcr->where; /* override */
170 } else if (jcr->job->RestoreWhere) {
171 where = jcr->job->RestoreWhere; /* no override take from job */
173 where = ∅ /* None */
175 jcr->prefix_links = jcr->job->PrefixLinks;
177 bnet_fsend(fd, restorecmd, replace, jcr->prefix_links, where);
178 unbash_spaces(where);
180 if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) {
181 restore_cleanup(jcr, JS_ErrorTerminated);
185 /* Wait for Job Termination */
186 int stat = wait_for_job_termination(jcr);
187 restore_cleanup(jcr, stat);
192 bool do_restore_init(JCR *jcr)
198 * Release resources allocated during restore.
201 void restore_cleanup(JCR *jcr, int TermCode)
203 char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
204 char ec1[30], ec2[30], ec3[30];
205 char term_code[100], fd_term_msg[100], sd_term_msg[100];
206 const char *term_msg;
210 Dmsg0(20, "In restore_cleanup\n");
211 dequeue_messages(jcr); /* display any queued messages */
212 set_jcr_job_status(jcr, TermCode);
214 if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
215 unlink(jcr->RestoreBootstrap);
216 jcr->unlink_bsr = false;
219 update_job_end_record(jcr);
221 msg_type = M_INFO; /* by default INFO message */
224 if (jcr->ExpectedFiles > jcr->jr.JobFiles) {
225 term_msg = _("Restore OK -- warning file count mismatch");
227 term_msg = _("Restore OK");
231 case JS_ErrorTerminated:
232 term_msg = _("*** Restore Error ***");
233 msg_type = M_ERROR; /* Generate error message */
234 if (jcr->store_bsock) {
235 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
236 if (jcr->SD_msg_chan) {
237 pthread_cancel(jcr->SD_msg_chan);
242 term_msg = _("Restore Canceled");
243 if (jcr->store_bsock) {
244 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
245 if (jcr->SD_msg_chan) {
246 pthread_cancel(jcr->SD_msg_chan);
251 term_msg = term_code;
252 sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
255 bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
256 bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
257 if (jcr->jr.EndTime - jcr->jr.StartTime > 0) {
258 kbps = (double)jcr->jr.JobBytes / (1000 * (jcr->jr.EndTime - jcr->jr.StartTime));
266 jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
267 jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
269 Jmsg(jcr, msg_type, 0, _("Bacula %s (%s): %s\n"
275 " Files Expected: %s\n"
276 " Files Restored: %s\n"
277 " Bytes Restored: %s\n"
280 " FD termination status: %s\n"
281 " SD termination status: %s\n"
282 " Termination: %s\n\n"),
288 jcr->client->hdr.name,
291 edit_uint64_with_commas((uint64_t)jcr->ExpectedFiles, ec1),
292 edit_uint64_with_commas((uint64_t)jcr->jr.JobFiles, ec2),
293 edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
300 Dmsg0(20, "Leaving restore_cleanup\n");