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