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