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