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, NULL)) {
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 * send Storage daemon address to the File daemon,
124 * then wait for File daemon to make connection
125 * with Storage daemon.
127 if (jcr->store->SDDport == 0) {
128 jcr->store->SDDport = jcr->store->SDport;
130 bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport);
131 Dmsg1(6, "dird>filed: %s\n", fd->msg);
132 if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
133 restore_cleanup(jcr, JS_ErrorTerminated);
138 * Send the bootstrap file -- what Volumes/files to restore
140 if (!send_bootstrap_file(jcr)) {
141 restore_cleanup(jcr, JS_ErrorTerminated);
146 if (!send_run_before_and_after_commands(jcr)) {
147 restore_cleanup(jcr, JS_ErrorTerminated);
151 /* Send restore command */
152 char replace, *where;
155 if (jcr->replace != 0) {
156 replace = jcr->replace;
157 } else if (jcr->job->replace != 0) {
158 replace = jcr->job->replace;
160 replace = REPLACE_ALWAYS; /* always replace */
163 where = jcr->where; /* override */
164 } else if (jcr->job->RestoreWhere) {
165 where = jcr->job->RestoreWhere; /* no override take from job */
167 where = ∅ /* None */
169 jcr->prefix_links = jcr->job->PrefixLinks;
171 bnet_fsend(fd, restorecmd, replace, jcr->prefix_links, where);
172 unbash_spaces(where);
174 if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) {
175 restore_cleanup(jcr, JS_ErrorTerminated);
179 /* Wait for Job Termination */
180 int stat = wait_for_job_termination(jcr);
181 restore_cleanup(jcr, stat);
186 bool do_restore_init(JCR *jcr)
192 * Release resources allocated during restore.
195 void restore_cleanup(JCR *jcr, int TermCode)
197 char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
198 char ec1[30], ec2[30], ec3[30];
199 char term_code[100], fd_term_msg[100], sd_term_msg[100];
200 const char *term_msg;
204 Dmsg0(20, "In restore_cleanup\n");
205 dequeue_messages(jcr); /* display any queued messages */
206 set_jcr_job_status(jcr, TermCode);
208 if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
209 unlink(jcr->RestoreBootstrap);
210 jcr->unlink_bsr = false;
213 update_job_end_record(jcr);
215 msg_type = M_INFO; /* by default INFO message */
218 if (jcr->ExpectedFiles > jcr->jr.JobFiles) {
219 term_msg = _("Restore OK -- warning file count mismatch");
221 term_msg = _("Restore OK");
225 case JS_ErrorTerminated:
226 term_msg = _("*** Restore Error ***");
227 msg_type = M_ERROR; /* Generate error message */
228 if (jcr->store_bsock) {
229 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
230 if (jcr->SD_msg_chan) {
231 pthread_cancel(jcr->SD_msg_chan);
236 term_msg = _("Restore Canceled");
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 = term_code;
246 sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
249 bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
250 bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
251 if (jcr->jr.EndTime - jcr->jr.StartTime > 0) {
252 kbps = (double)jcr->jr.JobBytes / (1000 * (jcr->jr.EndTime - jcr->jr.StartTime));
260 jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
261 jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
263 Jmsg(jcr, msg_type, 0, _("Bacula %s (%s): %s\n"
269 " Files Expected: %s\n"
270 " Files Restored: %s\n"
271 " Bytes Restored: %s\n"
274 " FD termination status: %s\n"
275 " SD termination status: %s\n"
276 " Termination: %s\n\n"),
282 jcr->client->hdr.name,
285 edit_uint64_with_commas((uint64_t)jcr->ExpectedFiles, ec1),
286 edit_uint64_with_commas((uint64_t)jcr->jr.JobFiles, ec2),
287 edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
294 Dmsg0(20, "Leaving restore_cleanup\n");