]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/restore.c
Set job status to running when restore job really starts
[bacula/bacula] / bacula / src / dird / restore.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /**
29  *   Bacula Director -- restore.c -- responsible for restoring files
30  *
31  *     Kern Sibbald, November MM
32  *
33  *    This routine is run as a separate thread.
34  *
35  * Current implementation is Catalog verification only (i.e. no
36  *  verification versus tape).
37  *
38  *  Basic tasks done here:
39  *     Open DB
40  *     Open Message Channel with Storage daemon to tell him a job will be starting.
41  *     Open connection with File daemon and pass him commands
42  *       to do the restore.
43  *     Update the DB according to what files where restored????
44  *
45  */
46
47
48 #include "bacula.h"
49 #include "dird.h"
50
51 /* Commands sent to File daemon */
52 static char restorecmd[]  = "restore replace=%c prelinks=%d where=%s\n";
53 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
54 static char storaddr[]    = "storage address=%s port=%d ssl=0 Authorization=%s\n";
55
56 /* Responses received from File daemon */
57 static char OKrestore[]   = "2000 OK restore\n";
58 static char OKstore[]     = "2000 OK storage\n";
59 static char OKstoreend[]  = "2000 OK storage end\n";
60
61 /* Responses received from the Storage daemon */
62 static char OKbootstrap[] = "3000 OK bootstrap\n";
63
64 static void build_restore_command(JCR *jcr, POOL_MEM &ret)
65 {
66    char replace, *where, *cmd;
67    char empty = '\0';
68
69    /* Build the restore command */
70
71    if (jcr->replace != 0) {
72       replace = jcr->replace;
73    } else if (jcr->job->replace != 0) {
74       replace = jcr->job->replace;
75    } else {
76       replace = REPLACE_ALWAYS;       /* always replace */
77    }
78    
79    if (jcr->RegexWhere) {
80       where = jcr->RegexWhere;             /* override */
81       cmd = restorecmdR;
82    } else if (jcr->job->RegexWhere) {
83       where = jcr->job->RegexWhere;   /* no override take from job */
84       cmd = restorecmdR;
85
86    } else if (jcr->where) {
87       where = jcr->where;             /* override */
88       cmd = restorecmd;
89    } else if (jcr->job->RestoreWhere) {
90       where = jcr->job->RestoreWhere; /* no override take from job */
91       cmd = restorecmd;
92
93    } else {                           /* nothing was specified */
94       where = ∅                 /* use default */
95       cmd   = restorecmd;                    
96    }
97    
98    jcr->prefix_links = jcr->job->PrefixLinks;
99
100    bash_spaces(where);
101    Mmsg(ret, cmd, replace, jcr->prefix_links, where);
102    unbash_spaces(where);
103 }
104
105 struct bootstrap_info
106 {
107    FILE *bs;
108    UAContext *ua;
109    char storage[MAX_NAME_LENGTH+1];
110 };
111
112 #define UA_CMD_SIZE 1000
113
114 /**
115  * Open the bootstrap file and find the first Storage=
116  * Returns ok if able to open
117  * It fills the storage name (should be the first line) 
118  * and the file descriptor to the bootstrap file, 
119  * it should be used for next operations, and need to be closed
120  * at the end.
121  */
122 static bool open_bootstrap_file(JCR *jcr, bootstrap_info &info)
123 {
124    FILE *bs;
125    UAContext *ua;
126    info.bs = NULL;
127    info.ua = NULL;
128
129    if (!jcr->RestoreBootstrap) {
130       return false;
131    }
132    strncpy(info.storage, jcr->rstore->name(), MAX_NAME_LENGTH);
133
134    bs = fopen(jcr->RestoreBootstrap, "rb");
135    if (!bs) {
136       berrno be;
137       Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
138          jcr->RestoreBootstrap, be.bstrerror());
139       jcr->setJobStatus(JS_ErrorTerminated);
140       return false;
141    }
142
143    ua = new_ua_context(jcr);
144    ua->cmd = check_pool_memory_size(ua->cmd, UA_CMD_SIZE+1);
145    while (!fgets(ua->cmd, UA_CMD_SIZE, bs)) {
146       parse_ua_args(ua);
147       if (ua->argc != 1) {
148          continue;
149       }
150       if (!strcasecmp(ua->argk[0], "Storage")) {
151          strncpy(info.storage, ua->argv[0], MAX_NAME_LENGTH);
152          break;
153       }
154    }
155    info.bs = bs;
156    info.ua = ua;
157    fseek(bs, 0, SEEK_SET);      /* return to the top of the file */
158    return true;
159 }
160
161 /**
162  * This function compare the given storage name with the
163  * the current one. We compare the name and the address:port.
164  * Returns true if we use the same storage.
165  */
166 static bool is_on_same_storage(JCR *jcr, char *new_one)
167 {
168    STORE *new_store;
169
170    /* with old FD, we send the whole bootstrap to the storage */
171    if (jcr->FDVersion < 2) {
172       return true;
173    }
174    /* we are in init loop ? shoudn't fail here */
175    if (!*new_one) {
176       return true;
177    }
178    /* same name */
179    if (!strcmp(new_one, jcr->rstore->name())) {
180       return true;
181    }
182    new_store = (STORE *)GetResWithName(R_STORAGE, new_one);
183    if (!new_store) {
184       Jmsg(jcr, M_WARNING, 0,
185            _("Could not get storage resource '%s'.\n"), new_one);
186       return false;
187    }
188    /* if Port and Hostname/IP are same, we are talking to the same
189     * Storage Daemon
190     */
191    if (jcr->rstore->SDport != new_store->SDport ||
192        strcmp(jcr->rstore->address, new_store->address))
193    {
194       return false;
195    }
196    return true;
197 }
198
199 /**
200  * Check if the current line contains Storage="xxx", and compare the
201  * result to the current storage. We use UAContext to analyse the bsr 
202  * string.
203  *
204  * Returns true if we need to change the storage, and it set the new
205  * Storage resource name in "storage" arg. 
206  */
207 static bool check_for_new_storage(JCR *jcr, bootstrap_info &info)
208 {
209    UAContext *ua = info.ua;
210    parse_ua_args(ua);
211    if (ua->argc != 1) {
212       return false;
213    }
214    if (!strcasecmp(ua->argk[0], "Storage")) {
215       /* Continue if this is a volume from the same storage. */
216       if (is_on_same_storage(jcr, ua->argv[0])) {
217          return false;
218       }
219       /* note the next storage name */
220       strncpy(info.storage, ua->argv[0], MAX_NAME_LENGTH);
221       Dmsg1(5, "Change storage to %s\n", info.storage);
222       return true;
223    }
224    return false;
225 }
226
227 /**
228  * Send bootstrap file to Storage daemon section by section.
229  */
230 static bool send_bootstrap_file(JCR *jcr, BSOCK *sock,
231                                 bootstrap_info &info)
232 {
233    boffset_t pos;
234    const char *bootstrap = "bootstrap\n";
235    UAContext *ua = info.ua;
236    FILE *bs = info.bs;
237
238    Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
239    if (!jcr->RestoreBootstrap) {
240       return false;
241    }
242    sock->fsend(bootstrap);
243    pos = ftello(bs);
244    while(fgets(ua->cmd, UA_CMD_SIZE, bs)) {
245       if (check_for_new_storage(jcr, info)) {
246          /* Otherwise, we need to contact another storage daemon.
247           * Reset bs to the beginning of the current segment. 
248           */
249          fseeko(bs, pos, SEEK_SET);
250          break;
251       }
252       sock->fsend("%s", ua->cmd);
253       pos = ftello(bs);
254    }
255    sock->signal(BNET_EOD);
256    return true;
257 }
258
259 #define MAX_TRIES 6 * 360   /* 6 hours */
260
261 /**
262  * Change the read storage resource for the current job.
263  */
264 static bool select_rstore(JCR *jcr, bootstrap_info &info)
265 {
266    USTORE ustore;
267    int i;
268
269
270    if (!strcmp(jcr->rstore->name(), info.storage)) {
271       return true;                 /* same SD nothing to change */
272    }
273
274    if (!(ustore.store = (STORE *)GetResWithName(R_STORAGE,info.storage))) {
275       Jmsg(jcr, M_FATAL, 0,
276            _("Could not get storage resource '%s'.\n"), info.storage);
277       jcr->setJobStatus(JS_ErrorTerminated);
278       return false;
279    }
280    
281    /*
282     * What does this do???????????  KES
283     */
284    if (jcr->store_bsock) {
285       jcr->store_bsock->destroy();
286       jcr->store_bsock = NULL;
287    }
288    
289    /*
290     * release current read storage and get a new one 
291     */
292    dec_read_store(jcr);
293    free_rstorage(jcr);
294    set_rstorage(jcr, &ustore);
295    jcr->setJobStatus(JS_WaitSD);
296    /*
297     * Wait for up to 6 hours to increment read stoage counter 
298     */
299    for (i=0; i < MAX_TRIES; i++) {
300       /* try to get read storage counter incremented */
301       if (inc_read_store(jcr)) {
302          jcr->setJobStatus(JS_Running);
303          return true;
304       }
305       bmicrosleep(10, 0);       /* sleep 10 secs */
306       if (job_canceled(jcr)) {
307          free_rstorage(jcr);
308          return false;
309       }
310    }
311    /* Failed to inc_read_store() */
312    free_rstorage(jcr);
313    Jmsg(jcr, M_FATAL, 0, 
314       _("Could not acquire read storage lock for \"%s\""), info.storage);
315    return false;
316 }
317
318 /* 
319  * Clean the bootstrap_info struct
320  */
321 static void close_bootstrap_file(bootstrap_info &info)
322 {
323    if (info.bs) {
324       fclose(info.bs);
325    }
326    if (info.ua) {
327       free_ua_context(info.ua);
328    }
329 }
330
331 /**
332  * The bootstrap is stored in a file, so open the file, and loop
333  *   through it processing each storage device in turn. If the
334  *   storage is different from the prior one, we open a new connection
335  *   to the new storage and do a restore for that part.
336  * This permits handling multiple storage daemons for a single
337  *   restore.  E.g. your Full is stored on tape, and Incrementals
338  *   on disk.
339  */
340 bool restore_bootstrap(JCR *jcr)
341 {
342    BSOCK *fd = NULL;
343    BSOCK *sd;
344    bool first_time = true;
345    bootstrap_info info;
346    POOL_MEM restore_cmd(PM_MESSAGE);
347    bool ret = false;
348
349    /* this command is used for each part */
350    build_restore_command(jcr, restore_cmd);
351    
352    /* Open the bootstrap file */
353    if (!open_bootstrap_file(jcr, info)) {
354       goto bail_out;
355    }
356    /* Read the bootstrap file */
357    while (!feof(info.bs)) {
358       
359       if (!select_rstore(jcr, info)) {
360          goto bail_out;
361       }
362
363       /**
364        * Open a message channel connection with the Storage
365        * daemon. This is to let him know that our client
366        * will be contacting him for a backup  session.
367        *
368        */
369       Dmsg0(10, "Open connection with storage daemon\n");
370       jcr->setJobStatus(JS_WaitSD);
371       /*
372        * Start conversation with Storage daemon
373        */
374       if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
375          goto bail_out;
376       }
377       sd = jcr->store_bsock;
378       /*
379        * Now start a job with the Storage daemon
380        */
381       if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL)) {
382          goto bail_out;
383       }
384
385       if (first_time) {
386          /*
387           * Start conversation with File daemon
388           */
389          jcr->setJobStatus(JS_WaitFD);
390          jcr->keep_sd_auth_key = true; /* don't clear the sd_auth_key now */
391          if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
392             goto bail_out;
393          }
394          fd = jcr->file_bsock;
395       }
396
397       jcr->setJobStatus(JS_Running);
398
399       /*
400        * Send the bootstrap file -- what Volumes/files to restore
401        */
402       if (!send_bootstrap_file(jcr, sd, info) ||
403           !response(jcr, sd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
404          goto bail_out;
405       }
406
407       if (!sd->fsend("run")) {
408          goto bail_out;
409       }
410       /*
411        * Now start a Storage daemon message thread
412        */
413       if (!start_storage_daemon_message_thread(jcr)) {
414          goto bail_out;
415       }
416       Dmsg0(50, "Storage daemon connection OK\n");
417
418       /*
419        * send Storage daemon address to the File daemon,
420        *   then wait for File daemon to make connection
421        *   with Storage daemon.
422        */
423       if (jcr->rstore->SDDport == 0) {
424          jcr->rstore->SDDport = jcr->rstore->SDport;
425       }
426       fd->fsend(storaddr, jcr->rstore->address, jcr->rstore->SDDport,
427                 jcr->sd_auth_key);
428       memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
429
430       Dmsg1(6, "dird>filed: %s\n", fd->msg);
431       if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
432          goto bail_out;
433       }
434
435       /* Only pass "global" commands to the FD once */
436       if (first_time) {
437          first_time = false;
438          if (!send_runscripts_commands(jcr)) {
439             goto bail_out;
440          }
441          if (!send_restore_objects(jcr)) {
442             Dmsg0(000, "FAIL: Send restore objects\n");
443             goto bail_out;
444          }
445       }
446
447       fd->fsend("%s", restore_cmd.c_str());
448
449       if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) {
450          goto bail_out;
451       }
452
453       if (jcr->FDVersion < 2) { /* Old FD */
454          break;                 /* we do only one loop */
455       } else {
456          if (!response(jcr, fd, OKstoreend, "Store end", DISPLAY_ERROR)) {
457             goto bail_out;
458          }
459          wait_for_storage_daemon_termination(jcr);
460       }
461    } /* the whole boostrap has been send */
462
463    if (fd && jcr->FDVersion >= 2) {
464       fd->fsend("endrestore");
465    }
466
467    ret = true;
468
469 bail_out:
470    close_bootstrap_file(info);
471    return ret;
472 }
473
474 /**
475  * Do a restore of the specified files
476  *
477  *  Returns:  0 on failure
478  *            1 on success
479  */
480 bool do_restore(JCR *jcr)
481 {
482    JOB_DBR rjr;                       /* restore job record */
483    int stat;
484
485    free_wstorage(jcr);                /* we don't write */
486
487    if (!allow_duplicate_job(jcr)) {
488       goto bail_out;
489    }
490
491    memset(&rjr, 0, sizeof(rjr));
492    jcr->jr.JobLevel = L_FULL;         /* Full restore */
493    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
494       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
495       goto bail_out;
496    }
497    Dmsg0(20, "Updated job start record\n");
498
499    Dmsg1(20, "RestoreJobId=%d\n", jcr->job->RestoreJobId);
500
501    if (!jcr->RestoreBootstrap) {
502       Jmsg(jcr, M_FATAL, 0, _("Cannot restore without a bootstrap file.\n"
503           "You probably ran a restore job directly. All restore jobs must\n"
504           "be run using the restore command.\n"));
505       goto bail_out;
506    }
507
508
509    /* Print Job Start message */
510    Jmsg(jcr, M_INFO, 0, _("Start Restore Job %s\n"), jcr->Job);
511
512    /* Read the bootstrap file and do the restore */
513    if (!restore_bootstrap(jcr)) {
514       goto bail_out;
515    }
516
517    /* Wait for Job Termination */
518    stat = wait_for_job_termination(jcr);
519    restore_cleanup(jcr, stat);
520    return true;
521
522 bail_out:
523    restore_cleanup(jcr, JS_ErrorTerminated);
524    return false;
525 }
526
527 bool do_restore_init(JCR *jcr) 
528 {
529    free_wstorage(jcr);
530    return true;
531 }
532
533 /**
534  * Release resources allocated during restore.
535  *
536  */
537 void restore_cleanup(JCR *jcr, int TermCode)
538 {
539    char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
540    char ec1[30], ec2[30], ec3[30];
541    char term_code[100], fd_term_msg[100], sd_term_msg[100];
542    const char *term_msg;
543    int msg_type = M_INFO;
544    double kbps;
545
546    Dmsg0(20, "In restore_cleanup\n");
547    update_job_end(jcr, TermCode);
548
549    if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
550       unlink(jcr->RestoreBootstrap);
551       jcr->unlink_bsr = false;
552    }
553
554    if (job_canceled(jcr)) {
555       cancel_storage_daemon_job(jcr);
556    }  
557
558    switch (TermCode) {
559    case JS_Terminated:
560       if (jcr->ExpectedFiles > jcr->jr.JobFiles) {
561          term_msg = _("Restore OK -- warning file count mismatch");
562       } else {
563          term_msg = _("Restore OK");
564       }
565       break;
566    case JS_Warnings:
567          term_msg = _("Restore OK -- with warnings");
568          break;
569    case JS_FatalError:
570    case JS_ErrorTerminated:
571       term_msg = _("*** Restore Error ***");
572       msg_type = M_ERROR;          /* Generate error message */
573       if (jcr->store_bsock) {
574          jcr->store_bsock->signal(BNET_TERMINATE);
575          if (jcr->SD_msg_chan) {
576             pthread_cancel(jcr->SD_msg_chan);
577          }
578       }
579       break;
580    case JS_Canceled:
581       term_msg = _("Restore Canceled");
582       if (jcr->store_bsock) {
583          jcr->store_bsock->signal(BNET_TERMINATE);
584          if (jcr->SD_msg_chan) {
585             pthread_cancel(jcr->SD_msg_chan);
586          }
587       }
588       break;
589    default:
590       term_msg = term_code;
591       sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
592       break;
593    }
594    bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
595    bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
596    if (jcr->jr.EndTime - jcr->jr.StartTime > 0) {
597       kbps = (double)jcr->jr.JobBytes / (1000 * (jcr->jr.EndTime - jcr->jr.StartTime));
598    } else {
599       kbps = 0;
600    }
601    if (kbps < 0.05) {
602       kbps = 0;
603    }
604
605    jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
606    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
607
608    Jmsg(jcr, msg_type, 0, _("%s %s %s (%s):\n"
609 "  Build OS:               %s %s %s\n"
610 "  JobId:                  %d\n"
611 "  Job:                    %s\n"
612 "  Restore Client:         %s\n"
613 "  Start time:             %s\n"
614 "  End time:               %s\n"
615 "  Files Expected:         %s\n"
616 "  Files Restored:         %s\n"
617 "  Bytes Restored:         %s\n"
618 "  Rate:                   %.1f KB/s\n"
619 "  FD Errors:              %d\n"
620 "  FD termination status:  %s\n"
621 "  SD termination status:  %s\n"
622 "  Termination:            %s\n\n"),
623         BACULA, my_name, VERSION, LSMDATE,
624         HOST_OS, DISTNAME, DISTVER,
625         jcr->jr.JobId,
626         jcr->jr.Job,
627         jcr->client->name(),
628         sdt,
629         edt,
630         edit_uint64_with_commas((uint64_t)jcr->ExpectedFiles, ec1),
631         edit_uint64_with_commas((uint64_t)jcr->jr.JobFiles, ec2),
632         edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
633         (float)kbps,
634         jcr->JobErrors,
635         fd_term_msg,
636         sd_term_msg,
637         term_msg);
638
639    Dmsg0(20, "Leaving restore_cleanup\n");
640 }