]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/parse_bsr.c
Make 5 min Heartbeat the default
[bacula/bacula] / bacula / src / stored / parse_bsr.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2014 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    Bacula® is a registered trademark of Kern Sibbald.
15 */
16 /*
17  *   Parse a Bootstrap Records (used for restores)
18  *
19  *     Kern Sibbald, June MMII
20  *
21  */
22
23
24 #include "bacula.h"
25 #include "stored.h"
26
27 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...);
28 static bool add_restore_volume(JCR *jcr, VOL_LIST *vol);
29
30 typedef BSR * (ITEM_HANDLER)(LEX *lc, BSR *bsr);
31
32 static BSR *store_client(LEX *lc, BSR *bsr);
33 static BSR *store_count(LEX *lc, BSR *bsr);
34 static BSR *store_device(LEX *lc, BSR *bsr);
35 static BSR *store_exclude(LEX *lc, BSR *bsr);
36 static BSR *store_fileregex(LEX *lc, BSR *bsr);
37 static BSR *store_findex(LEX *lc, BSR *bsr);
38 static BSR *store_include(LEX *lc, BSR *bsr);
39 static BSR *store_jobid(LEX *lc, BSR *bsr);
40 static BSR *store_joblevel(LEX *lc, BSR *bsr);
41 static BSR *store_job(LEX *lc, BSR *bsr);
42 static BSR *store_jobtype(LEX *lc, BSR *bsr);
43 static BSR *store_mediatype(LEX *lc, BSR *bsr);
44 static BSR *store_nothing(LEX *lc, BSR *bsr);
45 static BSR *store_sessid(LEX *lc, BSR *bsr);
46 static BSR *store_sesstime(LEX *lc, BSR *bsr);
47 static BSR *store_slot(LEX *lc, BSR *bsr);
48 static BSR *store_stream(LEX *lc, BSR *bsr);
49 static BSR *store_voladdr(LEX *lc, BSR *bsr);
50 static BSR *store_volblock(LEX *lc, BSR *bsr);
51 static BSR *store_volfile(LEX *lc, BSR *bsr);
52 static BSR *store_vol(LEX *lc, BSR *bsr);
53 static bool is_fast_rejection_ok(BSR *bsr);
54 static bool is_positioning_ok(BSR *bsr);
55
56 struct kw_items {
57    const char *name;
58    ITEM_HANDLER *handler;
59 };
60
61 /*
62  * List of all keywords permitted in bsr files and their handlers
63  */
64 struct kw_items items[] = {
65    {"client",    store_client},
66    {"count",     store_count},
67    {"device",    store_device},
68    {"exclude",   store_exclude},
69    {"fileindex", store_findex},
70    {"fileregex", store_fileregex},
71    {"include",   store_include},
72    {"jobid",     store_jobid},
73    {"joblevel",  store_joblevel},
74    {"job",       store_job},
75    {"jobtype",   store_jobtype},
76    {"mediatype", store_mediatype},
77    {"slot",      store_slot},
78    {"storage",   store_nothing},
79    {"stream",    store_stream},
80    {"voladdr",   store_voladdr},
81    {"volblock",  store_volblock},
82    {"volume",    store_vol},
83    {"volfile",   store_volfile},
84    {"volsessionid",   store_sessid},
85    {"volsessiontime", store_sesstime},
86    {NULL, NULL}
87 };
88
89 /*
90  * Create a BSR record
91  */
92 static BSR *new_bsr()
93 {
94    BSR *bsr = (BSR *)malloc(sizeof(BSR));
95    memset(bsr, 0, sizeof(BSR));
96    return bsr;
97 }
98
99
100 /*********************************************************************
101  *
102  *      Parse Bootstrap file
103  *
104  */
105 BSR *parse_bsr(JCR *jcr, char *fname)
106 {
107    LEX *lc = NULL;
108    int token, i;
109    BSR *root_bsr = new_bsr();
110    BSR *bsr = root_bsr;
111
112    Dmsg1(300, "Enter parse_bsf %s\n", fname);
113    if ((lc = lex_open_file(lc, fname, s_err)) == NULL) {
114       berrno be;
115       Emsg2(M_ERROR_TERM, 0, _("Cannot open bootstrap file %s: %s\n"),
116             fname, be.bstrerror());
117    }
118    lc->caller_ctx = (void *)jcr;
119    while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
120       Dmsg1(300, "parse got token=%s\n", lex_tok_to_str(token));
121       if (token == T_EOL) {
122          continue;
123       }
124       for (i=0; items[i].name; i++) {
125          if (strcasecmp(items[i].name, lc->str) == 0) {
126             token = lex_get_token(lc, T_ALL);
127             Dmsg1 (300, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
128             if (token != T_EQUALS) {
129                scan_err1(lc, "expected an equals, got: %s", lc->str);
130                bsr = NULL;
131                break;
132             }
133             Dmsg1(300, "calling handler for %s\n", items[i].name);
134             /* Call item handler */
135             bsr = items[i].handler(lc, bsr);
136             i = -1;
137             break;
138          }
139       }
140       if (i >= 0) {
141          Dmsg1(300, "Keyword = %s\n", lc->str);
142          scan_err1(lc, "Keyword %s not found", lc->str);
143          bsr = NULL;
144          break;
145       }
146       if (!bsr) {
147          break;
148       }
149    }
150    lc = lex_close_file(lc);
151    Dmsg0(300, "Leave parse_bsf()\n");
152    if (!bsr) {
153       free_bsr(root_bsr);
154       root_bsr = NULL;
155    }
156    if (root_bsr) {
157       root_bsr->use_fast_rejection = is_fast_rejection_ok(root_bsr);
158       root_bsr->use_positioning = is_positioning_ok(root_bsr);
159    }
160    for (bsr=root_bsr; bsr; bsr=bsr->next) {
161       bsr->root = root_bsr;
162    }
163    return root_bsr;
164 }
165
166 static BSR *store_client(LEX *lc, BSR *bsr)
167 {
168    int token;
169    BSR_CLIENT *client;
170
171    for (;;) {
172       token = lex_get_token(lc, T_NAME);
173       if (token == T_ERROR) {
174          return NULL;
175       }
176       client = (BSR_CLIENT *)malloc(sizeof(BSR_CLIENT));
177       memset(client, 0, sizeof(BSR_CLIENT));
178       bstrncpy(client->ClientName, lc->str, sizeof(client->ClientName));
179       /* Add it to the end of the client chain */
180       if (!bsr->client) {
181          bsr->client = client;
182       } else {
183          BSR_CLIENT *bc = bsr->client;
184          for ( ;bc->next; bc=bc->next)
185             { }
186          bc->next = client;
187       }
188       token = lex_get_token(lc, T_ALL);
189       if (token != T_COMMA) {
190          break;
191       }
192    }
193    return bsr;
194 }
195
196 static BSR *store_count(LEX *lc, BSR *bsr)
197 {
198    int token;
199
200    token = lex_get_token(lc, T_PINT32);
201    if (token == T_ERROR) {
202       return NULL;
203    }
204    bsr->count = lc->pint32_val;
205    scan_to_eol(lc);
206    return bsr;
207 }
208
209 /* Shove the Device name in each Volume in the current bsr */
210 static BSR *store_device(LEX *lc, BSR *bsr)
211 {
212    int token;
213
214    token = lex_get_token(lc, T_STRING);
215    if (token == T_ERROR) {
216       return NULL;
217    }
218    if (!bsr->volume) {
219       Emsg1(M_ERROR,0, _("Device \"%s\" in bsr at inappropriate place.\n"),
220          lc->str);
221       return bsr;
222    }
223    BSR_VOLUME *bv;
224    for (bv=bsr->volume; bv; bv=bv->next) {
225       bstrncpy(bv->device, lc->str, sizeof(bv->device));
226    }
227    return bsr;
228 }
229
230 static BSR *store_findex(LEX *lc, BSR *bsr)
231 {
232    int token;
233    BSR_FINDEX *findex;
234
235    for (;;) {
236       token = lex_get_token(lc, T_PINT32_RANGE);
237       if (token == T_ERROR) {
238          return NULL;
239       }
240       findex = (BSR_FINDEX *)malloc(sizeof(BSR_FINDEX));
241       memset(findex, 0, sizeof(BSR_FINDEX));
242       findex->findex = lc->pint32_val;
243       findex->findex2 = lc->pint32_val2;
244       /* Add it to the end of the chain */
245       if (!bsr->FileIndex) {
246          bsr->FileIndex = findex;
247       } else {
248          /* Add to end of chain */
249          BSR_FINDEX *bs = bsr->FileIndex;
250          for ( ;bs->next; bs=bs->next)
251             {  }
252          bs->next = findex;
253       }
254       token = lex_get_token(lc, T_ALL);
255       if (token != T_COMMA) {
256          break;
257       }
258    }
259    return bsr;
260 }
261
262 static BSR *store_fileregex(LEX *lc, BSR *bsr)
263 {
264    int token;
265    int rc;
266
267    token = lex_get_token(lc, T_STRING);
268    if (token == T_ERROR) {
269       return NULL;
270    }
271
272    if (bsr->fileregex) free(bsr->fileregex);
273    bsr->fileregex = bstrdup(lc->str);
274
275    if (bsr->fileregex_re == NULL)
276       bsr->fileregex_re = (regex_t *)bmalloc(sizeof(regex_t));
277
278    rc = regcomp(bsr->fileregex_re, bsr->fileregex, REG_EXTENDED|REG_NOSUB);
279    if (rc != 0) {
280       char prbuf[500];
281       regerror(rc, bsr->fileregex_re, prbuf, sizeof(prbuf));
282       Emsg2(M_ERROR, 0, _("REGEX '%s' compile error. ERR=%s\n"),
283             bsr->fileregex, prbuf);
284       return NULL;
285    }
286    return bsr;
287 }
288
289 static BSR *store_jobid(LEX *lc, BSR *bsr)
290 {
291    int token;
292    BSR_JOBID *jobid;
293
294    for (;;) {
295       token = lex_get_token(lc, T_PINT32_RANGE);
296       if (token == T_ERROR) {
297          return NULL;
298       }
299       jobid = (BSR_JOBID *)malloc(sizeof(BSR_JOBID));
300       memset(jobid, 0, sizeof(BSR_JOBID));
301       jobid->JobId = lc->pint32_val;
302       jobid->JobId2 = lc->pint32_val2;
303       /* Add it to the end of the chain */
304       if (!bsr->JobId) {
305          bsr->JobId = jobid;
306       } else {
307          /* Add to end of chain */
308          BSR_JOBID *bs = bsr->JobId;
309          for ( ;bs->next; bs=bs->next)
310             {  }
311          bs->next = jobid;
312       }
313       token = lex_get_token(lc, T_ALL);
314       if (token != T_COMMA) {
315          break;
316       }
317    }
318    return bsr;
319 }
320
321
322 static BSR *store_jobtype(LEX *lc, BSR *bsr)
323 {
324    /* *****FIXME****** */
325    Pmsg0(-1, _("JobType not yet implemented\n"));
326    return bsr;
327 }
328
329
330 static BSR *store_joblevel(LEX *lc, BSR *bsr)
331 {
332    /* *****FIXME****** */
333    Pmsg0(-1, _("JobLevel not yet implemented\n"));
334    return bsr;
335 }
336
337 static BSR *store_job(LEX *lc, BSR *bsr)
338 {
339    int token;
340    BSR_JOB *job;
341
342    for (;;) {
343       token = lex_get_token(lc, T_NAME);
344       if (token == T_ERROR) {
345          return NULL;
346       }
347       job = (BSR_JOB *)malloc(sizeof(BSR_JOB));
348       memset(job, 0, sizeof(BSR_JOB));
349       bstrncpy(job->Job, lc->str, sizeof(job->Job));
350       /* Add it to the end of the client chain */
351       if (!bsr->job) {
352          bsr->job = job;
353       } else {
354          /* Add to end of chain */
355          BSR_JOB *bc = bsr->job;
356          for ( ;bc->next; bc=bc->next)
357             { }
358          bc->next = job;
359       }
360       token = lex_get_token(lc, T_ALL);
361       if (token != T_COMMA) {
362          break;
363       }
364    }
365    return bsr;
366 }
367
368 /* Shove the MediaType in each Volume in the current bsr */
369 static BSR *store_mediatype(LEX *lc, BSR *bsr)
370 {
371    int token;
372
373    token = lex_get_token(lc, T_STRING);
374    if (token == T_ERROR) {
375       return NULL;
376    }
377    if (!bsr->volume) {
378       Emsg1(M_ERROR,0, _("MediaType %s in bsr at inappropriate place.\n"),
379          lc->str);
380       return bsr;
381    }
382    BSR_VOLUME *bv;
383    for (bv=bsr->volume; bv; bv=bv->next) {
384       bstrncpy(bv->MediaType, lc->str, sizeof(bv->MediaType));
385    }
386    return bsr;
387 }
388
389 static BSR *store_vol(LEX *lc, BSR *bsr)
390 {
391    int token;
392    BSR_VOLUME *volume;
393    char *p, *n;
394
395    token = lex_get_token(lc, T_STRING);
396    if (token == T_ERROR) {
397       return NULL;
398    }
399    if (bsr->volume) {
400       bsr->next = new_bsr();
401       bsr->next->prev = bsr;
402       bsr = bsr->next;
403    }
404    /* This may actually be more than one volume separated by a |
405     * If so, separate them.
406     */
407    for (p=lc->str; p && *p; ) {
408       n = strchr(p, '|');
409       if (n) {
410          *n++ = 0;
411       }
412       volume = (BSR_VOLUME *)malloc(sizeof(BSR_VOLUME));
413       memset(volume, 0, sizeof(BSR_VOLUME));
414       bstrncpy(volume->VolumeName, p, sizeof(volume->VolumeName));
415       /* Add it to the end of the volume chain */
416       if (!bsr->volume) {
417          bsr->volume = volume;
418       } else {
419          BSR_VOLUME *bc = bsr->volume;
420          for ( ;bc->next; bc=bc->next)
421             { }
422          bc->next = volume;
423       }
424       p = n;
425    }
426    return bsr;
427 }
428
429 static bool is_positioning_ok(BSR *bsr)
430 {
431    /*
432     * Every bsr should have a volfile entry and a volblock entry
433     * or a VolAddr
434     *   if we are going to use positioning
435     */
436    for ( ; bsr; bsr=bsr->next) {
437       if (!((bsr->volfile && bsr->volblock) || bsr->voladdr)) {
438          return false;
439       }
440    }
441    return true;
442 }
443
444 static bool is_fast_rejection_ok(BSR *bsr)
445 {
446    /*
447     * Although, this can be optimized, for the moment, require
448     *  all bsrs to have both sesstime and sessid set before
449     *  we do fast rejection.
450     */
451    for ( ; bsr; bsr=bsr->next) {
452       if (!(bsr->sesstime && bsr->sessid)) {
453          return false;
454       }
455    }
456    return true;
457 }
458
459
460 static BSR *store_nothing(LEX *lc, BSR *bsr)
461 {
462    int token;
463
464    token = lex_get_token(lc, T_STRING);
465    if (token == T_ERROR) {
466       return NULL;
467    }
468    return bsr;
469 }
470
471
472
473 /*
474  * Routine to handle Volume start/end file
475  */
476 static BSR *store_volfile(LEX *lc, BSR *bsr)
477 {
478    int token;
479    BSR_VOLFILE *volfile;
480
481    for (;;) {
482       token = lex_get_token(lc, T_PINT32_RANGE);
483       if (token == T_ERROR) {
484          return NULL;
485       }
486       volfile = (BSR_VOLFILE *)malloc(sizeof(BSR_VOLFILE));
487       memset(volfile, 0, sizeof(BSR_VOLFILE));
488       volfile->sfile = lc->pint32_val;
489       volfile->efile = lc->pint32_val2;
490       /* Add it to the end of the chain */
491       if (!bsr->volfile) {
492          bsr->volfile = volfile;
493       } else {
494          /* Add to end of chain */
495          BSR_VOLFILE *bs = bsr->volfile;
496          for ( ;bs->next; bs=bs->next)
497             {  }
498          bs->next = volfile;
499       }
500       token = lex_get_token(lc, T_ALL);
501       if (token != T_COMMA) {
502          break;
503       }
504    }
505    return bsr;
506 }
507
508
509 /*
510  * Routine to handle Volume start/end Block
511  */
512 static BSR *store_volblock(LEX *lc, BSR *bsr)
513 {
514    int token;
515    BSR_VOLBLOCK *volblock;
516
517    for (;;) {
518       token = lex_get_token(lc, T_PINT32_RANGE);
519       if (token == T_ERROR) {
520          return NULL;
521       }
522       volblock = (BSR_VOLBLOCK *)malloc(sizeof(BSR_VOLBLOCK));
523       memset(volblock, 0, sizeof(BSR_VOLBLOCK));
524       volblock->sblock = lc->pint32_val;
525       volblock->eblock = lc->pint32_val2;
526       /* Add it to the end of the chain */
527       if (!bsr->volblock) {
528          bsr->volblock = volblock;
529       } else {
530          /* Add to end of chain */
531          BSR_VOLBLOCK *bs = bsr->volblock;
532          for ( ;bs->next; bs=bs->next)
533             {  }
534          bs->next = volblock;
535       }
536       token = lex_get_token(lc, T_ALL);
537       if (token != T_COMMA) {
538          break;
539       }
540    }
541    return bsr;
542 }
543
544 /*
545  * Routine to handle Volume start/end address
546  */
547 static BSR *store_voladdr(LEX *lc, BSR *bsr)
548 {
549    int token;
550    BSR_VOLADDR *voladdr;
551
552    for (;;) {
553       token = lex_get_token(lc, T_PINT64_RANGE);
554       if (token == T_ERROR) {
555          return NULL;
556       }
557       voladdr = (BSR_VOLADDR *)malloc(sizeof(BSR_VOLADDR));
558       memset(voladdr, 0, sizeof(BSR_VOLADDR));
559       voladdr->saddr = lc->pint64_val;
560       voladdr->eaddr = lc->pint64_val2;
561       /* Add it to the end of the chain */
562       if (!bsr->voladdr) {
563          bsr->voladdr = voladdr;
564       } else {
565          /* Add to end of chain */
566          BSR_VOLADDR *bs = bsr->voladdr;
567          for ( ;bs->next; bs=bs->next)
568             {  }
569          bs->next = voladdr;
570       }
571       token = lex_get_token(lc, T_ALL);
572       if (token != T_COMMA) {
573          break;
574       }
575    }
576    return bsr;
577 }
578
579 static BSR *store_sessid(LEX *lc, BSR *bsr)
580 {
581    int token;
582    BSR_SESSID *sid;
583
584    for (;;) {
585       token = lex_get_token(lc, T_PINT32_RANGE);
586       if (token == T_ERROR) {
587          return NULL;
588       }
589       sid = (BSR_SESSID *)malloc(sizeof(BSR_SESSID));
590       memset(sid, 0, sizeof(BSR_SESSID));
591       sid->sessid = lc->pint32_val;
592       sid->sessid2 = lc->pint32_val2;
593       /* Add it to the end of the chain */
594       if (!bsr->sessid) {
595          bsr->sessid = sid;
596       } else {
597          /* Add to end of chain */
598          BSR_SESSID *bs = bsr->sessid;
599          for ( ;bs->next; bs=bs->next)
600             {  }
601          bs->next = sid;
602       }
603       token = lex_get_token(lc, T_ALL);
604       if (token != T_COMMA) {
605          break;
606       }
607    }
608    return bsr;
609 }
610
611 static BSR *store_sesstime(LEX *lc, BSR *bsr)
612 {
613    int token;
614    BSR_SESSTIME *stime;
615
616    for (;;) {
617       token = lex_get_token(lc, T_PINT32);
618       if (token == T_ERROR) {
619          return NULL;
620       }
621       stime = (BSR_SESSTIME *)malloc(sizeof(BSR_SESSTIME));
622       memset(stime, 0, sizeof(BSR_SESSTIME));
623       stime->sesstime = lc->pint32_val;
624       /* Add it to the end of the chain */
625       if (!bsr->sesstime) {
626          bsr->sesstime = stime;
627       } else {
628          /* Add to end of chain */
629          BSR_SESSTIME *bs = bsr->sesstime;
630          for ( ;bs->next; bs=bs->next)
631             { }
632          bs->next = stime;
633       }
634       token = lex_get_token(lc, T_ALL);
635       if (token != T_COMMA) {
636          break;
637       }
638    }
639    return bsr;
640 }
641
642
643 static BSR *store_stream(LEX *lc, BSR *bsr)
644 {
645    int token;
646    BSR_STREAM *stream;
647
648    for (;;) {
649       token = lex_get_token(lc, T_INT32);
650       if (token == T_ERROR) {
651          return NULL;
652       }
653       stream = (BSR_STREAM *)malloc(sizeof(BSR_STREAM));
654       memset(stream, 0, sizeof(BSR_STREAM));
655       stream->stream = lc->int32_val;
656       /* Add it to the end of the chain */
657       if (!bsr->stream) {
658          bsr->stream = stream;
659       } else {
660          /* Add to end of chain */
661          BSR_STREAM *bs = bsr->stream;
662          for ( ;bs->next; bs=bs->next)
663             { }
664          bs->next = stream;
665       }
666       token = lex_get_token(lc, T_ALL);
667       if (token != T_COMMA) {
668          break;
669       }
670    }
671    return bsr;
672 }
673
674 static BSR *store_slot(LEX *lc, BSR *bsr)
675 {
676    int token;
677
678    token = lex_get_token(lc, T_PINT32);
679    if (token == T_ERROR) {
680       return NULL;
681    }
682    if (!bsr->volume) {
683       Emsg1(M_ERROR,0, _("Slot %d in bsr at inappropriate place.\n"),
684          lc->pint32_val);
685       return bsr;
686    }
687    bsr->volume->Slot = lc->pint32_val;
688    scan_to_eol(lc);
689    return bsr;
690 }
691
692 static BSR *store_include(LEX *lc, BSR *bsr)
693 {
694    scan_to_eol(lc);
695    return bsr;
696 }
697
698 static BSR *store_exclude(LEX *lc, BSR *bsr)
699 {
700    scan_to_eol(lc);
701    return bsr;
702 }
703
704 void dump_volfile(BSR_VOLFILE *volfile)
705 {
706    if (volfile) {
707       Pmsg2(-1, _("VolFile     : %u-%u\n"), volfile->sfile, volfile->efile);
708       dump_volfile(volfile->next);
709    }
710 }
711
712 void dump_volblock(BSR_VOLBLOCK *volblock)
713 {
714    if (volblock) {
715       Pmsg2(-1, _("VolBlock    : %u-%u\n"), volblock->sblock, volblock->eblock);
716       dump_volblock(volblock->next);
717    }
718 }
719
720 void dump_voladdr(BSR_VOLADDR *voladdr)
721 {
722    if (voladdr) {
723       Pmsg2(-1, _("VolAddr    : %llu-%llu\n"), voladdr->saddr, voladdr->eaddr);
724       dump_voladdr(voladdr->next);
725    }
726 }
727
728 void dump_findex(BSR_FINDEX *FileIndex)
729 {
730    if (FileIndex) {
731       if (FileIndex->findex == FileIndex->findex2) {
732          Pmsg1(-1, _("FileIndex   : %u\n"), FileIndex->findex);
733       } else {
734          Pmsg2(-1, _("FileIndex   : %u-%u\n"), FileIndex->findex, FileIndex->findex2);
735       }
736       dump_findex(FileIndex->next);
737    }
738 }
739
740 void dump_jobid(BSR_JOBID *jobid)
741 {
742    if (jobid) {
743       if (jobid->JobId == jobid->JobId2) {
744          Pmsg1(-1, _("JobId       : %u\n"), jobid->JobId);
745       } else {
746          Pmsg2(-1, _("JobId       : %u-%u\n"), jobid->JobId, jobid->JobId2);
747       }
748       dump_jobid(jobid->next);
749    }
750 }
751
752 void dump_sessid(BSR_SESSID *sessid)
753 {
754    if (sessid) {
755       if (sessid->sessid == sessid->sessid2) {
756          Pmsg1(-1, _("SessId      : %u\n"), sessid->sessid);
757       } else {
758          Pmsg2(-1, _("SessId      : %u-%u\n"), sessid->sessid, sessid->sessid2);
759       }
760       dump_sessid(sessid->next);
761    }
762 }
763
764 void dump_volume(BSR_VOLUME *volume)
765 {
766    if (volume) {
767       Pmsg1(-1, _("VolumeName  : %s\n"), volume->VolumeName);
768       Pmsg1(-1, _("  MediaType : %s\n"), volume->MediaType);
769       Pmsg1(-1, _("  Device    : %s\n"), volume->device);
770       Pmsg1(-1, _("  Slot      : %d\n"), volume->Slot);
771       dump_volume(volume->next);
772    }
773 }
774
775
776 void dump_client(BSR_CLIENT *client)
777 {
778    if (client) {
779       Pmsg1(-1, _("Client      : %s\n"), client->ClientName);
780       dump_client(client->next);
781    }
782 }
783
784 void dump_job(BSR_JOB *job)
785 {
786    if (job) {
787       Pmsg1(-1, _("Job          : %s\n"), job->Job);
788       dump_job(job->next);
789    }
790 }
791
792 void dump_sesstime(BSR_SESSTIME *sesstime)
793 {
794    if (sesstime) {
795       Pmsg1(-1, _("SessTime    : %u\n"), sesstime->sesstime);
796       dump_sesstime(sesstime->next);
797    }
798 }
799
800
801 void dump_bsr(BSR *bsr, bool recurse)
802 {
803    int64_t save_debug = debug_level;
804    debug_level = 1;
805    if (!bsr) {
806       Pmsg0(-1, _("BSR is NULL\n"));
807       debug_level = save_debug;
808       return;
809    }
810    Pmsg1(-1,    _("Next        : 0x%x\n"), bsr->next);
811    Pmsg1(-1,    _("Root bsr    : 0x%x\n"), bsr->root);
812    dump_volume(bsr->volume);
813    dump_sessid(bsr->sessid);
814    dump_sesstime(bsr->sesstime);
815    dump_volfile(bsr->volfile);
816    dump_volblock(bsr->volblock);
817    dump_voladdr(bsr->voladdr);
818    dump_client(bsr->client);
819    dump_jobid(bsr->JobId);
820    dump_job(bsr->job);
821    dump_findex(bsr->FileIndex);
822    if (bsr->count) {
823       Pmsg1(-1, _("count       : %u\n"), bsr->count);
824       Pmsg1(-1, _("found       : %u\n"), bsr->found);
825    }
826
827    Pmsg1(-1,    _("done        : %s\n"), bsr->done?_("yes"):_("no"));
828    Pmsg1(-1,    _("positioning : %d\n"), bsr->use_positioning);
829    Pmsg1(-1,    _("fast_reject : %d\n"), bsr->use_fast_rejection);
830    if (recurse && bsr->next) {
831       Pmsg0(-1, "\n");
832       dump_bsr(bsr->next, true);
833    }
834    debug_level = save_debug;
835 }
836
837
838
839 /*********************************************************************
840  *
841  *      Free bsr resources
842  */
843
844 static void free_bsr_item(BSR *bsr)
845 {
846    if (bsr) {
847       free_bsr_item(bsr->next);
848       free(bsr);
849    }
850 }
851
852 /*
853  * Remove a single item from the bsr tree
854  */
855 void remove_bsr(BSR *bsr)
856 {
857    free_bsr_item((BSR *)bsr->volume);
858    free_bsr_item((BSR *)bsr->client);
859    free_bsr_item((BSR *)bsr->sessid);
860    free_bsr_item((BSR *)bsr->sesstime);
861    free_bsr_item((BSR *)bsr->volfile);
862    free_bsr_item((BSR *)bsr->volblock);
863    free_bsr_item((BSR *)bsr->voladdr);
864    free_bsr_item((BSR *)bsr->JobId);
865    free_bsr_item((BSR *)bsr->job);
866    free_bsr_item((BSR *)bsr->FileIndex);
867    free_bsr_item((BSR *)bsr->JobType);
868    free_bsr_item((BSR *)bsr->JobLevel);
869    if (bsr->fileregex) {
870       bfree(bsr->fileregex);
871    }
872    if (bsr->fileregex_re) {
873       regfree(bsr->fileregex_re);
874       free(bsr->fileregex_re);
875    }
876    if (bsr->attr) {
877       free_attr(bsr->attr);
878    }
879    if (bsr->next) {
880       bsr->next->prev = bsr->prev;
881    }
882    if (bsr->prev) {
883       bsr->prev->next = bsr->next;
884    }
885    free(bsr);
886 }
887
888 /*
889  * Free all bsrs in chain
890  */
891 void free_bsr(BSR *bsr)
892 {
893    BSR *next_bsr;
894
895    if (!bsr) {
896       return;
897    }
898    next_bsr = bsr->next;
899    /* Remove (free) current bsr */
900    remove_bsr(bsr);
901    /* Now get the next one */
902    free_bsr(next_bsr);
903 }
904
905 /*****************************************************************
906  * Routines for handling volumes
907  */
908 static VOL_LIST *new_restore_volume()
909 {
910    VOL_LIST *vol;
911    vol = (VOL_LIST *)malloc(sizeof(VOL_LIST));
912    memset(vol, 0, sizeof(VOL_LIST));
913    return vol;
914 }
915
916 /*
917  * Create a list of Volumes (and Slots and Start positions) to be
918  *  used in the current restore job.
919  */
920 void create_restore_volume_list(JCR *jcr)
921 {
922    char *p, *n;
923    VOL_LIST *vol;
924
925    /*
926     * Build a list of volumes to be processed
927     */
928    jcr->NumReadVolumes = 0;
929    jcr->CurReadVolume = 0;
930    if (jcr->bsr) {
931       BSR *bsr = jcr->bsr;
932       if (!bsr->volume || !bsr->volume->VolumeName[0]) {
933          return;
934       }
935       for ( ; bsr; bsr=bsr->next) {
936          BSR_VOLUME *bsrvol;
937          BSR_VOLFILE *volfile;
938          uint32_t sfile = UINT32_MAX;
939
940          /* Find minimum start file so that we can forward space to it */
941          for (volfile = bsr->volfile; volfile; volfile=volfile->next) {
942             if (volfile->sfile < sfile) {
943                sfile = volfile->sfile;
944             }
945          }
946          /* Now add volumes for this bsr */
947          for (bsrvol = bsr->volume; bsrvol; bsrvol=bsrvol->next) {
948             vol = new_restore_volume();
949             bstrncpy(vol->VolumeName, bsrvol->VolumeName, sizeof(vol->VolumeName));
950             bstrncpy(vol->MediaType,  bsrvol->MediaType,  sizeof(vol->MediaType));
951             bstrncpy(vol->device, bsrvol->device, sizeof(vol->device));
952             vol->Slot = bsrvol->Slot;
953             vol->start_file = sfile;
954             if (add_restore_volume(jcr, vol)) {
955                jcr->NumReadVolumes++;
956                Dmsg2(400, "Added volume=%s mediatype=%s\n", vol->VolumeName,
957                   vol->MediaType);
958             } else {
959                Dmsg1(400, "Duplicate volume %s\n", vol->VolumeName);
960                free((char *)vol);
961             }
962             sfile = 0;                /* start at beginning of second volume */
963          }
964       }
965    } else {
966       /* This is the old way -- deprecated */
967       for (p = jcr->dcr->VolumeName; p && *p; ) {
968          n = strchr(p, '|');             /* volume name separator */
969          if (n) {
970             *n++ = 0;                    /* Terminate name */
971          }
972          vol = new_restore_volume();
973          bstrncpy(vol->VolumeName, p, sizeof(vol->VolumeName));
974          bstrncpy(vol->MediaType, jcr->dcr->media_type, sizeof(vol->MediaType));
975          if (add_restore_volume(jcr, vol)) {
976             jcr->NumReadVolumes++;
977          } else {
978             free((char *)vol);
979          }
980          p = n;
981       }
982    }
983 }
984
985 /*
986  * Add current volume to end of list, only if the Volume
987  * is not already in the list.
988  *
989  *   returns: 1 if volume added
990  *            0 if volume already in list
991  */
992 static bool add_restore_volume(JCR *jcr, VOL_LIST *vol)
993 {
994    VOL_LIST *next = jcr->VolList;
995
996    /* Add volume to volume manager's read list */
997    add_read_volume(jcr, vol->VolumeName);
998
999    if (!next) {                       /* list empty ? */
1000       jcr->VolList = vol;             /* yes, add volume */
1001    } else {
1002       /* Loop through all but last */
1003       for ( ; next->next; next=next->next) {
1004          if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
1005             /* Save smallest start file */
1006             if (vol->start_file < next->start_file) {
1007                next->start_file = vol->start_file;
1008             }
1009             return false;              /* already in list */
1010          }
1011       }
1012       /* Check last volume in list */
1013       if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
1014          if (vol->start_file < next->start_file) {
1015             next->start_file = vol->start_file;
1016          }
1017          return false;                /* already in list */
1018       }
1019       next->next = vol;               /* add volume */
1020    }
1021    return true;
1022 }
1023
1024 void free_restore_volume_list(JCR *jcr)
1025 {
1026    VOL_LIST *vol = jcr->VolList;
1027    VOL_LIST *tmp;
1028
1029    for ( ; vol; ) {
1030       tmp = vol->next;
1031       remove_read_volume(jcr, vol->VolumeName);
1032       free(vol);
1033       vol = tmp;
1034    }
1035    jcr->VolList = NULL;
1036 }
1037
1038
1039 /*
1040  * Format a scanner error message
1041  */
1042 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
1043 {
1044    JCR *jcr = (JCR *)(lc->caller_ctx);
1045    va_list arg_ptr;
1046    char buf[MAXSTRING];
1047
1048    va_start(arg_ptr, msg);
1049    bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
1050    va_end(arg_ptr);
1051
1052    if (jcr) {
1053       Jmsg(jcr, M_FATAL, 0, _("Bootstrap file error: %s\n"
1054 "            : Line %d, col %d of file %s\n%s\n"),
1055          buf, lc->line_no, lc->col_no, lc->fname, lc->line);
1056    } else {
1057       e_msg(file, line, M_FATAL, 0, _("Bootstrap file error: %s\n"
1058 "            : Line %d, col %d of file %s\n%s\n"),
1059          buf, lc->line_no, lc->col_no, lc->fname, lc->line);
1060    }
1061 }