2 * Parse a Bootstrap Records (used for restores)
4 * Kern Sibbald, June MMII
10 Copyright (C) 2002-2005 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
28 typedef BSR * (ITEM_HANDLER)(LEX *lc, BSR *bsr);
30 static BSR *store_vol(LEX *lc, BSR *bsr);
31 static BSR *store_mediatype(LEX *lc, BSR *bsr);
32 static BSR *store_client(LEX *lc, BSR *bsr);
33 static BSR *store_job(LEX *lc, BSR *bsr);
34 static BSR *store_jobid(LEX *lc, BSR *bsr);
35 static BSR *store_count(LEX *lc, BSR *bsr);
36 static BSR *store_jobtype(LEX *lc, BSR *bsr);
37 static BSR *store_joblevel(LEX *lc, BSR *bsr);
38 static BSR *store_findex(LEX *lc, BSR *bsr);
39 static BSR *store_sessid(LEX *lc, BSR *bsr);
40 static BSR *store_volfile(LEX *lc, BSR *bsr);
41 static BSR *store_volblock(LEX *lc, BSR *bsr);
42 static BSR *store_sesstime(LEX *lc, BSR *bsr);
43 static BSR *store_include(LEX *lc, BSR *bsr);
44 static BSR *store_exclude(LEX *lc, BSR *bsr);
45 static BSR *store_stream(LEX *lc, BSR *bsr);
46 static BSR *store_slot(LEX *lc, BSR *bsr);
47 static bool is_fast_rejection_ok(BSR *bsr);
48 static bool is_positioning_ok(BSR *bsr);
52 ITEM_HANDLER *handler;
56 * List of all keywords permitted in bsr files and their handlers
58 struct kw_items items[] = {
59 {"volume", store_vol},
60 {"mediatype", store_mediatype},
61 {"client", store_client},
63 {"jobid", store_jobid},
64 {"count", store_count},
65 {"fileindex", store_findex},
66 {"jobtype", store_jobtype},
67 {"joblevel", store_joblevel},
68 {"volsessionid", store_sessid},
69 {"volsessiontime", store_sesstime},
70 {"include", store_include},
71 {"exclude", store_exclude},
72 {"volfile", store_volfile},
73 {"volblock", store_volblock},
74 {"stream", store_stream},
85 BSR *bsr = (BSR *)malloc(sizeof(BSR));
86 memset(bsr, 0, sizeof(BSR));
91 * Format a scanner error message
93 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
95 JCR *jcr = (JCR *)(lc->caller_ctx);
99 va_start(arg_ptr, msg);
100 bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
104 Jmsg(jcr, M_FATAL, 0, _("Bootstrap file error: %s\n"
105 " : Line %d, col %d of file %s\n%s\n"),
106 buf, lc->line_no, lc->col_no, lc->fname, lc->line);
108 e_msg(file, line, M_FATAL, 0, _("Bootstrap file error: %s\n"
109 " : Line %d, col %d of file %s\n%s\n"),
110 buf, lc->line_no, lc->col_no, lc->fname, lc->line);
115 /*********************************************************************
117 * Parse Bootstrap file
120 BSR *parse_bsr(JCR *jcr, char *fname)
124 BSR *root_bsr = new_bsr();
127 Dmsg1(200, "Enter parse_bsf %s\n", fname);
128 if ((lc = lex_open_file(lc, fname, s_err)) == NULL) {
130 Emsg2(M_ERROR_TERM, 0, _("Cannot open bootstrap file %s: %s\n"),
131 fname, be.strerror());
133 lc->caller_ctx = (void *)jcr;
134 while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
135 Dmsg1(200, "parse got token=%s\n", lex_tok_to_str(token));
136 if (token == T_EOL) {
139 for (i=0; items[i].name; i++) {
140 if (strcasecmp(items[i].name, lc->str) == 0) {
141 token = lex_get_token(lc, T_ALL);
142 Dmsg1 (200, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
143 if (token != T_EQUALS) {
144 scan_err1(lc, "expected an equals, got: %s", lc->str);
148 Dmsg1(200, "calling handler for %s\n", items[i].name);
149 /* Call item handler */
150 bsr = items[i].handler(lc, bsr);
156 Dmsg1(200, "Keyword = %s\n", lc->str);
157 scan_err1(lc, "Keyword %s not found", lc->str);
165 lc = lex_close_file(lc);
166 Dmsg0(200, "Leave parse_bsf()\n");
172 root_bsr->use_fast_rejection = is_fast_rejection_ok(root_bsr);
173 root_bsr->use_positioning = is_positioning_ok(root_bsr);
175 for (bsr=root_bsr; bsr; bsr=bsr->next) {
176 bsr->root = root_bsr;
181 static bool is_fast_rejection_ok(BSR *bsr)
184 * Although, this can be optimized, for the moment, require
185 * all bsrs to have both sesstime and sessid set before
186 * we do fast rejection.
188 for ( ; bsr; bsr=bsr->next) {
189 if (!(bsr->sesstime && bsr->sessid)) {
196 static bool is_positioning_ok(BSR *bsr)
199 * Every bsr should have a volfile entry and a volblock entry
200 * if we are going to use positioning
202 for ( ; bsr; bsr=bsr->next) {
203 if (!bsr->volfile || !bsr->volblock) {
211 static BSR *store_vol(LEX *lc, BSR *bsr)
217 token = lex_get_token(lc, T_STRING);
218 if (token == T_ERROR) {
222 bsr->next = new_bsr();
225 /* This may actually be more than one volume separated by a |
226 * If so, separate them.
228 for (p=lc->str; p && *p; ) {
233 volume = (BSR_VOLUME *)malloc(sizeof(BSR_VOLUME));
234 memset(volume, 0, sizeof(BSR_VOLUME));
235 bstrncpy(volume->VolumeName, p, sizeof(volume->VolumeName));
236 /* Add it to the end of the volume chain */
238 bsr->volume = volume;
240 BSR_VOLUME *bc = bsr->volume;
241 for ( ;bc->next; bc=bc->next)
250 /* Shove the MediaType in each Volume in the current bsr */
251 static BSR *store_mediatype(LEX *lc, BSR *bsr)
255 token = lex_get_token(lc, T_STRING);
256 if (token == T_ERROR) {
260 Emsg1(M_ERROR,0, _("MediaType %s in bsr at inappropriate place.\n"),
265 for (bv=bsr->volume; bv; bv=bv->next) {
266 bstrncpy(bv->MediaType, lc->str, sizeof(bv->MediaType));
272 static BSR *store_client(LEX *lc, BSR *bsr)
278 token = lex_get_token(lc, T_NAME);
279 if (token == T_ERROR) {
282 client = (BSR_CLIENT *)malloc(sizeof(BSR_CLIENT));
283 memset(client, 0, sizeof(BSR_CLIENT));
284 bstrncpy(client->ClientName, lc->str, sizeof(client->ClientName));
285 /* Add it to the end of the client chain */
287 bsr->client = client;
289 BSR_CLIENT *bc = bsr->client;
290 for ( ;bc->next; bc=bc->next)
294 token = lex_get_token(lc, T_ALL);
295 if (token != T_COMMA) {
302 static BSR *store_job(LEX *lc, BSR *bsr)
308 token = lex_get_token(lc, T_NAME);
309 if (token == T_ERROR) {
312 job = (BSR_JOB *)malloc(sizeof(BSR_JOB));
313 memset(job, 0, sizeof(BSR_JOB));
314 bstrncpy(job->Job, lc->str, sizeof(job->Job));
315 /* Add it to the end of the client chain */
319 /* Add to end of chain */
320 BSR_JOB *bc = bsr->job;
321 for ( ;bc->next; bc=bc->next)
325 token = lex_get_token(lc, T_ALL);
326 if (token != T_COMMA) {
333 static BSR *store_findex(LEX *lc, BSR *bsr)
339 token = lex_get_token(lc, T_PINT32_RANGE);
340 if (token == T_ERROR) {
343 findex = (BSR_FINDEX *)malloc(sizeof(BSR_FINDEX));
344 memset(findex, 0, sizeof(BSR_FINDEX));
345 findex->findex = lc->pint32_val;
346 findex->findex2 = lc->pint32_val2;
347 /* Add it to the end of the chain */
348 if (!bsr->FileIndex) {
349 bsr->FileIndex = findex;
351 /* Add to end of chain */
352 BSR_FINDEX *bs = bsr->FileIndex;
353 for ( ;bs->next; bs=bs->next)
357 token = lex_get_token(lc, T_ALL);
358 if (token != T_COMMA) {
366 static BSR *store_jobid(LEX *lc, BSR *bsr)
372 token = lex_get_token(lc, T_PINT32_RANGE);
373 if (token == T_ERROR) {
376 jobid = (BSR_JOBID *)malloc(sizeof(BSR_JOBID));
377 memset(jobid, 0, sizeof(BSR_JOBID));
378 jobid->JobId = lc->pint32_val;
379 jobid->JobId2 = lc->pint32_val2;
380 /* Add it to the end of the chain */
384 /* Add to end of chain */
385 BSR_JOBID *bs = bsr->JobId;
386 for ( ;bs->next; bs=bs->next)
390 token = lex_get_token(lc, T_ALL);
391 if (token != T_COMMA) {
399 static BSR *store_count(LEX *lc, BSR *bsr)
403 token = lex_get_token(lc, T_PINT32);
404 if (token == T_ERROR) {
407 bsr->count = lc->pint32_val;
413 static BSR *store_jobtype(LEX *lc, BSR *bsr)
415 /* *****FIXME****** */
416 Pmsg0(-1, _("JobType not yet implemented\n"));
421 static BSR *store_joblevel(LEX *lc, BSR *bsr)
423 /* *****FIXME****** */
424 Pmsg0(-1, _("JobLevel not yet implemented\n"));
432 * Routine to handle Volume start/end file
434 static BSR *store_volfile(LEX *lc, BSR *bsr)
437 BSR_VOLFILE *volfile;
440 token = lex_get_token(lc, T_PINT32_RANGE);
441 if (token == T_ERROR) {
444 volfile = (BSR_VOLFILE *)malloc(sizeof(BSR_VOLFILE));
445 memset(volfile, 0, sizeof(BSR_VOLFILE));
446 volfile->sfile = lc->pint32_val;
447 volfile->efile = lc->pint32_val2;
448 /* Add it to the end of the chain */
450 bsr->volfile = volfile;
452 /* Add to end of chain */
453 BSR_VOLFILE *bs = bsr->volfile;
454 for ( ;bs->next; bs=bs->next)
458 token = lex_get_token(lc, T_ALL);
459 if (token != T_COMMA) {
468 * Routine to handle Volume start/end Block
470 static BSR *store_volblock(LEX *lc, BSR *bsr)
473 BSR_VOLBLOCK *volblock;
476 token = lex_get_token(lc, T_PINT32_RANGE);
477 if (token == T_ERROR) {
480 volblock = (BSR_VOLBLOCK *)malloc(sizeof(BSR_VOLBLOCK));
481 memset(volblock, 0, sizeof(BSR_VOLBLOCK));
482 volblock->sblock = lc->pint32_val;
483 volblock->eblock = lc->pint32_val2;
484 /* Add it to the end of the chain */
485 if (!bsr->volblock) {
486 bsr->volblock = volblock;
488 /* Add to end of chain */
489 BSR_VOLBLOCK *bs = bsr->volblock;
490 for ( ;bs->next; bs=bs->next)
494 token = lex_get_token(lc, T_ALL);
495 if (token != T_COMMA) {
503 static BSR *store_sessid(LEX *lc, BSR *bsr)
509 token = lex_get_token(lc, T_PINT32_RANGE);
510 if (token == T_ERROR) {
513 sid = (BSR_SESSID *)malloc(sizeof(BSR_SESSID));
514 memset(sid, 0, sizeof(BSR_SESSID));
515 sid->sessid = lc->pint32_val;
516 sid->sessid2 = lc->pint32_val2;
517 /* Add it to the end of the chain */
521 /* Add to end of chain */
522 BSR_SESSID *bs = bsr->sessid;
523 for ( ;bs->next; bs=bs->next)
527 token = lex_get_token(lc, T_ALL);
528 if (token != T_COMMA) {
535 static BSR *store_sesstime(LEX *lc, BSR *bsr)
541 token = lex_get_token(lc, T_PINT32);
542 if (token == T_ERROR) {
545 stime = (BSR_SESSTIME *)malloc(sizeof(BSR_SESSTIME));
546 memset(stime, 0, sizeof(BSR_SESSTIME));
547 stime->sesstime = lc->pint32_val;
548 /* Add it to the end of the chain */
549 if (!bsr->sesstime) {
550 bsr->sesstime = stime;
552 /* Add to end of chain */
553 BSR_SESSTIME *bs = bsr->sesstime;
554 for ( ;bs->next; bs=bs->next)
558 token = lex_get_token(lc, T_ALL);
559 if (token != T_COMMA) {
567 static BSR *store_stream(LEX *lc, BSR *bsr)
573 token = lex_get_token(lc, T_INT32);
574 if (token == T_ERROR) {
577 stream = (BSR_STREAM *)malloc(sizeof(BSR_STREAM));
578 memset(stream, 0, sizeof(BSR_STREAM));
579 stream->stream = lc->int32_val;
580 /* Add it to the end of the chain */
582 bsr->stream = stream;
584 /* Add to end of chain */
585 BSR_STREAM *bs = bsr->stream;
586 for ( ;bs->next; bs=bs->next)
590 token = lex_get_token(lc, T_ALL);
591 if (token != T_COMMA) {
598 static BSR *store_slot(LEX *lc, BSR *bsr)
602 token = lex_get_token(lc, T_PINT32);
603 if (token == T_ERROR) {
606 bsr->Slot = lc->pint32_val;
611 static BSR *store_include(LEX *lc, BSR *bsr)
617 static BSR *store_exclude(LEX *lc, BSR *bsr)
623 void dump_volfile(BSR_VOLFILE *volfile)
626 Pmsg2(-1, _("VolFile : %u-%u\n"), volfile->sfile, volfile->efile);
627 dump_volfile(volfile->next);
631 void dump_volblock(BSR_VOLBLOCK *volblock)
634 Pmsg2(-1, _("VolBlock : %u-%u\n"), volblock->sblock, volblock->eblock);
635 dump_volblock(volblock->next);
640 void dump_findex(BSR_FINDEX *FileIndex)
643 if (FileIndex->findex == FileIndex->findex2) {
644 Pmsg1(-1, _("FileIndex : %u\n"), FileIndex->findex);
646 Pmsg2(-1, _("FileIndex : %u-%u\n"), FileIndex->findex, FileIndex->findex2);
648 dump_findex(FileIndex->next);
652 void dump_jobid(BSR_JOBID *jobid)
655 if (jobid->JobId == jobid->JobId2) {
656 Pmsg1(-1, _("JobId : %u\n"), jobid->JobId);
658 Pmsg2(-1, _("JobId : %u-%u\n"), jobid->JobId, jobid->JobId2);
660 dump_jobid(jobid->next);
664 void dump_sessid(BSR_SESSID *sessid)
667 if (sessid->sessid == sessid->sessid2) {
668 Pmsg1(-1, _("SessId : %u\n"), sessid->sessid);
670 Pmsg2(-1, _("SessId : %u-%u\n"), sessid->sessid, sessid->sessid2);
672 dump_sessid(sessid->next);
676 void dump_volume(BSR_VOLUME *volume)
679 Pmsg1(-1, _("VolumeName : %s\n"), volume->VolumeName);
680 dump_volume(volume->next);
685 void dump_client(BSR_CLIENT *client)
688 Pmsg1(-1, _("Client : %s\n"), client->ClientName);
689 dump_client(client->next);
693 void dump_job(BSR_JOB *job)
696 Pmsg1(-1, _("Job : %s\n"), job->Job);
701 void dump_sesstime(BSR_SESSTIME *sesstime)
704 Pmsg1(-1, _("SessTime : %u\n"), sesstime->sesstime);
705 dump_sesstime(sesstime->next);
713 void dump_bsr(BSR *bsr, bool recurse)
715 int save_debug = debug_level;
718 Pmsg0(-1, _("BSR is NULL\n"));
719 debug_level = save_debug;
722 Pmsg1(-1, _("Next : 0x%x\n"), bsr->next);
723 Pmsg1(-1, _("Root bsr : 0x%x\n"), bsr->root);
724 dump_volume(bsr->volume);
725 dump_sessid(bsr->sessid);
726 dump_sesstime(bsr->sesstime);
727 dump_volfile(bsr->volfile);
728 dump_volblock(bsr->volblock);
729 dump_client(bsr->client);
730 dump_jobid(bsr->JobId);
732 dump_findex(bsr->FileIndex);
734 Pmsg1(-1, _("Slot : %u\n"), bsr->Slot);
737 Pmsg1(-1, _("count : %u\n"), bsr->count);
738 Pmsg1(-1, _("found : %u\n"), bsr->found);
741 Pmsg1(-1, _("done : %s\n"), bsr->done?_("yes"):_("no"));
742 Pmsg1(-1, _("positioning : %d\n"), bsr->use_positioning);
743 Pmsg1(-1, _("fast_reject : %d\n"), bsr->use_fast_rejection);
744 if (recurse && bsr->next) {
746 dump_bsr(bsr->next, true);
748 debug_level = save_debug;
753 /*********************************************************************
758 static void free_bsr_item(BSR *bsr)
761 free_bsr_item(bsr->next);
766 void free_bsr(BSR *bsr)
771 free_bsr_item((BSR *)bsr->volume);
772 free_bsr_item((BSR *)bsr->client);
773 free_bsr_item((BSR *)bsr->sessid);
774 free_bsr_item((BSR *)bsr->sesstime);
775 free_bsr_item((BSR *)bsr->volfile);
776 free_bsr_item((BSR *)bsr->volblock);
777 free_bsr_item((BSR *)bsr->JobId);
778 free_bsr_item((BSR *)bsr->job);
779 free_bsr_item((BSR *)bsr->FileIndex);
780 free_bsr_item((BSR *)bsr->JobType);
781 free_bsr_item((BSR *)bsr->JobLevel);
786 /*****************************************************************
787 * Routines for handling volumes
789 VOL_LIST *new_restore_volume()
792 vol = (VOL_LIST *)malloc(sizeof(VOL_LIST));
793 memset(vol, 0, sizeof(VOL_LIST));
798 * Add current volume to end of list, only if the Volume
799 * is not already in the list.
801 * returns: 1 if volume added
802 * 0 if volume already in list
804 int add_restore_volume(JCR *jcr, VOL_LIST *vol)
806 VOL_LIST *next = jcr->VolList;
808 if (!next) { /* list empty ? */
809 jcr->VolList = vol; /* yes, add volume */
811 for ( ; next->next; next=next->next) {
812 if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
813 if (vol->start_file < next->start_file) {
814 next->start_file = vol->start_file;
816 return 0; /* already in list */
819 if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
820 if (vol->start_file < next->start_file) {
821 next->start_file = vol->start_file;
823 return 0; /* already in list */
825 next->next = vol; /* add volume */
830 void free_restore_volume_list(JCR *jcr)
832 VOL_LIST *next = jcr->VolList;
844 * Create a list of Volumes (and Slots and Start positions) to be
845 * used in the current restore job.
847 void create_restore_volume_list(JCR *jcr)
853 * Build a list of volumes to be processed
859 if (!bsr->volume || !bsr->volume->VolumeName) {
862 for ( ; bsr; bsr=bsr->next) {
864 BSR_VOLFILE *volfile;
865 uint32_t sfile = UINT32_MAX;
867 /* Find minimum start file so that we can forward space to it */
868 for (volfile = bsr->volfile; volfile; volfile=volfile->next) {
869 if (volfile->sfile < sfile) {
870 sfile = volfile->sfile;
873 /* Now add volumes for this bsr */
874 for (bsrvol = bsr->volume; bsrvol; bsrvol=bsrvol->next) {
875 vol = new_restore_volume();
876 bstrncpy(vol->VolumeName, bsrvol->VolumeName, sizeof(vol->VolumeName));
877 bstrncpy(vol->MediaType, bsrvol->MediaType, sizeof(vol->MediaType));
878 vol->start_file = sfile;
879 if (add_restore_volume(jcr, vol)) {
881 Dmsg2(400, "Added volume=%s mediatype=%s\n", vol->VolumeName,
884 Dmsg1(400, "Duplicate volume %s\n", vol->VolumeName);
887 sfile = 0; /* start at beginning of second volume */
891 /* This is the old way -- deprecated */
892 for (p = jcr->dcr->VolumeName; p && *p; ) {
893 n = strchr(p, '|'); /* volume name separator */
895 *n++ = 0; /* Terminate name */
897 vol = new_restore_volume();
898 bstrncpy(vol->VolumeName, p, sizeof(vol->VolumeName));
899 bstrncpy(vol->MediaType, jcr->dcr->media_type, sizeof(vol->MediaType));
900 if (add_restore_volume(jcr, vol)) {