]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/parse_bsr.c
kes Fix configure to do minimum Win32 configure so that make clean
[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->next->prev = bsr;
239       bsr = bsr->next;
240    }
241    /* This may actually be more than one volume separated by a |
242     * If so, separate them.
243     */
244    for (p=lc->str; p && *p; ) {
245       n = strchr(p, '|');
246       if (n) {
247          *n++ = 0;
248       }
249       volume = (BSR_VOLUME *)malloc(sizeof(BSR_VOLUME));
250       memset(volume, 0, sizeof(BSR_VOLUME));
251       bstrncpy(volume->VolumeName, p, sizeof(volume->VolumeName));
252       /* Add it to the end of the volume chain */
253       if (!bsr->volume) {
254          bsr->volume = volume;
255       } else {
256          BSR_VOLUME *bc = bsr->volume;
257          for ( ;bc->next; bc=bc->next)
258             { }
259          bc->next = volume;
260       }
261       p = n;
262    }
263    return bsr;
264 }
265
266 /* Shove the MediaType in each Volume in the current bsr */
267 static BSR *store_mediatype(LEX *lc, BSR *bsr)
268 {
269    int token;
270
271    token = lex_get_token(lc, T_STRING);
272    if (token == T_ERROR) {
273       return NULL;
274    }
275    if (!bsr->volume) {
276       Emsg1(M_ERROR,0, _("MediaType %s in bsr at inappropriate place.\n"),
277          lc->str);
278       return bsr;
279    }
280    BSR_VOLUME *bv;
281    for (bv=bsr->volume; bv; bv=bv->next) {
282       bstrncpy(bv->MediaType, lc->str, sizeof(bv->MediaType));
283    }
284    return bsr;
285 }
286
287 /* Shove the Device name in each Volume in the current bsr */
288 static BSR *store_device(LEX *lc, BSR *bsr)
289 {
290    int token;
291
292    token = lex_get_token(lc, T_STRING);
293    if (token == T_ERROR) {
294       return NULL;
295    }
296    if (!bsr->volume) {
297       Emsg1(M_ERROR,0, _("Device \"%s\" in bsr at inappropriate place.\n"),
298          lc->str);
299       return bsr;
300    }
301    BSR_VOLUME *bv;
302    for (bv=bsr->volume; bv; bv=bv->next) {
303       bstrncpy(bv->device, lc->str, sizeof(bv->device));
304    }
305    return bsr;
306 }
307
308
309
310 static BSR *store_client(LEX *lc, BSR *bsr)
311 {
312    int token;
313    BSR_CLIENT *client;
314
315    for (;;) {
316       token = lex_get_token(lc, T_NAME);
317       if (token == T_ERROR) {
318          return NULL;
319       }
320       client = (BSR_CLIENT *)malloc(sizeof(BSR_CLIENT));
321       memset(client, 0, sizeof(BSR_CLIENT));
322       bstrncpy(client->ClientName, lc->str, sizeof(client->ClientName));
323       /* Add it to the end of the client chain */
324       if (!bsr->client) {
325          bsr->client = client;
326       } else {
327          BSR_CLIENT *bc = bsr->client;
328          for ( ;bc->next; bc=bc->next)
329             { }
330          bc->next = client;
331       }
332       token = lex_get_token(lc, T_ALL);
333       if (token != T_COMMA) {
334          break;
335       }
336    }
337    return bsr;
338 }
339
340 static BSR *store_job(LEX *lc, BSR *bsr)
341 {
342    int token;
343    BSR_JOB *job;
344
345    for (;;) {
346       token = lex_get_token(lc, T_NAME);
347       if (token == T_ERROR) {
348          return NULL;
349       }
350       job = (BSR_JOB *)malloc(sizeof(BSR_JOB));
351       memset(job, 0, sizeof(BSR_JOB));
352       bstrncpy(job->Job, lc->str, sizeof(job->Job));
353       /* Add it to the end of the client chain */
354       if (!bsr->job) {
355          bsr->job = job;
356       } else {
357          /* Add to end of chain */
358          BSR_JOB *bc = bsr->job;
359          for ( ;bc->next; bc=bc->next)
360             { }
361          bc->next = job;
362       }
363       token = lex_get_token(lc, T_ALL);
364       if (token != T_COMMA) {
365          break;
366       }
367    }
368    return bsr;
369 }
370
371 static BSR *store_findex(LEX *lc, BSR *bsr)
372 {
373    int token;
374    BSR_FINDEX *findex;
375
376    for (;;) {
377       token = lex_get_token(lc, T_PINT32_RANGE);
378       if (token == T_ERROR) {
379          return NULL;
380       }
381       findex = (BSR_FINDEX *)malloc(sizeof(BSR_FINDEX));
382       memset(findex, 0, sizeof(BSR_FINDEX));
383       findex->findex = lc->pint32_val;
384       findex->findex2 = lc->pint32_val2;
385       /* Add it to the end of the chain */
386       if (!bsr->FileIndex) {
387          bsr->FileIndex = findex;
388       } else {
389          /* Add to end of chain */
390          BSR_FINDEX *bs = bsr->FileIndex;
391          for ( ;bs->next; bs=bs->next)
392             {  }
393          bs->next = findex;
394       }
395       token = lex_get_token(lc, T_ALL);
396       if (token != T_COMMA) {
397          break;
398       }
399    }
400    return bsr;
401 }
402
403
404 static BSR *store_jobid(LEX *lc, BSR *bsr)
405 {
406    int token;
407    BSR_JOBID *jobid;
408
409    for (;;) {
410       token = lex_get_token(lc, T_PINT32_RANGE);
411       if (token == T_ERROR) {
412          return NULL;
413       }
414       jobid = (BSR_JOBID *)malloc(sizeof(BSR_JOBID));
415       memset(jobid, 0, sizeof(BSR_JOBID));
416       jobid->JobId = lc->pint32_val;
417       jobid->JobId2 = lc->pint32_val2;
418       /* Add it to the end of the chain */
419       if (!bsr->JobId) {
420          bsr->JobId = jobid;
421       } else {
422          /* Add to end of chain */
423          BSR_JOBID *bs = bsr->JobId;
424          for ( ;bs->next; bs=bs->next)
425             {  }
426          bs->next = jobid;
427       }
428       token = lex_get_token(lc, T_ALL);
429       if (token != T_COMMA) {
430          break;
431       }
432    }
433    return bsr;
434 }
435
436
437 static BSR *store_count(LEX *lc, BSR *bsr)
438 {
439    int token;
440
441    token = lex_get_token(lc, T_PINT32);
442    if (token == T_ERROR) {
443       return NULL;
444    }
445    bsr->count = lc->pint32_val;
446    scan_to_eol(lc);
447    return bsr;
448 }
449
450 static BSR *store_fileregex(LEX *lc, BSR *bsr)
451 {
452    int token;
453    int rc;
454  
455    token = lex_get_token(lc, T_STRING);
456    if (token == T_ERROR) {
457       return NULL;
458    }
459
460    if (bsr->fileregex) free(bsr->fileregex);
461    bsr->fileregex = bstrdup(lc->str);
462
463    if (bsr->fileregex_re == NULL)
464       bsr->fileregex_re = (regex_t *)bmalloc(sizeof(regex_t));
465
466    rc = regcomp(bsr->fileregex_re, bsr->fileregex, REG_EXTENDED|REG_NOSUB);
467    if (rc != 0) {
468       char prbuf[500];
469       regerror(rc, bsr->fileregex_re, prbuf, sizeof(prbuf));
470       Emsg2(M_ERROR, 0, _("REGEX '%s' compile error. ERR=%s\n"),
471             bsr->fileregex, prbuf);
472       return NULL;
473    }
474    return bsr;
475 }
476
477 static BSR *store_jobtype(LEX *lc, BSR *bsr)
478 {
479    /* *****FIXME****** */
480    Pmsg0(-1, _("JobType not yet implemented\n"));
481    return bsr;
482 }
483
484
485 static BSR *store_joblevel(LEX *lc, BSR *bsr)
486 {
487    /* *****FIXME****** */
488    Pmsg0(-1, _("JobLevel not yet implemented\n"));
489    return bsr;
490 }
491
492
493
494
495 /*
496  * Routine to handle Volume start/end file
497  */
498 static BSR *store_volfile(LEX *lc, BSR *bsr)
499 {
500    int token;
501    BSR_VOLFILE *volfile;
502
503    for (;;) {
504       token = lex_get_token(lc, T_PINT32_RANGE);
505       if (token == T_ERROR) {
506          return NULL;
507       }
508       volfile = (BSR_VOLFILE *)malloc(sizeof(BSR_VOLFILE));
509       memset(volfile, 0, sizeof(BSR_VOLFILE));
510       volfile->sfile = lc->pint32_val;
511       volfile->efile = lc->pint32_val2;
512       /* Add it to the end of the chain */
513       if (!bsr->volfile) {
514          bsr->volfile = volfile;
515       } else {
516          /* Add to end of chain */
517          BSR_VOLFILE *bs = bsr->volfile;
518          for ( ;bs->next; bs=bs->next)
519             {  }
520          bs->next = volfile;
521       }
522       token = lex_get_token(lc, T_ALL);
523       if (token != T_COMMA) {
524          break;
525       }
526    }
527    return bsr;
528 }
529
530
531 /*
532  * Routine to handle Volume start/end Block
533  */
534 static BSR *store_volblock(LEX *lc, BSR *bsr)
535 {
536    int token;
537    BSR_VOLBLOCK *volblock;
538
539    for (;;) {
540       token = lex_get_token(lc, T_PINT32_RANGE);
541       if (token == T_ERROR) {
542          return NULL;
543       }
544       volblock = (BSR_VOLBLOCK *)malloc(sizeof(BSR_VOLBLOCK));
545       memset(volblock, 0, sizeof(BSR_VOLBLOCK));
546       volblock->sblock = lc->pint32_val;
547       volblock->eblock = lc->pint32_val2;
548       /* Add it to the end of the chain */
549       if (!bsr->volblock) {
550          bsr->volblock = volblock;
551       } else {
552          /* Add to end of chain */
553          BSR_VOLBLOCK *bs = bsr->volblock;
554          for ( ;bs->next; bs=bs->next)
555             {  }
556          bs->next = volblock;
557       }
558       token = lex_get_token(lc, T_ALL);
559       if (token != T_COMMA) {
560          break;
561       }
562    }
563    return bsr;
564 }
565
566
567 static BSR *store_sessid(LEX *lc, BSR *bsr)
568 {
569    int token;
570    BSR_SESSID *sid;
571
572    for (;;) {
573       token = lex_get_token(lc, T_PINT32_RANGE);
574       if (token == T_ERROR) {
575          return NULL;
576       }
577       sid = (BSR_SESSID *)malloc(sizeof(BSR_SESSID));
578       memset(sid, 0, sizeof(BSR_SESSID));
579       sid->sessid = lc->pint32_val;
580       sid->sessid2 = lc->pint32_val2;
581       /* Add it to the end of the chain */
582       if (!bsr->sessid) {
583          bsr->sessid = sid;
584       } else {
585          /* Add to end of chain */
586          BSR_SESSID *bs = bsr->sessid;
587          for ( ;bs->next; bs=bs->next)
588             {  }
589          bs->next = sid;
590       }
591       token = lex_get_token(lc, T_ALL);
592       if (token != T_COMMA) {
593          break;
594       }
595    }
596    return bsr;
597 }
598
599 static BSR *store_sesstime(LEX *lc, BSR *bsr)
600 {
601    int token;
602    BSR_SESSTIME *stime;
603
604    for (;;) {
605       token = lex_get_token(lc, T_PINT32);
606       if (token == T_ERROR) {
607          return NULL;
608       }
609       stime = (BSR_SESSTIME *)malloc(sizeof(BSR_SESSTIME));
610       memset(stime, 0, sizeof(BSR_SESSTIME));
611       stime->sesstime = lc->pint32_val;
612       /* Add it to the end of the chain */
613       if (!bsr->sesstime) {
614          bsr->sesstime = stime;
615       } else {
616          /* Add to end of chain */
617          BSR_SESSTIME *bs = bsr->sesstime;
618          for ( ;bs->next; bs=bs->next)
619             { }
620          bs->next = stime;
621       }
622       token = lex_get_token(lc, T_ALL);
623       if (token != T_COMMA) {
624          break;
625       }
626    }
627    return bsr;
628 }
629
630
631 static BSR *store_stream(LEX *lc, BSR *bsr)
632 {
633    int token;
634    BSR_STREAM *stream;
635
636    for (;;) {
637       token = lex_get_token(lc, T_INT32);
638       if (token == T_ERROR) {
639          return NULL;
640       }
641       stream = (BSR_STREAM *)malloc(sizeof(BSR_STREAM));
642       memset(stream, 0, sizeof(BSR_STREAM));
643       stream->stream = lc->int32_val;
644       /* Add it to the end of the chain */
645       if (!bsr->stream) {
646          bsr->stream = stream;
647       } else {
648          /* Add to end of chain */
649          BSR_STREAM *bs = bsr->stream;
650          for ( ;bs->next; bs=bs->next)
651             { }
652          bs->next = stream;
653       }
654       token = lex_get_token(lc, T_ALL);
655       if (token != T_COMMA) {
656          break;
657       }
658    }
659    return bsr;
660 }
661
662 static BSR *store_slot(LEX *lc, BSR *bsr)
663 {
664    int token;
665
666    token = lex_get_token(lc, T_PINT32);
667    if (token == T_ERROR) {
668       return NULL;
669    }
670    if (!bsr->volume) {
671       Emsg1(M_ERROR,0, _("Slot %d in bsr at inappropriate place.\n"),
672          lc->pint32_val);
673       return bsr;
674    }
675    bsr->volume->Slot = lc->pint32_val;
676    scan_to_eol(lc);
677    return bsr;
678 }
679
680 static BSR *store_include(LEX *lc, BSR *bsr)
681 {
682    scan_to_eol(lc);
683    return bsr;
684 }
685
686 static BSR *store_exclude(LEX *lc, BSR *bsr)
687 {
688    scan_to_eol(lc);
689    return bsr;
690 }
691
692 void dump_volfile(BSR_VOLFILE *volfile)
693 {
694    if (volfile) {
695       Pmsg2(-1, _("VolFile     : %u-%u\n"), volfile->sfile, volfile->efile);
696       dump_volfile(volfile->next);
697    }
698 }
699
700 void dump_volblock(BSR_VOLBLOCK *volblock)
701 {
702    if (volblock) {
703       Pmsg2(-1, _("VolBlock    : %u-%u\n"), volblock->sblock, volblock->eblock);
704       dump_volblock(volblock->next);
705    }
706 }
707
708
709 void dump_findex(BSR_FINDEX *FileIndex)
710 {
711    if (FileIndex) {
712       if (FileIndex->findex == FileIndex->findex2) {
713          Pmsg1(-1, _("FileIndex   : %u\n"), FileIndex->findex);
714       } else {
715          Pmsg2(-1, _("FileIndex   : %u-%u\n"), FileIndex->findex, FileIndex->findex2);
716       }
717       dump_findex(FileIndex->next);
718    }
719 }
720
721 void dump_jobid(BSR_JOBID *jobid)
722 {
723    if (jobid) {
724       if (jobid->JobId == jobid->JobId2) {
725          Pmsg1(-1, _("JobId       : %u\n"), jobid->JobId);
726       } else {
727          Pmsg2(-1, _("JobId       : %u-%u\n"), jobid->JobId, jobid->JobId2);
728       }
729       dump_jobid(jobid->next);
730    }
731 }
732
733 void dump_sessid(BSR_SESSID *sessid)
734 {
735    if (sessid) {
736       if (sessid->sessid == sessid->sessid2) {
737          Pmsg1(-1, _("SessId      : %u\n"), sessid->sessid);
738       } else {
739          Pmsg2(-1, _("SessId      : %u-%u\n"), sessid->sessid, sessid->sessid2);
740       }
741       dump_sessid(sessid->next);
742    }
743 }
744
745 void dump_volume(BSR_VOLUME *volume)
746 {
747    if (volume) {
748       Pmsg1(-1, _("VolumeName  : %s\n"), volume->VolumeName);
749       Pmsg1(-1, _("  MediaType : %s\n"), volume->MediaType);
750       Pmsg1(-1, _("  Device    : %s\n"), volume->device);
751       Pmsg1(-1, _("  Slot      : %d\n"), volume->Slot);
752       dump_volume(volume->next);
753    }
754 }
755
756
757 void dump_client(BSR_CLIENT *client)
758 {
759    if (client) {
760       Pmsg1(-1, _("Client      : %s\n"), client->ClientName);
761       dump_client(client->next);
762    }
763 }
764
765 void dump_job(BSR_JOB *job)
766 {
767    if (job) {
768       Pmsg1(-1, _("Job          : %s\n"), job->Job);
769       dump_job(job->next);
770    }
771 }
772
773 void dump_sesstime(BSR_SESSTIME *sesstime)
774 {
775    if (sesstime) {
776       Pmsg1(-1, _("SessTime    : %u\n"), sesstime->sesstime);
777       dump_sesstime(sesstime->next);
778    }
779 }
780
781
782 void dump_bsr(BSR *bsr, bool recurse)
783 {
784    int save_debug = debug_level;
785    debug_level = 1;
786    if (!bsr) {
787       Pmsg0(-1, _("BSR is NULL\n"));
788       debug_level = save_debug;
789       return;
790    }
791    Pmsg1(-1,    _("Next        : 0x%x\n"), bsr->next);
792    Pmsg1(-1,    _("Root bsr    : 0x%x\n"), bsr->root);
793    dump_volume(bsr->volume);
794    dump_sessid(bsr->sessid);
795    dump_sesstime(bsr->sesstime);
796    dump_volfile(bsr->volfile);
797    dump_volblock(bsr->volblock);
798    dump_client(bsr->client);
799    dump_jobid(bsr->JobId);
800    dump_job(bsr->job);
801    dump_findex(bsr->FileIndex);
802    if (bsr->count) {
803       Pmsg1(-1, _("count       : %u\n"), bsr->count);
804       Pmsg1(-1, _("found       : %u\n"), bsr->found);
805    }
806
807    Pmsg1(-1,    _("done        : %s\n"), bsr->done?_("yes"):_("no"));
808    Pmsg1(-1,    _("positioning : %d\n"), bsr->use_positioning);
809    Pmsg1(-1,    _("fast_reject : %d\n"), bsr->use_fast_rejection);
810    if (recurse && bsr->next) {
811       Pmsg0(-1, "\n");
812       dump_bsr(bsr->next, true);
813    }
814    debug_level = save_debug;
815 }
816
817
818
819 /*********************************************************************
820  *
821  *      Free bsr resources
822  */
823
824 static void free_bsr_item(BSR *bsr)
825 {
826    if (bsr) {
827       free_bsr_item(bsr->next);
828       free(bsr);
829    }
830 }
831
832 /*
833  * Remove a single item from the bsr tree
834  */
835 void remove_bsr(BSR *bsr)
836 {
837    free_bsr_item((BSR *)bsr->volume);
838    free_bsr_item((BSR *)bsr->client);
839    free_bsr_item((BSR *)bsr->sessid);
840    free_bsr_item((BSR *)bsr->sesstime);
841    free_bsr_item((BSR *)bsr->volfile);
842    free_bsr_item((BSR *)bsr->volblock);
843    free_bsr_item((BSR *)bsr->JobId);
844    free_bsr_item((BSR *)bsr->job);
845    free_bsr_item((BSR *)bsr->FileIndex);
846    free_bsr_item((BSR *)bsr->JobType);
847    free_bsr_item((BSR *)bsr->JobLevel);
848    if (bsr->fileregex) {
849       bfree(bsr->fileregex);
850    }
851    if (bsr->fileregex_re) {
852       regfree(bsr->fileregex_re);
853       free(bsr->fileregex_re);
854    }
855    if (bsr->attr) {
856       free_attr(bsr->attr);
857    }
858    if (bsr->next) {
859       bsr->next->prev = bsr->prev;
860    }
861    if (bsr->prev) {
862       bsr->prev->next = bsr->next;
863    }
864    free(bsr);
865 }
866
867 /*
868  * Free all bsrs in chain
869  */
870 void free_bsr(BSR *bsr)
871 {
872    BSR *next_bsr;
873
874    if (!bsr) {
875       return;
876    }
877    next_bsr = bsr->next;
878    /* Remove (free) current bsr */
879    remove_bsr(bsr);
880    /* Now get the next one */
881    free_bsr(next_bsr);
882 }
883
884 /*****************************************************************
885  * Routines for handling volumes
886  */
887 static VOL_LIST *new_restore_volume()
888 {
889    VOL_LIST *vol;
890    vol = (VOL_LIST *)malloc(sizeof(VOL_LIST));
891    memset(vol, 0, sizeof(VOL_LIST));
892    return vol;
893 }
894
895 /*
896  * Add current volume to end of list, only if the Volume
897  * is not already in the list.
898  *
899  *   returns: 1 if volume added
900  *            0 if volume already in list
901  */
902 static bool add_restore_volume(JCR *jcr, VOL_LIST *vol)
903 {
904    VOL_LIST *next = jcr->VolList;
905
906    /* Add volume to volume manager's read list */
907    add_read_volume(jcr, vol->VolumeName);
908
909    if (!next) {                       /* list empty ? */
910       jcr->VolList = vol;             /* yes, add volume */
911    } else {
912       /* Loop through all but last */
913       for ( ; next->next; next=next->next) {
914          if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
915             /* Save smallest start file */
916             if (vol->start_file < next->start_file) {
917                next->start_file = vol->start_file;
918             }
919             return false;              /* already in list */
920          }
921       }
922       /* Check last volume in list */
923       if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
924          if (vol->start_file < next->start_file) {
925             next->start_file = vol->start_file;
926          }
927          return false;                /* already in list */
928       }
929       next->next = vol;               /* add volume */
930    }
931    return true;
932 }
933
934 void free_restore_volume_list(JCR *jcr)
935 {
936    VOL_LIST *vol = jcr->VolList;
937    VOL_LIST *tmp;
938
939    for ( ; vol; ) {
940       tmp = vol->next;
941       remove_read_volume(jcr, vol->VolumeName);
942       free(vol);
943       vol = tmp;
944    }
945    jcr->VolList = NULL;
946 }
947
948 /*
949  * Create a list of Volumes (and Slots and Start positions) to be
950  *  used in the current restore job.
951  */
952 void create_restore_volume_list(JCR *jcr)
953 {
954    char *p, *n;
955    VOL_LIST *vol;
956
957    /*
958     * Build a list of volumes to be processed
959     */
960    jcr->NumReadVolumes = 0;
961    jcr->CurReadVolume = 0;
962    if (jcr->bsr) {
963       BSR *bsr = jcr->bsr;
964       if (!bsr->volume || !bsr->volume->VolumeName) {
965          return;
966       }
967       for ( ; bsr; bsr=bsr->next) {
968          BSR_VOLUME *bsrvol;
969          BSR_VOLFILE *volfile;
970          uint32_t sfile = UINT32_MAX;
971
972          /* Find minimum start file so that we can forward space to it */
973          for (volfile = bsr->volfile; volfile; volfile=volfile->next) {
974             if (volfile->sfile < sfile) {
975                sfile = volfile->sfile;
976             }
977          }
978          /* Now add volumes for this bsr */
979          for (bsrvol = bsr->volume; bsrvol; bsrvol=bsrvol->next) {
980             vol = new_restore_volume();
981             bstrncpy(vol->VolumeName, bsrvol->VolumeName, sizeof(vol->VolumeName));
982             bstrncpy(vol->MediaType,  bsrvol->MediaType,  sizeof(vol->MediaType));
983             bstrncpy(vol->device, bsrvol->device, sizeof(vol->device));
984             vol->Slot = bsrvol->Slot;
985             vol->start_file = sfile;
986             if (add_restore_volume(jcr, vol)) {
987                jcr->NumReadVolumes++;
988                Dmsg2(400, "Added volume=%s mediatype=%s\n", vol->VolumeName,
989                   vol->MediaType);
990             } else {
991                Dmsg1(400, "Duplicate volume %s\n", vol->VolumeName);
992                free((char *)vol);
993             }
994             sfile = 0;                /* start at beginning of second volume */
995          }
996       }
997    } else {
998       /* This is the old way -- deprecated */
999       for (p = jcr->dcr->VolumeName; p && *p; ) {
1000          n = strchr(p, '|');             /* volume name separator */
1001          if (n) {
1002             *n++ = 0;                    /* Terminate name */
1003          }
1004          vol = new_restore_volume();
1005          bstrncpy(vol->VolumeName, p, sizeof(vol->VolumeName));
1006          bstrncpy(vol->MediaType, jcr->dcr->media_type, sizeof(vol->MediaType));
1007          if (add_restore_volume(jcr, vol)) {
1008             jcr->NumReadVolumes++;
1009          } else {
1010             free((char *)vol);
1011          }
1012          p = n;
1013       }
1014    }
1015 }