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