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