2 * Parse a Bootstrap Records (used for restores)
4 * Kern Sibbald, June MMII
10 Copyright (C) 2002-2006 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_device(LEX *lc, BSR *bsr);
33 static BSR *store_client(LEX *lc, BSR *bsr);
34 static BSR *store_job(LEX *lc, BSR *bsr);
35 static BSR *store_jobid(LEX *lc, BSR *bsr);
36 static BSR *store_count(LEX *lc, BSR *bsr);
37 static BSR *store_jobtype(LEX *lc, BSR *bsr);
38 static BSR *store_joblevel(LEX *lc, BSR *bsr);
39 static BSR *store_findex(LEX *lc, BSR *bsr);
40 static BSR *store_sessid(LEX *lc, BSR *bsr);
41 static BSR *store_volfile(LEX *lc, BSR *bsr);
42 static BSR *store_volblock(LEX *lc, BSR *bsr);
43 static BSR *store_sesstime(LEX *lc, BSR *bsr);
44 static BSR *store_include(LEX *lc, BSR *bsr);
45 static BSR *store_exclude(LEX *lc, BSR *bsr);
46 static BSR *store_stream(LEX *lc, BSR *bsr);
47 static BSR *store_slot(LEX *lc, BSR *bsr);
48 static bool is_fast_rejection_ok(BSR *bsr);
49 static bool is_positioning_ok(BSR *bsr);
53 ITEM_HANDLER *handler;
57 * List of all keywords permitted in bsr files and their handlers
59 struct kw_items items[] = {
60 {"volume", store_vol},
61 {"mediatype", store_mediatype},
62 {"client", store_client},
64 {"jobid", store_jobid},
65 {"count", store_count},
66 {"fileindex", store_findex},
67 {"jobtype", store_jobtype},
68 {"joblevel", store_joblevel},
69 {"volsessionid", store_sessid},
70 {"volsessiontime", store_sesstime},
71 {"include", store_include},
72 {"exclude", store_exclude},
73 {"volfile", store_volfile},
74 {"volblock", store_volblock},
75 {"stream", store_stream},
77 {"device", store_device},
87 BSR *bsr = (BSR *)malloc(sizeof(BSR));
88 memset(bsr, 0, sizeof(BSR));
93 * Format a scanner error message
95 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
97 JCR *jcr = (JCR *)(lc->caller_ctx);
101 va_start(arg_ptr, msg);
102 bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
106 Jmsg(jcr, M_FATAL, 0, _("Bootstrap file error: %s\n"
107 " : Line %d, col %d of file %s\n%s\n"),
108 buf, lc->line_no, lc->col_no, lc->fname, lc->line);
110 e_msg(file, line, M_FATAL, 0, _("Bootstrap file error: %s\n"
111 " : Line %d, col %d of file %s\n%s\n"),
112 buf, lc->line_no, lc->col_no, lc->fname, lc->line);
117 /*********************************************************************
119 * Parse Bootstrap file
122 BSR *parse_bsr(JCR *jcr, char *fname)
126 BSR *root_bsr = new_bsr();
129 Dmsg1(200, "Enter parse_bsf %s\n", fname);
130 if ((lc = lex_open_file(lc, fname, s_err)) == NULL) {
132 Emsg2(M_ERROR_TERM, 0, _("Cannot open bootstrap file %s: %s\n"),
133 fname, be.strerror());
135 lc->caller_ctx = (void *)jcr;
136 while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
137 Dmsg1(200, "parse got token=%s\n", lex_tok_to_str(token));
138 if (token == T_EOL) {
141 for (i=0; items[i].name; i++) {
142 if (strcasecmp(items[i].name, lc->str) == 0) {
143 token = lex_get_token(lc, T_ALL);
144 Dmsg1 (200, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
145 if (token != T_EQUALS) {
146 scan_err1(lc, "expected an equals, got: %s", lc->str);
150 Dmsg1(200, "calling handler for %s\n", items[i].name);
151 /* Call item handler */
152 bsr = items[i].handler(lc, bsr);
158 Dmsg1(200, "Keyword = %s\n", lc->str);
159 scan_err1(lc, "Keyword %s not found", lc->str);
167 lc = lex_close_file(lc);
168 Dmsg0(200, "Leave parse_bsf()\n");
174 root_bsr->use_fast_rejection = is_fast_rejection_ok(root_bsr);
175 root_bsr->use_positioning = is_positioning_ok(root_bsr);
177 for (bsr=root_bsr; bsr; bsr=bsr->next) {
178 bsr->root = root_bsr;
183 static bool is_fast_rejection_ok(BSR *bsr)
186 * Although, this can be optimized, for the moment, require
187 * all bsrs to have both sesstime and sessid set before
188 * we do fast rejection.
190 for ( ; bsr; bsr=bsr->next) {
191 if (!(bsr->sesstime && bsr->sessid)) {
198 static bool is_positioning_ok(BSR *bsr)
201 * Every bsr should have a volfile entry and a volblock entry
202 * if we are going to use positioning
204 for ( ; bsr; bsr=bsr->next) {
205 if (!bsr->volfile || !bsr->volblock) {
213 static BSR *store_vol(LEX *lc, BSR *bsr)
219 token = lex_get_token(lc, T_STRING);
220 if (token == T_ERROR) {
224 bsr->next = new_bsr();
227 /* This may actually be more than one volume separated by a |
228 * If so, separate them.
230 for (p=lc->str; p && *p; ) {
235 volume = (BSR_VOLUME *)malloc(sizeof(BSR_VOLUME));
236 memset(volume, 0, sizeof(BSR_VOLUME));
237 bstrncpy(volume->VolumeName, p, sizeof(volume->VolumeName));
238 /* Add it to the end of the volume chain */
240 bsr->volume = volume;
242 BSR_VOLUME *bc = bsr->volume;
243 for ( ;bc->next; bc=bc->next)
252 /* Shove the MediaType in each Volume in the current bsr */
253 static BSR *store_mediatype(LEX *lc, BSR *bsr)
257 token = lex_get_token(lc, T_STRING);
258 if (token == T_ERROR) {
262 Emsg1(M_ERROR,0, _("MediaType %s in bsr at inappropriate place.\n"),
267 for (bv=bsr->volume; bv; bv=bv->next) {
268 bstrncpy(bv->MediaType, lc->str, sizeof(bv->MediaType));
273 /* Shove the Device name in each Volume in the current bsr */
274 static BSR *store_device(LEX *lc, BSR *bsr)
278 token = lex_get_token(lc, T_STRING);
279 if (token == T_ERROR) {
283 Emsg1(M_ERROR,0, _("Device \"%s\" in bsr at inappropriate place.\n"),
288 for (bv=bsr->volume; bv; bv=bv->next) {
289 bstrncpy(bv->device, lc->str, sizeof(bv->device));
296 static BSR *store_client(LEX *lc, BSR *bsr)
302 token = lex_get_token(lc, T_NAME);
303 if (token == T_ERROR) {
306 client = (BSR_CLIENT *)malloc(sizeof(BSR_CLIENT));
307 memset(client, 0, sizeof(BSR_CLIENT));
308 bstrncpy(client->ClientName, lc->str, sizeof(client->ClientName));
309 /* Add it to the end of the client chain */
311 bsr->client = client;
313 BSR_CLIENT *bc = bsr->client;
314 for ( ;bc->next; bc=bc->next)
318 token = lex_get_token(lc, T_ALL);
319 if (token != T_COMMA) {
326 static BSR *store_job(LEX *lc, BSR *bsr)
332 token = lex_get_token(lc, T_NAME);
333 if (token == T_ERROR) {
336 job = (BSR_JOB *)malloc(sizeof(BSR_JOB));
337 memset(job, 0, sizeof(BSR_JOB));
338 bstrncpy(job->Job, lc->str, sizeof(job->Job));
339 /* Add it to the end of the client chain */
343 /* Add to end of chain */
344 BSR_JOB *bc = bsr->job;
345 for ( ;bc->next; bc=bc->next)
349 token = lex_get_token(lc, T_ALL);
350 if (token != T_COMMA) {
357 static BSR *store_findex(LEX *lc, BSR *bsr)
363 token = lex_get_token(lc, T_PINT32_RANGE);
364 if (token == T_ERROR) {
367 findex = (BSR_FINDEX *)malloc(sizeof(BSR_FINDEX));
368 memset(findex, 0, sizeof(BSR_FINDEX));
369 findex->findex = lc->pint32_val;
370 findex->findex2 = lc->pint32_val2;
371 /* Add it to the end of the chain */
372 if (!bsr->FileIndex) {
373 bsr->FileIndex = findex;
375 /* Add to end of chain */
376 BSR_FINDEX *bs = bsr->FileIndex;
377 for ( ;bs->next; bs=bs->next)
381 token = lex_get_token(lc, T_ALL);
382 if (token != T_COMMA) {
390 static BSR *store_jobid(LEX *lc, BSR *bsr)
396 token = lex_get_token(lc, T_PINT32_RANGE);
397 if (token == T_ERROR) {
400 jobid = (BSR_JOBID *)malloc(sizeof(BSR_JOBID));
401 memset(jobid, 0, sizeof(BSR_JOBID));
402 jobid->JobId = lc->pint32_val;
403 jobid->JobId2 = lc->pint32_val2;
404 /* Add it to the end of the chain */
408 /* Add to end of chain */
409 BSR_JOBID *bs = bsr->JobId;
410 for ( ;bs->next; bs=bs->next)
414 token = lex_get_token(lc, T_ALL);
415 if (token != T_COMMA) {
423 static BSR *store_count(LEX *lc, BSR *bsr)
427 token = lex_get_token(lc, T_PINT32);
428 if (token == T_ERROR) {
431 bsr->count = lc->pint32_val;
437 static BSR *store_jobtype(LEX *lc, BSR *bsr)
439 /* *****FIXME****** */
440 Pmsg0(-1, _("JobType not yet implemented\n"));
445 static BSR *store_joblevel(LEX *lc, BSR *bsr)
447 /* *****FIXME****** */
448 Pmsg0(-1, _("JobLevel not yet implemented\n"));
456 * Routine to handle Volume start/end file
458 static BSR *store_volfile(LEX *lc, BSR *bsr)
461 BSR_VOLFILE *volfile;
464 token = lex_get_token(lc, T_PINT32_RANGE);
465 if (token == T_ERROR) {
468 volfile = (BSR_VOLFILE *)malloc(sizeof(BSR_VOLFILE));
469 memset(volfile, 0, sizeof(BSR_VOLFILE));
470 volfile->sfile = lc->pint32_val;
471 volfile->efile = lc->pint32_val2;
472 /* Add it to the end of the chain */
474 bsr->volfile = volfile;
476 /* Add to end of chain */
477 BSR_VOLFILE *bs = bsr->volfile;
478 for ( ;bs->next; bs=bs->next)
482 token = lex_get_token(lc, T_ALL);
483 if (token != T_COMMA) {
492 * Routine to handle Volume start/end Block
494 static BSR *store_volblock(LEX *lc, BSR *bsr)
497 BSR_VOLBLOCK *volblock;
500 token = lex_get_token(lc, T_PINT32_RANGE);
501 if (token == T_ERROR) {
504 volblock = (BSR_VOLBLOCK *)malloc(sizeof(BSR_VOLBLOCK));
505 memset(volblock, 0, sizeof(BSR_VOLBLOCK));
506 volblock->sblock = lc->pint32_val;
507 volblock->eblock = lc->pint32_val2;
508 /* Add it to the end of the chain */
509 if (!bsr->volblock) {
510 bsr->volblock = volblock;
512 /* Add to end of chain */
513 BSR_VOLBLOCK *bs = bsr->volblock;
514 for ( ;bs->next; bs=bs->next)
518 token = lex_get_token(lc, T_ALL);
519 if (token != T_COMMA) {
527 static BSR *store_sessid(LEX *lc, BSR *bsr)
533 token = lex_get_token(lc, T_PINT32_RANGE);
534 if (token == T_ERROR) {
537 sid = (BSR_SESSID *)malloc(sizeof(BSR_SESSID));
538 memset(sid, 0, sizeof(BSR_SESSID));
539 sid->sessid = lc->pint32_val;
540 sid->sessid2 = lc->pint32_val2;
541 /* Add it to the end of the chain */
545 /* Add to end of chain */
546 BSR_SESSID *bs = bsr->sessid;
547 for ( ;bs->next; bs=bs->next)
551 token = lex_get_token(lc, T_ALL);
552 if (token != T_COMMA) {
559 static BSR *store_sesstime(LEX *lc, BSR *bsr)
565 token = lex_get_token(lc, T_PINT32);
566 if (token == T_ERROR) {
569 stime = (BSR_SESSTIME *)malloc(sizeof(BSR_SESSTIME));
570 memset(stime, 0, sizeof(BSR_SESSTIME));
571 stime->sesstime = lc->pint32_val;
572 /* Add it to the end of the chain */
573 if (!bsr->sesstime) {
574 bsr->sesstime = stime;
576 /* Add to end of chain */
577 BSR_SESSTIME *bs = bsr->sesstime;
578 for ( ;bs->next; bs=bs->next)
582 token = lex_get_token(lc, T_ALL);
583 if (token != T_COMMA) {
591 static BSR *store_stream(LEX *lc, BSR *bsr)
597 token = lex_get_token(lc, T_INT32);
598 if (token == T_ERROR) {
601 stream = (BSR_STREAM *)malloc(sizeof(BSR_STREAM));
602 memset(stream, 0, sizeof(BSR_STREAM));
603 stream->stream = lc->int32_val;
604 /* Add it to the end of the chain */
606 bsr->stream = stream;
608 /* Add to end of chain */
609 BSR_STREAM *bs = bsr->stream;
610 for ( ;bs->next; bs=bs->next)
614 token = lex_get_token(lc, T_ALL);
615 if (token != T_COMMA) {
622 static BSR *store_slot(LEX *lc, BSR *bsr)
626 token = lex_get_token(lc, T_PINT32);
627 if (token == T_ERROR) {
631 Emsg1(M_ERROR,0, _("Slot %d in bsr at inappropriate place.\n"),
635 bsr->volume->Slot = lc->pint32_val;
640 static BSR *store_include(LEX *lc, BSR *bsr)
646 static BSR *store_exclude(LEX *lc, BSR *bsr)
652 void dump_volfile(BSR_VOLFILE *volfile)
655 Pmsg2(-1, _("VolFile : %u-%u\n"), volfile->sfile, volfile->efile);
656 dump_volfile(volfile->next);
660 void dump_volblock(BSR_VOLBLOCK *volblock)
663 Pmsg2(-1, _("VolBlock : %u-%u\n"), volblock->sblock, volblock->eblock);
664 dump_volblock(volblock->next);
669 void dump_findex(BSR_FINDEX *FileIndex)
672 if (FileIndex->findex == FileIndex->findex2) {
673 Pmsg1(-1, _("FileIndex : %u\n"), FileIndex->findex);
675 Pmsg2(-1, _("FileIndex : %u-%u\n"), FileIndex->findex, FileIndex->findex2);
677 dump_findex(FileIndex->next);
681 void dump_jobid(BSR_JOBID *jobid)
684 if (jobid->JobId == jobid->JobId2) {
685 Pmsg1(-1, _("JobId : %u\n"), jobid->JobId);
687 Pmsg2(-1, _("JobId : %u-%u\n"), jobid->JobId, jobid->JobId2);
689 dump_jobid(jobid->next);
693 void dump_sessid(BSR_SESSID *sessid)
696 if (sessid->sessid == sessid->sessid2) {
697 Pmsg1(-1, _("SessId : %u\n"), sessid->sessid);
699 Pmsg2(-1, _("SessId : %u-%u\n"), sessid->sessid, sessid->sessid2);
701 dump_sessid(sessid->next);
705 void dump_volume(BSR_VOLUME *volume)
708 Pmsg1(-1, _("VolumeName : %s\n"), volume->VolumeName);
709 Pmsg1(-1, _(" MediaType : %s\n"), volume->MediaType);
710 Pmsg1(-1, _(" Device : %s\n"), volume->device);
711 Pmsg1(-1, _(" Slot : %d\n"), volume->Slot);
712 dump_volume(volume->next);
717 void dump_client(BSR_CLIENT *client)
720 Pmsg1(-1, _("Client : %s\n"), client->ClientName);
721 dump_client(client->next);
725 void dump_job(BSR_JOB *job)
728 Pmsg1(-1, _("Job : %s\n"), job->Job);
733 void dump_sesstime(BSR_SESSTIME *sesstime)
736 Pmsg1(-1, _("SessTime : %u\n"), sesstime->sesstime);
737 dump_sesstime(sesstime->next);
745 void dump_bsr(BSR *bsr, bool recurse)
747 int save_debug = debug_level;
750 Pmsg0(-1, _("BSR is NULL\n"));
751 debug_level = save_debug;
754 Pmsg1(-1, _("Next : 0x%x\n"), bsr->next);
755 Pmsg1(-1, _("Root bsr : 0x%x\n"), bsr->root);
756 dump_volume(bsr->volume);
757 dump_sessid(bsr->sessid);
758 dump_sesstime(bsr->sesstime);
759 dump_volfile(bsr->volfile);
760 dump_volblock(bsr->volblock);
761 dump_client(bsr->client);
762 dump_jobid(bsr->JobId);
764 dump_findex(bsr->FileIndex);
766 Pmsg1(-1, _("count : %u\n"), bsr->count);
767 Pmsg1(-1, _("found : %u\n"), bsr->found);
770 Pmsg1(-1, _("done : %s\n"), bsr->done?_("yes"):_("no"));
771 Pmsg1(-1, _("positioning : %d\n"), bsr->use_positioning);
772 Pmsg1(-1, _("fast_reject : %d\n"), bsr->use_fast_rejection);
773 if (recurse && bsr->next) {
775 dump_bsr(bsr->next, true);
777 debug_level = save_debug;
782 /*********************************************************************
787 static void free_bsr_item(BSR *bsr)
790 free_bsr_item(bsr->next);
795 void free_bsr(BSR *bsr)
800 free_bsr_item((BSR *)bsr->volume);
801 free_bsr_item((BSR *)bsr->client);
802 free_bsr_item((BSR *)bsr->sessid);
803 free_bsr_item((BSR *)bsr->sesstime);
804 free_bsr_item((BSR *)bsr->volfile);
805 free_bsr_item((BSR *)bsr->volblock);
806 free_bsr_item((BSR *)bsr->JobId);
807 free_bsr_item((BSR *)bsr->job);
808 free_bsr_item((BSR *)bsr->FileIndex);
809 free_bsr_item((BSR *)bsr->JobType);
810 free_bsr_item((BSR *)bsr->JobLevel);
815 /*****************************************************************
816 * Routines for handling volumes
818 VOL_LIST *new_restore_volume()
821 vol = (VOL_LIST *)malloc(sizeof(VOL_LIST));
822 memset(vol, 0, sizeof(VOL_LIST));
827 * Add current volume to end of list, only if the Volume
828 * is not already in the list.
830 * returns: 1 if volume added
831 * 0 if volume already in list
833 int add_restore_volume(JCR *jcr, VOL_LIST *vol)
835 VOL_LIST *next = jcr->VolList;
837 if (!next) { /* list empty ? */
838 jcr->VolList = vol; /* yes, add volume */
840 for ( ; next->next; next=next->next) {
841 if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
842 if (vol->start_file < next->start_file) {
843 next->start_file = vol->start_file;
845 return 0; /* already in list */
848 if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
849 if (vol->start_file < next->start_file) {
850 next->start_file = vol->start_file;
852 return 0; /* already in list */
854 next->next = vol; /* add volume */
859 void free_restore_volume_list(JCR *jcr)
861 VOL_LIST *next = jcr->VolList;
873 * Create a list of Volumes (and Slots and Start positions) to be
874 * used in the current restore job.
876 void create_restore_volume_list(JCR *jcr)
882 * Build a list of volumes to be processed
888 if (!bsr->volume || !bsr->volume->VolumeName) {
891 for ( ; bsr; bsr=bsr->next) {
893 BSR_VOLFILE *volfile;
894 uint32_t sfile = UINT32_MAX;
896 /* Find minimum start file so that we can forward space to it */
897 for (volfile = bsr->volfile; volfile; volfile=volfile->next) {
898 if (volfile->sfile < sfile) {
899 sfile = volfile->sfile;
902 /* Now add volumes for this bsr */
903 for (bsrvol = bsr->volume; bsrvol; bsrvol=bsrvol->next) {
904 vol = new_restore_volume();
905 bstrncpy(vol->VolumeName, bsrvol->VolumeName, sizeof(vol->VolumeName));
906 bstrncpy(vol->MediaType, bsrvol->MediaType, sizeof(vol->MediaType));
907 bstrncpy(vol->device, bsrvol->device, sizeof(vol->device));
908 vol->Slot = bsrvol->Slot;
909 vol->start_file = sfile;
910 if (add_restore_volume(jcr, vol)) {
912 Dmsg2(400, "Added volume=%s mediatype=%s\n", vol->VolumeName,
915 Dmsg1(400, "Duplicate volume %s\n", vol->VolumeName);
918 sfile = 0; /* start at beginning of second volume */
922 /* This is the old way -- deprecated */
923 for (p = jcr->dcr->VolumeName; p && *p; ) {
924 n = strchr(p, '|'); /* volume name separator */
926 *n++ = 0; /* Terminate name */
928 vol = new_restore_volume();
929 bstrncpy(vol->VolumeName, p, sizeof(vol->VolumeName));
930 bstrncpy(vol->MediaType, jcr->dcr->media_type, sizeof(vol->MediaType));
931 if (add_restore_volume(jcr, vol)) {