]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/parse_bsr.c
Change copyright as per agreement with FSFE
[bacula/bacula] / bacula / src / stored / parse_bsr.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2016 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);
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 static 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(BSR_VOLADDR *voladdr)
724 {
725    if (voladdr) {
726       Pmsg2(-1, _("VolAddr    : %llu-%llu\n"), voladdr->saddr, voladdr->eaddr);
727       dump_voladdr(voladdr->next);
728    }
729 }
730
731 void dump_findex(BSR_FINDEX *FileIndex)
732 {
733    if (FileIndex) {
734       if (FileIndex->findex == FileIndex->findex2) {
735          Pmsg1(-1, _("FileIndex   : %u\n"), FileIndex->findex);
736       } else {
737          Pmsg2(-1, _("FileIndex   : %u-%u\n"), FileIndex->findex, FileIndex->findex2);
738       }
739       dump_findex(FileIndex->next);
740    }
741 }
742
743 void dump_jobid(BSR_JOBID *jobid)
744 {
745    if (jobid) {
746       if (jobid->JobId == jobid->JobId2) {
747          Pmsg1(-1, _("JobId       : %u\n"), jobid->JobId);
748       } else {
749          Pmsg2(-1, _("JobId       : %u-%u\n"), jobid->JobId, jobid->JobId2);
750       }
751       dump_jobid(jobid->next);
752    }
753 }
754
755 void dump_sessid(BSR_SESSID *sessid)
756 {
757    if (sessid) {
758       if (sessid->sessid == sessid->sessid2) {
759          Pmsg1(-1, _("SessId      : %u\n"), sessid->sessid);
760       } else {
761          Pmsg2(-1, _("SessId      : %u-%u\n"), sessid->sessid, sessid->sessid2);
762       }
763       dump_sessid(sessid->next);
764    }
765 }
766
767 void dump_volume(BSR_VOLUME *volume)
768 {
769    if (volume) {
770       Pmsg1(-1, _("VolumeName  : %s\n"), volume->VolumeName);
771       Pmsg1(-1, _("  MediaType : %s\n"), volume->MediaType);
772       Pmsg1(-1, _("  Device    : %s\n"), volume->device);
773       Pmsg1(-1, _("  Slot      : %d\n"), volume->Slot);
774       dump_volume(volume->next);
775    }
776 }
777
778
779 void dump_client(BSR_CLIENT *client)
780 {
781    if (client) {
782       Pmsg1(-1, _("Client      : %s\n"), client->ClientName);
783       dump_client(client->next);
784    }
785 }
786
787 void dump_job(BSR_JOB *job)
788 {
789    if (job) {
790       Pmsg1(-1, _("Job          : %s\n"), job->Job);
791       dump_job(job->next);
792    }
793 }
794
795 void dump_sesstime(BSR_SESSTIME *sesstime)
796 {
797    if (sesstime) {
798       Pmsg1(-1, _("SessTime    : %u\n"), sesstime->sesstime);
799       dump_sesstime(sesstime->next);
800    }
801 }
802
803
804 void dump_bsr(BSR *bsr, bool recurse)
805 {
806    int64_t save_debug = debug_level;
807    debug_level = 1;
808    if (!bsr) {
809       Pmsg0(-1, _("BSR is NULL\n"));
810       debug_level = save_debug;
811       return;
812    }
813    Pmsg1(-1,    _("Next        : 0x%x\n"), bsr->next);
814    Pmsg1(-1,    _("Root bsr    : 0x%x\n"), bsr->root);
815    dump_volume(bsr->volume);
816    dump_sessid(bsr->sessid);
817    dump_sesstime(bsr->sesstime);
818    dump_volfile(bsr->volfile);
819    dump_volblock(bsr->volblock);
820    dump_voladdr(bsr->voladdr);
821    dump_client(bsr->client);
822    dump_jobid(bsr->JobId);
823    dump_job(bsr->job);
824    dump_findex(bsr->FileIndex);
825    if (bsr->count) {
826       Pmsg1(-1, _("count       : %u\n"), bsr->count);
827       Pmsg1(-1, _("found       : %u\n"), bsr->found);
828    }
829
830    Pmsg1(-1,    _("done        : %s\n"), bsr->done?_("yes"):_("no"));
831    Pmsg1(-1,    _("positioning : %d\n"), bsr->use_positioning);
832    Pmsg1(-1,    _("fast_reject : %d\n"), bsr->use_fast_rejection);
833    if (recurse && bsr->next) {
834       Pmsg0(-1, "\n");
835       dump_bsr(bsr->next, true);
836    }
837    debug_level = save_debug;
838 }
839
840
841
842 /*********************************************************************
843  *
844  *      Free bsr resources
845  */
846
847 static void free_bsr_item(BSR *bsr)
848 {
849    BSR *next;
850    while (bsr) {
851       next = bsr->next;
852       free(bsr);
853       bsr = next;
854    }
855 }
856
857 /*
858  * Remove a single item from the bsr tree
859  */
860 void remove_bsr(BSR *bsr)
861 {
862    free_bsr_item((BSR *)bsr->volume);
863    free_bsr_item((BSR *)bsr->client);
864    free_bsr_item((BSR *)bsr->sessid);
865    free_bsr_item((BSR *)bsr->sesstime);
866    free_bsr_item((BSR *)bsr->volfile);
867    free_bsr_item((BSR *)bsr->volblock);
868    free_bsr_item((BSR *)bsr->voladdr);
869    free_bsr_item((BSR *)bsr->JobId);
870    free_bsr_item((BSR *)bsr->job);
871    free_bsr_item((BSR *)bsr->FileIndex);
872    free_bsr_item((BSR *)bsr->JobType);
873    free_bsr_item((BSR *)bsr->JobLevel);
874    if (bsr->fileregex) {
875       bfree(bsr->fileregex);
876    }
877    if (bsr->fileregex_re) {
878       regfree(bsr->fileregex_re);
879       free(bsr->fileregex_re);
880    }
881    if (bsr->attr) {
882       free_attr(bsr->attr);
883    }
884    if (bsr->next) {
885       bsr->next->prev = bsr->prev;
886    }
887    if (bsr->prev) {
888       bsr->prev->next = bsr->next;
889    }
890    free(bsr);
891 }
892
893 /*
894  * Free all bsrs in chain
895  */
896 void free_bsr(BSR *bsr)
897 {
898    BSR *next_bsr;
899    while (bsr) {
900       next_bsr = bsr->next;
901       /* Remove (free) current bsr */
902       remove_bsr(bsr);
903       /* Now get the next one */
904       bsr = next_bsr;
905    }
906 }
907
908 /*****************************************************************
909  * Routines for handling volumes
910  */
911 static VOL_LIST *new_restore_volume()
912 {
913    VOL_LIST *vol;
914    vol = (VOL_LIST *)malloc(sizeof(VOL_LIST));
915    memset(vol, 0, sizeof(VOL_LIST));
916    return vol;
917 }
918
919 /*
920  * Create a list of Volumes (and Slots and Start positions) to be
921  *  used in the current restore job.
922  */
923 void create_restore_volume_list(JCR *jcr)
924 {
925    char *p, *n;
926    VOL_LIST *vol;
927
928    /*
929     * Build a list of volumes to be processed
930     */
931    jcr->NumReadVolumes = 0;
932    jcr->CurReadVolume = 0;
933    if (jcr->bsr) {
934       BSR *bsr = jcr->bsr;
935       if (!bsr->volume || !bsr->volume->VolumeName[0]) {
936          return;
937       }
938       for ( ; bsr; bsr=bsr->next) {
939          BSR_VOLUME *bsrvol;
940          BSR_VOLFILE *volfile;
941          uint32_t sfile = UINT32_MAX;
942
943          /* Find minimum start file so that we can forward space to it */
944          for (volfile = bsr->volfile; volfile; volfile=volfile->next) {
945             if (volfile->sfile < sfile) {
946                sfile = volfile->sfile;
947             }
948          }
949          /* Now add volumes for this bsr */
950          for (bsrvol = bsr->volume; bsrvol; bsrvol=bsrvol->next) {
951             vol = new_restore_volume();
952             bstrncpy(vol->VolumeName, bsrvol->VolumeName, sizeof(vol->VolumeName));
953             bstrncpy(vol->MediaType,  bsrvol->MediaType,  sizeof(vol->MediaType));
954             bstrncpy(vol->device, bsrvol->device, sizeof(vol->device));
955             vol->Slot = bsrvol->Slot;
956             vol->start_file = sfile;
957             if (add_restore_volume(jcr, vol)) {
958                jcr->NumReadVolumes++;
959                Dmsg2(400, "Added volume=%s mediatype=%s\n", vol->VolumeName,
960                   vol->MediaType);
961             } else {
962                Dmsg1(400, "Duplicate volume %s\n", vol->VolumeName);
963                free((char *)vol);
964             }
965             sfile = 0;                /* start at beginning of second volume */
966          }
967       }
968    } else {
969       /* This is the old way -- deprecated */
970       for (p = jcr->dcr->VolumeName; p && *p; ) {
971          n = strchr(p, '|');             /* volume name separator */
972          if (n) {
973             *n++ = 0;                    /* Terminate name */
974          }
975          vol = new_restore_volume();
976          bstrncpy(vol->VolumeName, p, sizeof(vol->VolumeName));
977          bstrncpy(vol->MediaType, jcr->dcr->media_type, sizeof(vol->MediaType));
978          if (add_restore_volume(jcr, vol)) {
979             jcr->NumReadVolumes++;
980          } else {
981             free((char *)vol);
982          }
983          p = n;
984       }
985    }
986 }
987
988 /*
989  * Add current volume to end of list, only if the Volume
990  * is not already in the list.
991  *
992  *   returns: 1 if volume added
993  *            0 if volume already in list
994  */
995 static bool add_restore_volume(JCR *jcr, VOL_LIST *vol)
996 {
997    VOL_LIST *next = jcr->VolList;
998
999    /* Add volume to volume manager's read list */
1000    add_read_volume(jcr, vol->VolumeName);
1001
1002    if (!next) {                       /* list empty ? */
1003       jcr->VolList = vol;             /* yes, add volume */
1004    } else {
1005       /* Loop through all but last */
1006       for ( ; next->next; next=next->next) {
1007          if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
1008             /* Save smallest start file */
1009             if (vol->start_file < next->start_file) {
1010                next->start_file = vol->start_file;
1011             }
1012             return false;              /* already in list */
1013          }
1014       }
1015       /* Check last volume in list */
1016       if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
1017          if (vol->start_file < next->start_file) {
1018             next->start_file = vol->start_file;
1019          }
1020          return false;                /* already in list */
1021       }
1022       next->next = vol;               /* add volume */
1023    }
1024    return true;
1025 }
1026
1027 void free_restore_volume_list(JCR *jcr)
1028 {
1029    VOL_LIST *vol = jcr->VolList;
1030    VOL_LIST *tmp;
1031
1032    for ( ; vol; ) {
1033       tmp = vol->next;
1034       remove_read_volume(jcr, vol->VolumeName);
1035       free(vol);
1036       vol = tmp;
1037    }
1038    jcr->VolList = NULL;
1039 }
1040
1041
1042 /*
1043  * Format a scanner error message
1044  */
1045 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
1046 {
1047    JCR *jcr = (JCR *)(lc->caller_ctx);
1048    va_list arg_ptr;
1049    char buf[MAXSTRING];
1050
1051    va_start(arg_ptr, msg);
1052    bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
1053    va_end(arg_ptr);
1054
1055    if (jcr) {
1056       Jmsg(jcr, M_FATAL, 0, _("Bootstrap file error: %s\n"
1057 "            : Line %d, col %d of file %s\n%s\n"),
1058          buf, lc->line_no, lc->col_no, lc->fname, lc->line);
1059    } else {
1060       e_msg(file, line, M_FATAL, 0, _("Bootstrap file error: %s\n"
1061 "            : Line %d, col %d of file %s\n%s\n"),
1062          buf, lc->line_no, lc->col_no, lc->fname, lc->line);
1063    }
1064 }