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