]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/restore.c
Add jcr to DB arguments
[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-2003 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 replace=%c 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 static char EndRestore[]  = "2800 End Job TermCode=%d JobFiles=%u JobBytes=%" lld "\n";
57
58 /* Forward referenced functions */
59 static void restore_cleanup(JCR *jcr, int status);
60 static int send_bootstrap_file(JCR *jcr);
61
62 /* External functions */
63
64 /* 
65  * Do a restore of the specified files
66  *    
67  *  Returns:  0 on failure
68  *            1 on success
69  */
70 int do_restore(JCR *jcr) 
71 {
72    BSOCK   *fd;
73    JOB_DBR rjr;                       /* restore job record */
74    int ok = FALSE;
75
76
77    if (!get_or_create_client_record(jcr)) {
78       restore_cleanup(jcr, JS_ErrorTerminated);
79       return 0;
80    }
81
82    memset(&rjr, 0, sizeof(rjr));
83    jcr->jr.Level = 'F';            /* Full restore */
84    jcr->jr.StartTime = jcr->start_time;
85    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
86       Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
87       restore_cleanup(jcr, JS_ErrorTerminated);
88       return 0;
89    }
90    Dmsg0(20, "Updated job start record\n");
91    jcr->fname = (char *) get_pool_memory(PM_FNAME);
92
93    Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
94
95    /* 
96     * The following code is kept temporarily for compatibility.
97     * It is the predecessor to the Bootstrap file.
98     */
99    if (!jcr->RestoreBootstrap) {
100       /*
101        * Find Job Record for Files to be restored
102        */
103       if (jcr->RestoreJobId != 0) {
104          rjr.JobId = jcr->RestoreJobId;     /* specified by UA */
105       } else {
106          rjr.JobId = jcr->job->RestoreJobId; /* specified by Job Resource */
107       }
108       if (!db_get_job_record(jcr, jcr->db, &rjr)) {
109          Jmsg2(jcr, M_FATAL, 0, _("Cannot get job record id=%d %s"), rjr.JobId,
110             db_strerror(jcr->db));
111          restore_cleanup(jcr, JS_ErrorTerminated);
112          return 0;
113       }
114
115       /*
116        * Now find the Volumes we will need for the Restore
117        */
118       jcr->VolumeName[0] = 0;
119       if (!db_get_job_volume_names(jcr, jcr->db, rjr.JobId, &jcr->VolumeName) ||
120            jcr->VolumeName[0] == 0) {
121          Jmsg(jcr, M_FATAL, 0, _("Cannot find Volume Name for restore Job %d. %s"), 
122             rjr.JobId, db_strerror(jcr->db));
123          restore_cleanup(jcr, JS_ErrorTerminated);
124          return 0;
125       }
126       Dmsg1(20, "Got job Volume Names: %s\n", jcr->VolumeName);
127    }
128       
129
130    /* Print Job Start message */
131    Jmsg(jcr, M_INFO, 0, _("Start Restore Job %s\n"), jcr->Job);
132
133    /*
134     * Open a message channel connection with the Storage
135     * daemon. This is to let him know that our client
136     * will be contacting him for a backup  session.
137     *
138     */
139    Dmsg0(10, "Open connection with storage daemon\n");
140    set_jcr_job_status(jcr, JS_Blocked);
141    /*
142     * Start conversation with Storage daemon  
143     */
144    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
145       restore_cleanup(jcr, JS_ErrorTerminated);
146       return 0;
147    }
148    /*
149     * Now start a job with the Storage daemon
150     */
151    if (!start_storage_daemon_job(jcr)) {
152       restore_cleanup(jcr, JS_ErrorTerminated);
153       return 0;
154    }
155    /*
156     * Now start a Storage daemon message thread
157     */
158    if (!start_storage_daemon_message_thread(jcr)) {
159       restore_cleanup(jcr, JS_ErrorTerminated);
160       return 0;
161    }
162    Dmsg0(50, "Storage daemon connection OK\n");
163
164    /* 
165     * Start conversation with File daemon  
166     */
167    if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
168       restore_cleanup(jcr, JS_ErrorTerminated);
169       return 0;
170    }
171
172    fd = jcr->file_bsock;
173    set_jcr_job_status(jcr, JS_Running);
174
175    if (!send_include_list(jcr)) {
176       restore_cleanup(jcr, JS_ErrorTerminated);
177       return 0;
178    }
179
180    if (!send_exclude_list(jcr)) {
181       restore_cleanup(jcr, JS_ErrorTerminated);
182       return 0;
183    }
184
185
186    /* 
187     * send Storage daemon address to the File daemon,
188     *   then wait for File daemon to make connection
189     *   with Storage daemon.
190     */
191    set_jcr_job_status(jcr, JS_Blocked);
192    if (jcr->store->SDDport == 0) {
193       jcr->store->SDDport = jcr->store->SDport;
194    }
195    bnet_fsend(fd, storaddr, jcr->store->address, jcr->store->SDDport);
196    Dmsg1(6, "dird>filed: %s\n", fd->msg);
197    if (!response(fd, OKstore, "Storage")) {
198       restore_cleanup(jcr, JS_ErrorTerminated);
199       return 0;
200    }
201    set_jcr_job_status(jcr, JS_Running);
202
203    /* 
204     * Send the bootstrap file -- what Volumes/files to restore
205     */
206    if (!send_bootstrap_file(jcr)) {
207       restore_cleanup(jcr, JS_ErrorTerminated);
208       return 0;
209    }
210
211    /* 
212     * The following code is deprecated   
213     */
214    if (!jcr->RestoreBootstrap) {
215       /*
216        * Pass the VolSessionId, VolSessionTime, Start and
217        * end File and Blocks on the session command.
218        */
219       bnet_fsend(fd, sessioncmd, 
220                 jcr->VolumeName,
221                 rjr.VolSessionId, rjr.VolSessionTime, 
222                 rjr.StartFile, rjr.EndFile, rjr.StartBlock, 
223                 rjr.EndBlock);
224       if (!response(fd, OKsession, "Session")) {
225          restore_cleanup(jcr, JS_ErrorTerminated);
226          return 0;
227       }
228    }
229
230    /* Send restore command */
231    char replace, *where;
232
233    if (jcr->replace != 0) {
234       replace = jcr->replace;
235    } else if (jcr->job->replace != 0) {
236       replace = jcr->job->replace;
237    } else {
238       replace = REPLACE_ALWAYS;       /* always replace */
239    }
240    if (jcr->RestoreWhere) {
241       where = jcr->RestoreWhere;      /* override */
242    } else if (jcr->job->RestoreWhere) {
243       where = jcr->job->RestoreWhere; /* no override take from job */
244    } else {
245       where = "";                     /* None */
246    }
247    bash_spaces(where);
248    bnet_fsend(fd, restorecmd, replace, where);
249    unbash_spaces(where);
250
251    if (!response(fd, OKrestore, "Restore")) {
252       restore_cleanup(jcr, JS_ErrorTerminated);
253       return 0;
254    }
255
256    /* Wait for Job Termination */
257    Dmsg0(20, "wait for job termination\n");
258    while (bget_msg(fd, 0) >= 0) {
259       Dmsg1(100, "dird<filed: %s\n", fd->msg);
260       if (sscanf(fd->msg, EndRestore, &jcr->FDJobStatus, &jcr->JobFiles,
261           &jcr->JobBytes) == 3) {
262          ok = TRUE;
263       }
264    }
265
266    restore_cleanup(jcr, ok?jcr->FDJobStatus:JS_ErrorTerminated);
267
268    return 1;
269 }
270
271 /*
272  * Release resources allocated during restore.
273  *
274  */
275 static void restore_cleanup(JCR *jcr, int TermCode)
276 {
277    char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
278    char ec1[30], ec2[30];
279    char term_code[100];
280    char *term_msg;
281    int msg_type;
282    double kbps;
283
284    Dmsg0(20, "In restore_cleanup\n");
285    set_jcr_job_status(jcr, TermCode);
286
287    update_job_end_record(jcr);
288
289    msg_type = M_INFO;                 /* by default INFO message */
290    switch (TermCode) {
291       case JS_Terminated:
292          term_msg = _("Restore OK");
293          break;
294       case JS_FatalError:
295       case JS_ErrorTerminated:
296          term_msg = _("*** Restore Error ***"); 
297          msg_type = M_ERROR;          /* Generate error message */
298          if (jcr->store_bsock) {
299             bnet_sig(jcr->store_bsock, BNET_TERMINATE);
300             pthread_cancel(jcr->SD_msg_chan);
301          }
302          break;
303       case JS_Cancelled:
304          term_msg = _("Restore Cancelled");
305          if (jcr->store_bsock) {
306             bnet_sig(jcr->store_bsock, BNET_TERMINATE);
307             pthread_cancel(jcr->SD_msg_chan);
308          }
309          break;
310       default:
311          term_msg = term_code;
312          sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
313          break;
314    }
315    bstrftime(sdt, sizeof(sdt), jcr->jr.StartTime);
316    bstrftime(edt, sizeof(edt), jcr->jr.EndTime);
317    kbps = (double)jcr->jr.JobBytes / (1000 * (jcr->jr.EndTime - jcr->jr.StartTime));
318
319    Jmsg(jcr, msg_type, 0, _("Bacula " VERSION " (" LSMDATE "): %s\n\
320 JobId:                  %d\n\
321 Job:                    %s\n\
322 Client:                 %s\n\
323 Start time:             %s\n\
324 End time:               %s\n\
325 Files Restored:         %s\n\
326 Bytes Restored:         %s\n\
327 Rate:                   %.1f KB/s\n\
328 Termination:            %s\n\n"),
329         edt,
330         jcr->jr.JobId,
331         jcr->jr.Job,
332         jcr->client->hdr.name,
333         sdt,
334         edt,
335         edit_uint64_with_commas((uint64_t)jcr->jr.JobFiles, ec1),
336         edit_uint64_with_commas(jcr->jr.JobBytes, ec2),
337         (float)kbps,
338         term_msg);
339
340    Dmsg0(20, "Leaving restore_cleanup\n");
341 }
342
343 static int send_bootstrap_file(JCR *jcr)
344 {
345    FILE *bs;
346    char buf[1000];
347    BSOCK *fd = jcr->file_bsock;
348    char *bootstrap = "bootstrap\n";
349
350    Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
351    if (!jcr->RestoreBootstrap) {
352       return 1;
353    }
354    bs = fopen(jcr->RestoreBootstrap, "r");
355    if (!bs) {
356       Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"), 
357          jcr->RestoreBootstrap, strerror(errno));
358       set_jcr_job_status(jcr, JS_ErrorTerminated);
359       return 0;
360    }
361    strcpy(fd->msg, bootstrap);  
362    fd->msglen = strlen(fd->msg);
363    bnet_send(fd);
364    while (fgets(buf, sizeof(buf), bs)) {
365       fd->msglen = Mmsg(&fd->msg, "%s", buf);
366       bnet_send(fd);       
367    }
368    bnet_sig(fd, BNET_EOD);
369    fclose(bs);
370    if (!response(fd, OKbootstrap, "Bootstrap")) {
371       set_jcr_job_status(jcr, JS_ErrorTerminated);
372       return 0;
373    }
374    return 1;
375 }