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