]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/parse_bsr.c
Add mac.c file
[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
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_client(LEX *lc, BSR *bsr);
33 static BSR *store_job(LEX *lc, BSR *bsr);
34 static BSR *store_jobid(LEX *lc, BSR *bsr);
35 static BSR *store_count(LEX *lc, BSR *bsr);
36 static BSR *store_jobtype(LEX *lc, BSR *bsr);
37 static BSR *store_joblevel(LEX *lc, BSR *bsr);
38 static BSR *store_findex(LEX *lc, BSR *bsr);
39 static BSR *store_sessid(LEX *lc, BSR *bsr);
40 static BSR *store_volfile(LEX *lc, BSR *bsr);
41 static BSR *store_volblock(LEX *lc, BSR *bsr);
42 static BSR *store_sesstime(LEX *lc, BSR *bsr);
43 static BSR *store_include(LEX *lc, BSR *bsr);
44 static BSR *store_exclude(LEX *lc, BSR *bsr);
45 static BSR *store_stream(LEX *lc, BSR *bsr);
46 static BSR *store_slot(LEX *lc, BSR *bsr);
47 static bool is_fast_rejection_ok(BSR *bsr);
48 static bool is_positioning_ok(BSR *bsr);
49
50 struct kw_items {
51    const char *name;
52    ITEM_HANDLER *handler;
53 };
54
55 /*
56  * List of all keywords permitted in bsr files and their handlers
57  */
58 struct kw_items items[] = {
59    {"volume", store_vol},
60    {"mediatype", store_mediatype},
61    {"client", store_client},
62    {"job", store_job},
63    {"jobid", store_jobid},
64    {"count", store_count},
65    {"fileindex", store_findex},
66    {"jobtype", store_jobtype},
67    {"joblevel", store_joblevel},
68    {"volsessionid", store_sessid},
69    {"volsessiontime", store_sesstime},
70    {"include", store_include},
71    {"exclude", store_exclude},
72    {"volfile", store_volfile},
73    {"volblock", store_volblock},
74    {"stream",  store_stream},
75    {"slot",    store_slot},
76    {NULL, NULL}
77
78 };
79
80 /*
81  * Create a BSR record
82  */
83 static BSR *new_bsr()
84 {
85    BSR *bsr = (BSR *)malloc(sizeof(BSR));
86    memset(bsr, 0, sizeof(BSR));
87    return bsr;
88 }
89
90 /*
91  * Format a scanner error message
92  */
93 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
94 {
95    JCR *jcr = (JCR *)(lc->caller_ctx);
96    va_list arg_ptr;
97    char buf[MAXSTRING];
98
99    va_start(arg_ptr, msg);
100    bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
101    va_end(arg_ptr);
102
103    if (jcr) {
104       Jmsg(jcr, M_FATAL, 0, _("Bootstrap file error: %s\n"
105 "            : Line %d, col %d of file %s\n%s\n"),
106          buf, lc->line_no, lc->col_no, lc->fname, lc->line);
107    } else {
108       e_msg(file, line, 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    }
112 }
113
114
115 /*********************************************************************
116  *
117  *      Parse Bootstrap file
118  *
119  */
120 BSR *parse_bsr(JCR *jcr, char *fname)
121 {
122    LEX *lc = NULL;
123    int token, i;
124    BSR *root_bsr = new_bsr();
125    BSR *bsr = root_bsr;
126
127    Dmsg1(200, "Enter parse_bsf %s\n", fname);
128    if ((lc = lex_open_file(lc, fname, s_err)) == NULL) {
129       berrno be;
130       Emsg2(M_ERROR_TERM, 0, _("Cannot open bootstrap file %s: %s\n"),
131             fname, be.strerror());
132    }
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    Pmsg0(-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    Pmsg0(-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       Pmsg2(-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       Pmsg2(-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          Pmsg1(-1, _("FileIndex   : %u\n"), FileIndex->findex);
645       } else {
646          Pmsg2(-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          Pmsg1(-1, _("JobId       : %u\n"), jobid->JobId);
657       } else {
658          Pmsg2(-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          Pmsg1(-1, _("SessId      : %u\n"), sessid->sessid);
669       } else {
670          Pmsg2(-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       Pmsg1(-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       Pmsg1(-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       Pmsg1(-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       Pmsg1(-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       Pmsg0(-1, _("BSR is NULL\n"));
719       debug_level = save_debug;
720       return;
721    }
722    Pmsg1(-1,    _("Next        : 0x%x\n"), bsr->next);
723    Pmsg1(-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       Pmsg1(-1, _("Slot        : %u\n"), bsr->Slot);
735    }
736    if (bsr->count) {
737       Pmsg1(-1, _("count       : %u\n"), bsr->count);
738       Pmsg1(-1, _("found       : %u\n"), bsr->found);
739    }
740
741    Pmsg1(-1,    _("done        : %s\n"), bsr->done?_("yes"):_("no"));
742    Pmsg1(-1,    _("positioning : %d\n"), bsr->use_positioning);
743    Pmsg1(-1,    _("fast_reject : %d\n"), bsr->use_fast_rejection);
744    if (recurse && bsr->next) {
745       Pmsg0(-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_restore_volume()
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_restore_volume(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_restore_volume_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_restore_volume_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_restore_volume();
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_restore_volume(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_restore_volume();
898          bstrncpy(vol->VolumeName, p, sizeof(vol->VolumeName));
899          bstrncpy(vol->MediaType, jcr->dcr->media_type, sizeof(vol->MediaType));
900          if (add_restore_volume(jcr, vol)) {
901             jcr->NumVolumes++;
902          } else {
903             free((char *)vol);
904          }
905          p = n;
906       }
907    }
908 }