3 * Bacula Director -- restore.c -- responsible for restoring files
5 * Kern Sibbald, November MM
7 * This routine is run as a separate thread. There may be more
8 * work to be done to make it totally reentrant!!!!
10 * Current implementation is Catalog verification only (i.e. no
11 * verification versus tape).
13 * Basic tasks done here:
15 * Open Message Channel with Storage daemon to tell him a job will be starting.
16 * Open connection with File daemon and pass him commands
18 * Update the DB according to what files where restored????
24 Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
26 This program is free software; you can redistribute it and/or
27 modify it under the terms of the GNU General Public License as
28 published by the Free Software Foundation; either version 2 of
29 the License, or (at your option) any later version.
31 This program is distributed in the hope that it will be useful,
32 but WITHOUT ANY WARRANTY; without even the implied warranty of
33 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
34 General Public License for more details.
36 You should have received a copy of the GNU General Public
37 License along with this program; if not, write to the Free
38 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
46 /* Commands sent to File daemon */
47 static char restorecmd[] = "restore where=%s\n";
48 static char storaddr[] = "storage address=%s port=%d\n";
49 static char sessioncmd[] = "session %s %ld %ld %ld %ld %ld %ld\n";
51 /* Responses received from File daemon */
52 static char OKrestore[] = "2000 OK restore\n";
53 static char OKstore[] = "2000 OK storage\n";
54 static char OKsession[] = "2000 OK session\n";
55 static char OKbootstrap[] = "2000 OK bootstrap\n";
56 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u JobBytes=%" lld "\n";
58 /* Forward referenced functions */
59 static void restore_cleanup(JCR *jcr, int status);
60 static int send_bootstrap_file(JCR *jcr);
62 /* External functions */
65 * Do a restore of the specified files
67 * Returns: 0 on failure
70 int do_restore(JCR *jcr)
72 char dt[MAX_TIME_LENGTH];
74 JOB_DBR rjr; /* restore job record */
78 if (!get_or_create_client_record(jcr)) {
79 restore_cleanup(jcr, JS_ErrorTerminated);
83 memset(&rjr, 0, sizeof(rjr));
84 jcr->jr.Level = 'F'; /* Full restore */
85 jcr->jr.StartTime = jcr->start_time;
86 if (!db_update_job_start_record(jcr->db, &jcr->jr)) {
87 Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
88 restore_cleanup(jcr, JS_ErrorTerminated);
91 Dmsg0(20, "Updated job start record\n");
92 jcr->fname = (char *) get_pool_memory(PM_FNAME);
94 Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
97 * The following code is kept temporarily for compatibility.
98 * It is the predecessor to the Bootstrap file.
100 if (!jcr->RestoreBootstrap) {
102 * Find Job Record for Files to be restored
104 if (jcr->RestoreJobId != 0) {
105 rjr.JobId = jcr->RestoreJobId; /* specified by UA */
107 rjr.JobId = jcr->job->RestoreJobId; /* specified by Job Resource */
109 if (!db_get_job_record(jcr->db, &rjr)) {
110 Jmsg2(jcr, M_FATAL, 0, _("Cannot get job record id=%d %s"), rjr.JobId,
111 db_strerror(jcr->db));
112 restore_cleanup(jcr, JS_ErrorTerminated);
117 * Now find the Volumes we will need for the Restore
119 jcr->VolumeName[0] = 0;
120 if (!db_get_job_volume_names(jcr->db, rjr.JobId, &jcr->VolumeName) ||
121 jcr->VolumeName[0] == 0) {
122 Jmsg(jcr, M_FATAL, 0, _("Cannot find Volume Name for restore Job %d. %s"),
123 rjr.JobId, db_strerror(jcr->db));
124 restore_cleanup(jcr, JS_ErrorTerminated);
127 Dmsg1(20, "Got job Volume Names: %s\n", jcr->VolumeName);
131 /* Print Job Start message */
132 bstrftime(dt, sizeof(dt), jcr->start_time);
133 Jmsg(jcr, M_INFO, 0, _("%s Start Restore Job %s Name=%s, Client=%s, FileSet=%s\n"),
134 dt, jcr->Job, jcr->job->hdr.name, jcr->client->hdr.name,
135 jcr->fileset->hdr.name);
138 * Open a message channel connection with the Storage
139 * daemon. This is to let him know that our client
140 * will be contacting him for a backup session.
143 Dmsg0(10, "Open connection with storage daemon\n");
144 jcr->JobStatus = JS_Blocked;
146 * Start conversation with Storage daemon
148 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
149 restore_cleanup(jcr, JS_ErrorTerminated);
153 * Now start a job with the Storage daemon
155 if (!start_storage_daemon_job(jcr)) {
156 restore_cleanup(jcr, JS_ErrorTerminated);
160 * Now start a Storage daemon message thread
162 if (!start_storage_daemon_message_thread(jcr)) {
163 restore_cleanup(jcr, JS_ErrorTerminated);
166 Dmsg0(50, "Storage daemon connection OK\n");
169 * Start conversation with File daemon
171 if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
172 restore_cleanup(jcr, JS_ErrorTerminated);
176 fd = jcr->file_bsock;
177 jcr->JobStatus = JS_Running;
179 if (!send_include_list(jcr)) {
180 restore_cleanup(jcr, JS_ErrorTerminated);
184 if (!send_exclude_list(jcr)) {
185 restore_cleanup(jcr, JS_ErrorTerminated);
191 * send Storage daemon address to the File daemon,
192 * then wait for File daemon to make connection
193 * with Storage daemon.
195 jcr->JobStatus = JS_Blocked;
196 if (jcr->store->SDDport == 0) {
197 jcr->store->SDDport = jcr->store->SDport;
199 bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport);
200 Dmsg1(6, "dird>filed: %s\n", fd->msg);
201 if (!response(fd, OKstore, "Storage")) {
202 restore_cleanup(jcr, JS_ErrorTerminated);
205 jcr->JobStatus = JS_Running;
208 * Send the bootstrap file -- what Volumes/files to restore
210 if (!send_bootstrap_file(jcr)) {
211 restore_cleanup(jcr, JS_ErrorTerminated);
216 * The following code is deprecated
218 if (!jcr->RestoreBootstrap) {
220 * Pass the VolSessionId, VolSessionTime, Start and
221 * end File and Blocks on the session command.
223 bnet_fsend(fd, sessioncmd,
225 rjr.VolSessionId, rjr.VolSessionTime,
226 rjr.StartFile, rjr.EndFile, rjr.StartBlock,
228 if (!response(fd, OKsession, "Session")) {
229 restore_cleanup(jcr, JS_ErrorTerminated);
234 /* Send restore command */
235 if (jcr->RestoreWhere) {
236 bnet_fsend(fd, restorecmd, jcr->RestoreWhere);
238 bnet_fsend(fd, restorecmd,
239 jcr->job->RestoreWhere ? jcr->job->RestoreWhere : "");
241 if (!response(fd, OKrestore, "Restore")) {
242 restore_cleanup(jcr, JS_ErrorTerminated);
246 /* Wait for Job Termination */
247 /*** ****FIXME**** get job termination status */
248 Dmsg0(20, "wait for job termination\n");
249 while (bget_msg(fd, 0) > 0) {
250 Dmsg1(100, "dird<filed: %s\n", fd->msg);
251 if (sscanf(fd->msg, EndJob, &jcr->JobStatus, &jcr->JobFiles,
252 &jcr->JobBytes) == 3) {
257 restore_cleanup(jcr, ok?jcr->JobStatus:JS_ErrorTerminated);
263 * Release resources allocated during restore.
266 static void restore_cleanup(JCR *jcr, int TermCode)
268 char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
269 char ec1[30], ec2[30];
275 Dmsg0(20, "In restore_cleanup\n");
276 jcr->JobStatus = TermCode;
278 update_job_end_record(jcr);
280 msg_type = M_INFO; /* by default INFO message */
283 term_msg = _("Restore OK");
286 case JS_ErrorTerminated:
287 term_msg = _("*** Restore Error ***");
288 msg_type = M_ERROR; /* Generate error message */
289 if (jcr->store_bsock) {
290 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
291 pthread_cancel(jcr->SD_msg_chan);
295 term_msg = _("Restore Cancelled");
296 if (jcr->store_bsock) {
297 bnet_sig(jcr->store_bsock, BNET_TERMINATE);
298 pthread_cancel(jcr->SD_msg_chan);
302 term_msg = term_code;
303 sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
306 bstrftime(sdt, sizeof(sdt), jcr->jr.StartTime);
307 bstrftime(edt, sizeof(edt), jcr->jr.EndTime);
308 kbps = (double)jcr->jr.JobBytes / (1000 * (jcr->jr.EndTime - jcr->jr.StartTime));
310 Jmsg(jcr, msg_type, 0, _("%s\n\
316 Files Restored: %s\n\
317 Bytes Restored: %s\n\
319 Termination: %s\n\n"),
323 jcr->client->hdr.name,
326 edit_uint64_with_commas(jcr->jr.JobFiles, ec1),
327 edit_uint64_with_commas(jcr->jr.JobBytes, ec2),
331 Dmsg0(20, "Leaving restore_cleanup\n");
334 static int send_bootstrap_file(JCR *jcr)
338 BSOCK *fd = jcr->file_bsock;
339 char *bootstrap = "bootstrap\n";
341 Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
342 if (!jcr->RestoreBootstrap) {
345 bs = fopen(jcr->RestoreBootstrap, "r");
347 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
348 jcr->RestoreBootstrap, strerror(errno));
349 jcr->JobStatus = JS_ErrorTerminated;
352 strcpy(fd->msg, bootstrap);
353 fd->msglen = strlen(fd->msg);
355 while (fgets(buf, sizeof(buf), bs)) {
356 fd->msglen = Mmsg(&fd->msg, "%s", buf);
359 bnet_sig(fd, BNET_EOD);
361 if (!response(fd, OKbootstrap, "Bootstrap")) {
362 jcr->JobStatus = JS_ErrorTerminated;