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????
22 Copyright (C) 2000-2003 Kern Sibbald and John Walker
24 This program is free software; you can redistribute it and/or
25 modify it under the terms of the GNU General Public License as
26 published by the Free Software Foundation; either version 2 of
27 the License, or (at your option) any later version.
29 This program is distributed in the hope that it will be useful,
30 but WITHOUT ANY WARRANTY; without even the implied warranty of
31 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
32 General Public License for more details.
34 You should have received a copy of the GNU General Public
35 License along with this program; if not, write to the Free
36 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
44 /* Commands sent to File daemon */
45 static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n";
46 static char storaddr[] = "storage address=%s port=%d ssl=0\n";
47 static char sessioncmd[] = "session %s %ld %ld %ld %ld %ld %ld\n";
49 /* Responses received from File daemon */
50 static char OKrestore[] = "2000 OK restore\n";
51 static char OKstore[] = "2000 OK storage\n";
52 static char OKsession[] = "2000 OK session\n";
54 /* Forward referenced functions */
55 static void restore_cleanup(JCR *jcr, int status);
57 /* External functions */
60 * Do a restore of the specified files
62 * Returns: 0 on failure
65 int do_restore(JCR *jcr)
68 JOB_DBR rjr; /* restore job record */
70 if (!get_or_create_client_record(jcr)) {
71 restore_cleanup(jcr, JS_ErrorTerminated);
75 memset(&rjr, 0, sizeof(rjr));
76 jcr->jr.Level = L_FULL; /* Full restore */
77 jcr->jr.StartTime = jcr->start_time;
78 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
79 Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
80 restore_cleanup(jcr, JS_ErrorTerminated);
83 Dmsg0(20, "Updated job start record\n");
84 jcr->fname = (char *) get_pool_memory(PM_FNAME);
86 Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
89 * The following code is kept temporarily for compatibility.
90 * It is the predecessor to the Bootstrap file.
93 if (!jcr->RestoreBootstrap) {
95 * Find Job Record for Files to be restored
97 if (jcr->RestoreJobId != 0) {
98 rjr.JobId = jcr->RestoreJobId; /* specified by UA */
100 rjr.JobId = jcr->job->RestoreJobId; /* specified by Job Resource */
102 if (!db_get_job_record(jcr, jcr->db, &rjr)) {
103 Jmsg2(jcr, M_FATAL, 0, _("Cannot get job record id=%d %s"), rjr.JobId,
104 db_strerror(jcr->db));
105 restore_cleanup(jcr, JS_ErrorTerminated);
110 * Now find the Volumes we will need for the Restore
112 jcr->VolumeName[0] = 0;
113 if (!db_get_job_volume_names(jcr, jcr->db, rjr.JobId, &jcr->VolumeName) ||
114 jcr->VolumeName[0] == 0) {
115 Jmsg(jcr, M_FATAL, 0, _("Cannot find Volume Name for restore Job %d. %s"),
116 rjr.JobId, db_strerror(jcr->db));
117 restore_cleanup(jcr, JS_ErrorTerminated);
120 Dmsg1(20, "Got job Volume Names: %s\n", jcr->VolumeName);
124 /* Print Job Start message */
125 Jmsg(jcr, M_INFO, 0, _("Start Restore Job %s\n"), jcr->Job);
128 * Open a message channel connection with the Storage
129 * daemon. This is to let him know that our client
130 * will be contacting him for a backup session.
133 Dmsg0(10, "Open connection with storage daemon\n");
134 set_jcr_job_status(jcr, JS_WaitSD);
136 * Start conversation with Storage daemon
138 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
139 restore_cleanup(jcr, JS_ErrorTerminated);
143 * Now start a job with the Storage daemon
145 if (!start_storage_daemon_job(jcr)) {
146 restore_cleanup(jcr, JS_ErrorTerminated);
150 * Now start a Storage daemon message thread
152 if (!start_storage_daemon_message_thread(jcr)) {
153 restore_cleanup(jcr, JS_ErrorTerminated);
156 Dmsg0(50, "Storage daemon connection OK\n");
159 * Start conversation with File daemon
161 set_jcr_job_status(jcr, JS_WaitFD);
162 if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
163 restore_cleanup(jcr, JS_ErrorTerminated);
167 fd = jcr->file_bsock;
168 set_jcr_job_status(jcr, JS_Running);
170 if (!send_include_list(jcr)) {
171 restore_cleanup(jcr, JS_ErrorTerminated);
175 if (!send_exclude_list(jcr)) {
176 restore_cleanup(jcr, JS_ErrorTerminated);
181 * send Storage daemon address to the File daemon,
182 * then wait for File daemon to make connection
183 * with Storage daemon.
185 if (jcr->store->SDDport == 0) {
186 jcr->store->SDDport = jcr->store->SDport;
188 bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport);
189 Dmsg1(6, "dird>filed: %s\n", fd->msg);
190 if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
191 restore_cleanup(jcr, JS_ErrorTerminated);
196 * Send the bootstrap file -- what Volumes/files to restore
198 if (!send_bootstrap_file(jcr)) {
199 restore_cleanup(jcr, JS_ErrorTerminated);
204 * The following code is deprecated
206 if (!jcr->RestoreBootstrap) {
208 * Pass the VolSessionId, VolSessionTime, Start and
209 * end File and Blocks on the session command.
211 bnet_fsend(fd, sessioncmd,
213 rjr.VolSessionId, rjr.VolSessionTime,
214 rjr.StartFile, rjr.EndFile, rjr.StartBlock,
216 if (!response(jcr, fd, OKsession, "Session", DISPLAY_ERROR)) {
217 restore_cleanup(jcr, JS_ErrorTerminated);
222 if (!send_run_before_and_after_commands(jcr)) {
223 restore_cleanup(jcr, JS_ErrorTerminated);
227 /* Send restore command */
228 char replace, *where;
230 if (jcr->replace != 0) {
231 replace = jcr->replace;
232 } else if (jcr->job->replace != 0) {
233 replace = jcr->job->replace;
235 replace = REPLACE_ALWAYS; /* always replace */
238 where = jcr->where; /* override */
239 } else if (jcr->job->RestoreWhere) {
240 where = jcr->job->RestoreWhere; /* no override take from job */
242 where = ""; /* None */
244 jcr->prefix_links = jcr->job->PrefixLinks;
246 bnet_fsend(fd, restorecmd, replace, jcr->prefix_links, where);
247 unbash_spaces(where);
249 if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) {
250 restore_cleanup(jcr, JS_ErrorTerminated);
254 /* Wait for Job Termination */
255 int stat = wait_for_job_termination(jcr);
256 restore_cleanup(jcr, stat);
262 * Release resources allocated during restore.
265 static void restore_cleanup(JCR *jcr, int TermCode)
267 char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
268 char ec1[30], ec2[30], ec3[30];
269 char term_code[100], fd_term_msg[100], sd_term_msg[100];
274 Dmsg0(20, "In restore_cleanup\n");
275 set_jcr_job_status(jcr, TermCode);
277 update_job_end_record(jcr);
279 msg_type = M_INFO; /* by default INFO message */
282 if (jcr->ExpectedFiles > jcr->jr.JobFiles) {
283 term_msg = _("Restore OK -- warning file count mismatch");
285 term_msg = _("Restore OK");
289 case JS_ErrorTerminated:
290 term_msg = _("*** Restore Error ***");
291 msg_type = M_ERROR; /* Generate error message */
292 if (jcr->store_bsock) {
293 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
294 if (jcr->SD_msg_chan) {
295 pthread_cancel(jcr->SD_msg_chan);
300 term_msg = _("Restore Canceled");
301 if (jcr->store_bsock) {
302 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
303 if (jcr->SD_msg_chan) {
304 pthread_cancel(jcr->SD_msg_chan);
309 term_msg = term_code;
310 sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
313 bstrftime(sdt, sizeof(sdt), jcr->jr.StartTime);
314 bstrftime(edt, sizeof(edt), jcr->jr.EndTime);
315 if (jcr->jr.EndTime - jcr->jr.StartTime > 0) {
316 kbps = (double)jcr->jr.JobBytes / (1000 * (jcr->jr.EndTime - jcr->jr.StartTime));
324 jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
325 jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
327 Jmsg(jcr, msg_type, 0, _("Bacula " VERSION " (" LSMDATE "): %s\n\
333 Files Expected: %s\n\
334 Files Restored: %s\n\
335 Bytes Restored: %s\n\
338 FD termination status: %s\n\
339 SD termination status: %s\n\
340 Termination: %s\n\n"),
344 jcr->client->hdr.name,
347 edit_uint64_with_commas((uint64_t)jcr->ExpectedFiles, ec1),
348 edit_uint64_with_commas((uint64_t)jcr->jr.JobFiles, ec2),
349 edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
356 Dmsg0(20, "Leaving restore_cleanup\n");