]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/restore.c
Basic Restore bootstrap implemented -- kes25Jun02
[bacula/bacula] / bacula / src / dird / restore.c
1 /*
2  *
3  *   Bacula Director -- restore.c -- responsible for restoring files
4  *
5  *     Kern Sibbald, November MM
6  *
7  *    This routine is run as a separate thread.  There may be more
8  *    work to be done to make it totally reentrant!!!!
9  * 
10  * Current implementation is Catalog verification only (i.e. no
11  *  verification versus tape).
12  *
13  *  Basic tasks done here:
14  *     Open DB
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
17  *       to do the restore.
18  *     Update the DB according to what files where restored????
19  *
20  *   Version $Id$
21  */
22
23 /*
24    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
25
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.
30
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.
35
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,
39    MA 02111-1307, USA.
40
41  */
42
43 #include "bacula.h"
44 #include "dird.h"
45
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";  
50
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
57 /* Forward referenced functions */
58 static void restore_cleanup(JCR *jcr, int status);
59 static int send_bootstrap_file(JCR *jcr);
60
61 /* External functions */
62
63 /* 
64  * Do a restore of the specified files
65  *    
66  *  Returns:  0 on failure
67  *            1 on success
68  */
69 int do_restore(JCR *jcr) 
70 {
71    char dt[MAX_TIME_LENGTH];
72    BSOCK   *fd;
73    JOB_DBR rjr;                       /* restore job record */
74
75
76    if (!get_or_create_client_record(jcr)) {
77       restore_cleanup(jcr, JS_ErrorTerminated);
78       return 0;
79    }
80
81    memset(&rjr, 0, sizeof(rjr));
82    jcr->jr.Level = 'F';            /* Full restore */
83    jcr->jr.StartTime = jcr->start_time;
84    if (!db_update_job_start_record(jcr->db, &jcr->jr)) {
85       Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
86       restore_cleanup(jcr, JS_ErrorTerminated);
87       return 0;
88    }
89    Dmsg0(20, "Updated job start record\n");
90    jcr->fname = (char *) get_pool_memory(PM_FNAME);
91
92    Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
93
94    /* 
95     * The following code is kept temporarily for compatibility.
96     * It is the predecessor to the Bootstrap file.
97     */
98    if (!jcr->RestoreBootstrap) {
99       /*
100        * Find Job Record for Files to be restored
101        */
102       if (jcr->RestoreJobId != 0) {
103          rjr.JobId = jcr->RestoreJobId;     /* specified by UA */
104       } else {
105          rjr.JobId = jcr->job->RestoreJobId; /* specified by Job Resource */
106       }
107       if (!db_get_job_record(jcr->db, &rjr)) {
108          Jmsg2(jcr, M_FATAL, 0, _("Cannot get job record id=%d %s"), rjr.JobId,
109             db_strerror(jcr->db));
110          restore_cleanup(jcr, JS_ErrorTerminated);
111          return 0;
112       }
113
114       /*
115        * Now find the Volumes we will need for the Restore
116        */
117       jcr->VolumeName[0] = 0;
118       if (!db_get_job_volume_names(jcr->db, rjr.JobId, jcr->VolumeName) ||
119            jcr->VolumeName[0] == 0) {
120          Jmsg(jcr, M_FATAL, 0, _("Cannot find Volume Name for restore Job %d. %s"), 
121             rjr.JobId, db_strerror(jcr->db));
122          restore_cleanup(jcr, JS_ErrorTerminated);
123          return 0;
124       }
125       Dmsg1(20, "Got job Volume Names: %s\n", jcr->VolumeName);
126    }
127       
128
129    /* Print Job Start message */
130    bstrftime(dt, sizeof(dt), jcr->start_time);
131    Jmsg(jcr, M_INFO, 0, _("%s Start Restore Job %s Name=%s, Client=%s, FileSet=%s\n"), 
132       dt, jcr->Job, jcr->job->hdr.name, jcr->client->hdr.name, 
133       jcr->fileset->hdr.name);
134
135    /*
136     * Open a message channel connection with the Storage
137     * daemon. This is to let him know that our client
138     * will be contacting him for a backup  session.
139     *
140     */
141    Dmsg0(10, "Open connection with storage daemon\n");
142    jcr->JobStatus = JS_Blocked;
143    /*
144     * Start conversation with Storage daemon  
145     */
146    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
147       restore_cleanup(jcr, JS_ErrorTerminated);
148       return 0;
149    }
150    /*
151     * Now start a job with the Storage daemon
152     */
153    if (!start_storage_daemon_job(jcr)) {
154       restore_cleanup(jcr, JS_ErrorTerminated);
155       return 0;
156    }
157    /*
158     * Now start a Storage daemon message thread
159     */
160    if (!start_storage_daemon_message_thread(jcr)) {
161       restore_cleanup(jcr, JS_ErrorTerminated);
162       return 0;
163    }
164    Dmsg0(50, "Storage daemon connection OK\n");
165
166    /* 
167     * Start conversation with File daemon  
168     */
169    if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
170       restore_cleanup(jcr, JS_ErrorTerminated);
171       return 0;
172    }
173
174    fd = jcr->file_bsock;
175    jcr->JobStatus = JS_Running;
176
177    if (!send_include_list(jcr)) {
178       restore_cleanup(jcr, JS_ErrorTerminated);
179       return 0;
180    }
181
182    if (!send_exclude_list(jcr)) {
183       restore_cleanup(jcr, JS_ErrorTerminated);
184       return 0;
185    }
186
187
188    /* 
189     * send Storage daemon address to the File daemon,
190     *   then wait for File daemon to make connection
191     *   with Storage daemon.
192     */
193    jcr->JobStatus = JS_Blocked;
194    if (jcr->store->SDDport == 0) {
195       jcr->store->SDDport = jcr->store->SDport;
196    }
197    bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport);
198    Dmsg1(6, "dird>filed: %s\n", fd->msg);
199    if (!response(fd, OKstore, "Storage")) {
200       restore_cleanup(jcr, JS_ErrorTerminated);
201       return 0;
202    }
203    jcr->JobStatus = JS_Running;
204
205    /* 
206     * Send the bootstrap file -- what Volumes/files to restore
207     */
208    if (!send_bootstrap_file(jcr)) {
209       restore_cleanup(jcr, JS_ErrorTerminated);
210       return 0;
211    }
212
213    /* 
214     * The following code is deprecated   
215     */
216    if (!jcr->RestoreBootstrap) {
217       /*
218        * Pass the VolSessionId, VolSessionTime, Start and
219        * end File and Blocks on the session command.
220        */
221       bnet_fsend(fd, sessioncmd, 
222                 jcr->VolumeName,
223                 rjr.VolSessionId, rjr.VolSessionTime, 
224                 rjr.StartFile, rjr.EndFile, rjr.StartBlock, 
225                 rjr.EndBlock);
226       if (!response(fd, OKsession, "Session")) {
227          restore_cleanup(jcr, JS_ErrorTerminated);
228          return 0;
229       }
230    }
231
232    /* Send restore command */
233    if (jcr->RestoreWhere) {
234       bnet_fsend(fd, restorecmd, jcr->RestoreWhere);
235    } else {
236       bnet_fsend(fd, restorecmd, 
237                  jcr->job->RestoreWhere ? jcr->job->RestoreWhere : "");
238    }
239    if (!response(fd, OKrestore, "Restore")) {
240       restore_cleanup(jcr, JS_ErrorTerminated);
241       return 0;
242    }
243
244    /* Wait for Job Termination */
245    /*** ****FIXME**** get job termination status */
246    Dmsg0(20, "wait for job termination\n");
247    while (bget_msg(fd, 0) >  0) {
248       Dmsg1(0, "dird<filed: %s\n", fd->msg);
249    }
250
251    restore_cleanup(jcr, JS_Terminated);
252
253    return 1;
254 }
255
256 /*
257  * Release resources allocated during restore.
258  *
259  */
260 static void restore_cleanup(JCR *jcr, int status) 
261 {
262    char dt[MAX_TIME_LENGTH];
263
264    Dmsg0(20, "In restore_cleanup\n");
265    jcr->JobStatus = status;
266
267    update_job_end_record(jcr);
268
269    bstrftime(dt, sizeof(dt), jcr->jr.EndTime);
270    Jmsg(jcr, M_INFO, 0, _("%s End Restore Job %s.\n\n"),
271       dt, jcr->Job);
272
273    Dmsg0(20, "Leaving restore_cleanup\n");
274 }
275
276 static int send_bootstrap_file(JCR *jcr)
277 {
278    FILE *bs;
279    char buf[1000];
280    BSOCK *fd = jcr->file_bsock;
281    char *bootstrap = "bootstrap\n";
282
283    Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
284    if (!jcr->RestoreBootstrap) {
285       return 1;
286    }
287    bs = fopen(jcr->RestoreBootstrap, "r");
288    if (!bs) {
289       Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"), 
290          jcr->RestoreBootstrap, strerror(errno));
291       jcr->JobStatus = JS_ErrorTerminated;
292       return 0;
293    }
294    strcpy(fd->msg, bootstrap);  
295    fd->msglen = strlen(fd->msg);
296    bnet_send(fd);
297    while (fgets(buf, sizeof(buf), bs)) {
298       fd->msglen = Mmsg(&fd->msg, "%s", buf);
299       bnet_send(fd);       
300    }
301    bnet_sig(fd, BNET_EOF);
302    fclose(bs);
303    if (!response(fd, OKbootstrap, "Bootstrap")) {
304       jcr->JobStatus = JS_ErrorTerminated;
305       return 0;
306    }
307    return 1;
308 }