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