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