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????
23 Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
25 This program is free software; you can redistribute it and/or
26 modify it under the terms of the GNU General Public License as
27 published by the Free Software Foundation; either version 2 of
28 the License, or (at your option) any later version.
30 This program is distributed in the hope that it will be useful,
31 but WITHOUT ANY WARRANTY; without even the implied warranty of
32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33 General Public License for more details.
35 You should have received a copy of the GNU General Public
36 License along with this program; if not, write to the Free
37 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
45 /* Commands sent to File daemon */
46 static char restorecmd[] = "restore where=%s\n";
47 static char storaddr[] = "storage address=%s port=%d\n";
48 static char sessioncmd[] = "session %s %ld %ld %ld %ld %ld %ld\n";
50 /* Responses received from File daemon */
51 static char OKrestore[] = "2000 OK restore\n";
52 static char OKstore[] = "2000 OK storage\n";
53 static char OKsession[] = "2000 OK session\n";
55 /* Forward referenced functions */
56 static void restore_cleanup(JCR *jcr, int status);
58 /* External functions */
61 * Do a restore of the specified files
63 * Returns: 0 on failure
66 int do_restore(JCR *jcr)
68 char dt[MAX_TIME_LENGTH];
70 JOB_DBR rjr; /* restore job record */
74 * Get or Create a client record
76 memset(&cr, 0, sizeof(cr));
77 strcpy(cr.Name, jcr->client->hdr.name);
78 cr.AutoPrune = jcr->client->AutoPrune;
79 cr.FileRetention = jcr->client->FileRetention;
80 cr.JobRetention = jcr->client->JobRetention;
81 if (jcr->client_name) {
82 free(jcr->client_name);
84 jcr->client_name = bstrdup(jcr->client->hdr.name);
85 if (!db_create_client_record(jcr->db, &cr)) {
86 Jmsg(jcr, M_ERROR, 0, _("Could not create Client record. %s"),
87 db_strerror(jcr->db));
88 restore_cleanup(jcr, JS_ErrorTerminated);
91 jcr->jr.ClientId = cr.ClientId;
93 memset(&rjr, 0, sizeof(rjr));
94 jcr->jr.Level = 'F'; /* Full restore */
95 jcr->jr.StartTime = jcr->start_time;
96 if (!db_update_job_start_record(jcr->db, &jcr->jr)) {
97 Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
98 restore_cleanup(jcr, JS_ErrorTerminated);
101 Dmsg0(20, "Updated job start record\n");
102 jcr->fname = (char *) get_pool_memory(PM_FNAME);
104 Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
107 * Find Job Record for Files to be restored
109 if (jcr->RestoreJobId != 0) {
110 rjr.JobId = jcr->RestoreJobId; /* specified by UA */
112 rjr.JobId = jcr->job->RestoreJobId; /* specified by Job Resource */
114 if (!db_get_job_record(jcr->db, &rjr)) {
115 Jmsg2(jcr, M_FATAL, 0, _("Cannot get job record id=%d %s"), rjr.JobId,
116 db_strerror(jcr->db));
117 restore_cleanup(jcr, JS_ErrorTerminated);
120 Dmsg3(20, "Got JobId=%d VolSessId=%ld, VolSesTime=%ld\n",
121 rjr.JobId, rjr.VolSessionId, rjr.VolSessionTime);
122 Dmsg4(20, "StartFile=%ld, EndFile=%ld StartBlock=%ld EndBlock=%ld\n",
123 rjr.StartFile, rjr.EndFile, rjr.StartBlock, rjr.EndBlock);
126 * Now find the Volumes we will need for the Restore
128 jcr->VolumeName[0] = 0;
129 if (!db_get_job_volume_names(jcr->db, rjr.JobId, jcr->VolumeName) ||
130 jcr->VolumeName[0] == 0) {
131 Jmsg(jcr, M_FATAL, 0, _("Cannot find Volume Name for restore Job %d. %s"),
132 rjr.JobId, db_strerror(jcr->db));
133 restore_cleanup(jcr, JS_ErrorTerminated);
136 Dmsg1(20, "Got job Volume Names: %s\n", jcr->VolumeName);
139 /* Print Job Start message */
140 bstrftime(dt, sizeof(dt), jcr->start_time);
141 Jmsg(jcr, M_INFO, 0, _("%s Start Restore Job %s Name=%s, Client=%s, FileSet=%s\n"),
142 dt, jcr->Job, jcr->job->hdr.name, jcr->client->hdr.name,
143 jcr->fileset->hdr.name);
146 * Open a message channel connection with the Storage
147 * daemon. This is to let him know that our client
148 * will be contacting him for a backup session.
151 Dmsg0(10, "Open connection with storage daemon\n");
152 jcr->JobStatus = JS_Blocked;
154 * Start conversation with Storage daemon
156 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
157 restore_cleanup(jcr, JS_ErrorTerminated);
161 * Now start a job with the Storage daemon
163 if (!start_storage_daemon_job(jcr)) {
164 restore_cleanup(jcr, JS_ErrorTerminated);
168 * Now start a Storage daemon message thread
170 if (!start_storage_daemon_message_thread(jcr)) {
171 restore_cleanup(jcr, JS_ErrorTerminated);
174 Dmsg0(50, "Storage daemon connection OK\n");
177 * Start conversation with File daemon
179 if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
180 restore_cleanup(jcr, JS_ErrorTerminated);
184 fd = jcr->file_bsock;
185 jcr->JobStatus = JS_Running;
187 if (!send_include_list(jcr)) {
188 restore_cleanup(jcr, JS_ErrorTerminated);
192 if (!send_exclude_list(jcr)) {
193 restore_cleanup(jcr, JS_ErrorTerminated);
198 * send Storage daemon address to the File daemon,
199 * then wait for File daemon to make connection
200 * with Storage daemon.
202 jcr->JobStatus = JS_Blocked;
203 if (jcr->store->SDDport == 0) {
204 jcr->store->SDDport = jcr->store->SDport;
206 bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport);
207 Dmsg1(6, "dird>filed: %s\n", fd->msg);
208 if (!response(fd, OKstore, "Storage")) {
209 restore_cleanup(jcr, JS_ErrorTerminated);
212 jcr->JobStatus = JS_Running;
215 * Pass the VolSessionId, VolSessionTime, Start and
216 * end File and Blocks on the session command.
218 bnet_fsend(fd, sessioncmd,
220 rjr.VolSessionId, rjr.VolSessionTime,
221 rjr.StartFile, rjr.EndFile, rjr.StartBlock,
223 if (!response(fd, OKsession, "Session")) {
224 restore_cleanup(jcr, JS_ErrorTerminated);
228 /* Send restore command */
229 if (jcr->RestoreWhere) {
230 bnet_fsend(fd, restorecmd, jcr->RestoreWhere);
232 bnet_fsend(fd, restorecmd,
233 jcr->job->RestoreWhere==NULL ? "" : jcr->job->RestoreWhere);
235 if (!response(fd, OKrestore, "Restore")) {
236 restore_cleanup(jcr, JS_ErrorTerminated);
240 /* Wait for Job Termination */
241 /*** ****FIXME**** get job termination data */
242 Dmsg0(20, "wait for job termination\n");
243 while (bget_msg(fd, 0) > 0) {
244 Dmsg1(0, "dird<filed: %s\n", fd->msg);
247 restore_cleanup(jcr, JS_Terminated);
253 * Release resources allocated during restore.
256 static void restore_cleanup(JCR *jcr, int status)
258 char dt[MAX_TIME_LENGTH];
260 Dmsg0(20, "In restore_cleanup\n");
261 if (jcr->jr.EndTime == 0) {
262 jcr->jr.EndTime = time(NULL);
264 jcr->jr.JobStatus = jcr->JobStatus = status;
265 if (!db_update_job_end_record(jcr->db, &jcr->jr)) {
266 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
267 db_strerror(jcr->db));
270 bstrftime(dt, sizeof(dt), jcr->jr.EndTime);
271 Jmsg(jcr, M_INFO, 0, _("%s End Restore Job %s.\n"),
274 Dmsg0(20, "Leaving restore_cleanup\n");