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