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