2 * Parse a Bootstrap Records (used for restores)
4 * Kern Sibbald, June MMII
9 Bacula® - The Network Backup Solution
11 Copyright (C) 2002-2006 Free Software Foundation Europe e.V.
13 The main author of Bacula is Kern Sibbald, with contributions from
14 many others, a complete list can be found in the file AUTHORS.
15 This program is Free Software; you can redistribute it and/or
16 modify it under the terms of version two of the GNU General Public
17 License as published by the Free Software Foundation plus additions
18 that are listed in the file LICENSE.
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30 Bacula® is a registered trademark of John Walker.
31 The licensor of Bacula is the Free Software Foundation Europe
32 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
33 Switzerland, email:ftf@fsfeurope.org.
40 typedef BSR * (ITEM_HANDLER)(LEX *lc, BSR *bsr);
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_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 bool is_fast_rejection_ok(BSR *bsr);
61 static bool is_positioning_ok(BSR *bsr);
65 ITEM_HANDLER *handler;
69 * List of all keywords permitted in bsr files and their handlers
71 struct kw_items items[] = {
72 {"volume", store_vol},
73 {"mediatype", store_mediatype},
74 {"client", store_client},
76 {"jobid", store_jobid},
77 {"count", store_count},
78 {"fileindex", store_findex},
79 {"jobtype", store_jobtype},
80 {"joblevel", store_joblevel},
81 {"volsessionid", store_sessid},
82 {"volsessiontime", store_sesstime},
83 {"include", store_include},
84 {"exclude", store_exclude},
85 {"volfile", store_volfile},
86 {"volblock", store_volblock},
87 {"stream", store_stream},
89 {"device", store_device},
99 BSR *bsr = (BSR *)malloc(sizeof(BSR));
100 memset(bsr, 0, sizeof(BSR));
105 * Format a scanner error message
107 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
109 JCR *jcr = (JCR *)(lc->caller_ctx);
113 va_start(arg_ptr, msg);
114 bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
118 Jmsg(jcr, M_FATAL, 0, _("Bootstrap file error: %s\n"
119 " : Line %d, col %d of file %s\n%s\n"),
120 buf, lc->line_no, lc->col_no, lc->fname, lc->line);
122 e_msg(file, line, 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);
129 /*********************************************************************
131 * Parse Bootstrap file
134 BSR *parse_bsr(JCR *jcr, char *fname)
138 BSR *root_bsr = new_bsr();
141 Dmsg1(300, "Enter parse_bsf %s\n", fname);
142 if ((lc = lex_open_file(lc, fname, s_err)) == NULL) {
144 Emsg2(M_ERROR_TERM, 0, _("Cannot open bootstrap file %s: %s\n"),
145 fname, be.bstrerror());
147 lc->caller_ctx = (void *)jcr;
148 while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
149 Dmsg1(300, "parse got token=%s\n", lex_tok_to_str(token));
150 if (token == T_EOL) {
153 for (i=0; items[i].name; i++) {
154 if (strcasecmp(items[i].name, lc->str) == 0) {
155 token = lex_get_token(lc, T_ALL);
156 Dmsg1 (300, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
157 if (token != T_EQUALS) {
158 scan_err1(lc, "expected an equals, got: %s", lc->str);
162 Dmsg1(300, "calling handler for %s\n", items[i].name);
163 /* Call item handler */
164 bsr = items[i].handler(lc, bsr);
170 Dmsg1(300, "Keyword = %s\n", lc->str);
171 scan_err1(lc, "Keyword %s not found", lc->str);
179 lc = lex_close_file(lc);
180 Dmsg0(300, "Leave parse_bsf()\n");
186 root_bsr->use_fast_rejection = is_fast_rejection_ok(root_bsr);
187 root_bsr->use_positioning = is_positioning_ok(root_bsr);
189 for (bsr=root_bsr; bsr; bsr=bsr->next) {
190 bsr->root = root_bsr;
195 static bool is_fast_rejection_ok(BSR *bsr)
198 * Although, this can be optimized, for the moment, require
199 * all bsrs to have both sesstime and sessid set before
200 * we do fast rejection.
202 for ( ; bsr; bsr=bsr->next) {
203 if (!(bsr->sesstime && bsr->sessid)) {
210 static bool is_positioning_ok(BSR *bsr)
213 * Every bsr should have a volfile entry and a volblock entry
214 * if we are going to use positioning
216 for ( ; bsr; bsr=bsr->next) {
217 if (!bsr->volfile || !bsr->volblock) {
225 static BSR *store_vol(LEX *lc, BSR *bsr)
231 token = lex_get_token(lc, T_STRING);
232 if (token == T_ERROR) {
236 bsr->next = new_bsr();
239 /* This may actually be more than one volume separated by a |
240 * If so, separate them.
242 for (p=lc->str; p && *p; ) {
247 volume = (BSR_VOLUME *)malloc(sizeof(BSR_VOLUME));
248 memset(volume, 0, sizeof(BSR_VOLUME));
249 bstrncpy(volume->VolumeName, p, sizeof(volume->VolumeName));
250 /* Add it to the end of the volume chain */
252 bsr->volume = volume;
254 BSR_VOLUME *bc = bsr->volume;
255 for ( ;bc->next; bc=bc->next)
264 /* Shove the MediaType in each Volume in the current bsr */
265 static BSR *store_mediatype(LEX *lc, BSR *bsr)
269 token = lex_get_token(lc, T_STRING);
270 if (token == T_ERROR) {
274 Emsg1(M_ERROR,0, _("MediaType %s in bsr at inappropriate place.\n"),
279 for (bv=bsr->volume; bv; bv=bv->next) {
280 bstrncpy(bv->MediaType, lc->str, sizeof(bv->MediaType));
285 /* Shove the Device name in each Volume in the current bsr */
286 static BSR *store_device(LEX *lc, BSR *bsr)
290 token = lex_get_token(lc, T_STRING);
291 if (token == T_ERROR) {
295 Emsg1(M_ERROR,0, _("Device \"%s\" in bsr at inappropriate place.\n"),
300 for (bv=bsr->volume; bv; bv=bv->next) {
301 bstrncpy(bv->device, lc->str, sizeof(bv->device));
308 static BSR *store_client(LEX *lc, BSR *bsr)
314 token = lex_get_token(lc, T_NAME);
315 if (token == T_ERROR) {
318 client = (BSR_CLIENT *)malloc(sizeof(BSR_CLIENT));
319 memset(client, 0, sizeof(BSR_CLIENT));
320 bstrncpy(client->ClientName, lc->str, sizeof(client->ClientName));
321 /* Add it to the end of the client chain */
323 bsr->client = client;
325 BSR_CLIENT *bc = bsr->client;
326 for ( ;bc->next; bc=bc->next)
330 token = lex_get_token(lc, T_ALL);
331 if (token != T_COMMA) {
338 static BSR *store_job(LEX *lc, BSR *bsr)
344 token = lex_get_token(lc, T_NAME);
345 if (token == T_ERROR) {
348 job = (BSR_JOB *)malloc(sizeof(BSR_JOB));
349 memset(job, 0, sizeof(BSR_JOB));
350 bstrncpy(job->Job, lc->str, sizeof(job->Job));
351 /* Add it to the end of the client chain */
355 /* Add to end of chain */
356 BSR_JOB *bc = bsr->job;
357 for ( ;bc->next; bc=bc->next)
361 token = lex_get_token(lc, T_ALL);
362 if (token != T_COMMA) {
369 static BSR *store_findex(LEX *lc, BSR *bsr)
375 token = lex_get_token(lc, T_PINT32_RANGE);
376 if (token == T_ERROR) {
379 findex = (BSR_FINDEX *)malloc(sizeof(BSR_FINDEX));
380 memset(findex, 0, sizeof(BSR_FINDEX));
381 findex->findex = lc->pint32_val;
382 findex->findex2 = lc->pint32_val2;
383 /* Add it to the end of the chain */
384 if (!bsr->FileIndex) {
385 bsr->FileIndex = findex;
387 /* Add to end of chain */
388 BSR_FINDEX *bs = bsr->FileIndex;
389 for ( ;bs->next; bs=bs->next)
393 token = lex_get_token(lc, T_ALL);
394 if (token != T_COMMA) {
402 static BSR *store_jobid(LEX *lc, BSR *bsr)
408 token = lex_get_token(lc, T_PINT32_RANGE);
409 if (token == T_ERROR) {
412 jobid = (BSR_JOBID *)malloc(sizeof(BSR_JOBID));
413 memset(jobid, 0, sizeof(BSR_JOBID));
414 jobid->JobId = lc->pint32_val;
415 jobid->JobId2 = lc->pint32_val2;
416 /* Add it to the end of the chain */
420 /* Add to end of chain */
421 BSR_JOBID *bs = bsr->JobId;
422 for ( ;bs->next; bs=bs->next)
426 token = lex_get_token(lc, T_ALL);
427 if (token != T_COMMA) {
435 static BSR *store_count(LEX *lc, BSR *bsr)
439 token = lex_get_token(lc, T_PINT32);
440 if (token == T_ERROR) {
443 bsr->count = lc->pint32_val;
449 static BSR *store_jobtype(LEX *lc, BSR *bsr)
451 /* *****FIXME****** */
452 Pmsg0(-1, _("JobType not yet implemented\n"));
457 static BSR *store_joblevel(LEX *lc, BSR *bsr)
459 /* *****FIXME****** */
460 Pmsg0(-1, _("JobLevel not yet implemented\n"));
468 * Routine to handle Volume start/end file
470 static BSR *store_volfile(LEX *lc, BSR *bsr)
473 BSR_VOLFILE *volfile;
476 token = lex_get_token(lc, T_PINT32_RANGE);
477 if (token == T_ERROR) {
480 volfile = (BSR_VOLFILE *)malloc(sizeof(BSR_VOLFILE));
481 memset(volfile, 0, sizeof(BSR_VOLFILE));
482 volfile->sfile = lc->pint32_val;
483 volfile->efile = lc->pint32_val2;
484 /* Add it to the end of the chain */
486 bsr->volfile = volfile;
488 /* Add to end of chain */
489 BSR_VOLFILE *bs = bsr->volfile;
490 for ( ;bs->next; bs=bs->next)
494 token = lex_get_token(lc, T_ALL);
495 if (token != T_COMMA) {
504 * Routine to handle Volume start/end Block
506 static BSR *store_volblock(LEX *lc, BSR *bsr)
509 BSR_VOLBLOCK *volblock;
512 token = lex_get_token(lc, T_PINT32_RANGE);
513 if (token == T_ERROR) {
516 volblock = (BSR_VOLBLOCK *)malloc(sizeof(BSR_VOLBLOCK));
517 memset(volblock, 0, sizeof(BSR_VOLBLOCK));
518 volblock->sblock = lc->pint32_val;
519 volblock->eblock = lc->pint32_val2;
520 /* Add it to the end of the chain */
521 if (!bsr->volblock) {
522 bsr->volblock = volblock;
524 /* Add to end of chain */
525 BSR_VOLBLOCK *bs = bsr->volblock;
526 for ( ;bs->next; bs=bs->next)
530 token = lex_get_token(lc, T_ALL);
531 if (token != T_COMMA) {
539 static BSR *store_sessid(LEX *lc, BSR *bsr)
545 token = lex_get_token(lc, T_PINT32_RANGE);
546 if (token == T_ERROR) {
549 sid = (BSR_SESSID *)malloc(sizeof(BSR_SESSID));
550 memset(sid, 0, sizeof(BSR_SESSID));
551 sid->sessid = lc->pint32_val;
552 sid->sessid2 = lc->pint32_val2;
553 /* Add it to the end of the chain */
557 /* Add to end of chain */
558 BSR_SESSID *bs = bsr->sessid;
559 for ( ;bs->next; bs=bs->next)
563 token = lex_get_token(lc, T_ALL);
564 if (token != T_COMMA) {
571 static BSR *store_sesstime(LEX *lc, BSR *bsr)
577 token = lex_get_token(lc, T_PINT32);
578 if (token == T_ERROR) {
581 stime = (BSR_SESSTIME *)malloc(sizeof(BSR_SESSTIME));
582 memset(stime, 0, sizeof(BSR_SESSTIME));
583 stime->sesstime = lc->pint32_val;
584 /* Add it to the end of the chain */
585 if (!bsr->sesstime) {
586 bsr->sesstime = stime;
588 /* Add to end of chain */
589 BSR_SESSTIME *bs = bsr->sesstime;
590 for ( ;bs->next; bs=bs->next)
594 token = lex_get_token(lc, T_ALL);
595 if (token != T_COMMA) {
603 static BSR *store_stream(LEX *lc, BSR *bsr)
609 token = lex_get_token(lc, T_INT32);
610 if (token == T_ERROR) {
613 stream = (BSR_STREAM *)malloc(sizeof(BSR_STREAM));
614 memset(stream, 0, sizeof(BSR_STREAM));
615 stream->stream = lc->int32_val;
616 /* Add it to the end of the chain */
618 bsr->stream = stream;
620 /* Add to end of chain */
621 BSR_STREAM *bs = bsr->stream;
622 for ( ;bs->next; bs=bs->next)
626 token = lex_get_token(lc, T_ALL);
627 if (token != T_COMMA) {
634 static BSR *store_slot(LEX *lc, BSR *bsr)
638 token = lex_get_token(lc, T_PINT32);
639 if (token == T_ERROR) {
643 Emsg1(M_ERROR,0, _("Slot %d in bsr at inappropriate place.\n"),
647 bsr->volume->Slot = lc->pint32_val;
652 static BSR *store_include(LEX *lc, BSR *bsr)
658 static BSR *store_exclude(LEX *lc, BSR *bsr)
664 void dump_volfile(BSR_VOLFILE *volfile)
667 Pmsg2(-1, _("VolFile : %u-%u\n"), volfile->sfile, volfile->efile);
668 dump_volfile(volfile->next);
672 void dump_volblock(BSR_VOLBLOCK *volblock)
675 Pmsg2(-1, _("VolBlock : %u-%u\n"), volblock->sblock, volblock->eblock);
676 dump_volblock(volblock->next);
681 void dump_findex(BSR_FINDEX *FileIndex)
684 if (FileIndex->findex == FileIndex->findex2) {
685 Pmsg1(-1, _("FileIndex : %u\n"), FileIndex->findex);
687 Pmsg2(-1, _("FileIndex : %u-%u\n"), FileIndex->findex, FileIndex->findex2);
689 dump_findex(FileIndex->next);
693 void dump_jobid(BSR_JOBID *jobid)
696 if (jobid->JobId == jobid->JobId2) {
697 Pmsg1(-1, _("JobId : %u\n"), jobid->JobId);
699 Pmsg2(-1, _("JobId : %u-%u\n"), jobid->JobId, jobid->JobId2);
701 dump_jobid(jobid->next);
705 void dump_sessid(BSR_SESSID *sessid)
708 if (sessid->sessid == sessid->sessid2) {
709 Pmsg1(-1, _("SessId : %u\n"), sessid->sessid);
711 Pmsg2(-1, _("SessId : %u-%u\n"), sessid->sessid, sessid->sessid2);
713 dump_sessid(sessid->next);
717 void dump_volume(BSR_VOLUME *volume)
720 Pmsg1(-1, _("VolumeName : %s\n"), volume->VolumeName);
721 Pmsg1(-1, _(" MediaType : %s\n"), volume->MediaType);
722 Pmsg1(-1, _(" Device : %s\n"), volume->device);
723 Pmsg1(-1, _(" Slot : %d\n"), volume->Slot);
724 dump_volume(volume->next);
729 void dump_client(BSR_CLIENT *client)
732 Pmsg1(-1, _("Client : %s\n"), client->ClientName);
733 dump_client(client->next);
737 void dump_job(BSR_JOB *job)
740 Pmsg1(-1, _("Job : %s\n"), job->Job);
745 void dump_sesstime(BSR_SESSTIME *sesstime)
748 Pmsg1(-1, _("SessTime : %u\n"), sesstime->sesstime);
749 dump_sesstime(sesstime->next);
754 void dump_bsr(BSR *bsr, bool recurse)
756 int save_debug = debug_level;
759 Pmsg0(-1, _("BSR is NULL\n"));
760 debug_level = save_debug;
763 Pmsg1(-1, _("Next : 0x%x\n"), bsr->next);
764 Pmsg1(-1, _("Root bsr : 0x%x\n"), bsr->root);
765 dump_volume(bsr->volume);
766 dump_sessid(bsr->sessid);
767 dump_sesstime(bsr->sesstime);
768 dump_volfile(bsr->volfile);
769 dump_volblock(bsr->volblock);
770 dump_client(bsr->client);
771 dump_jobid(bsr->JobId);
773 dump_findex(bsr->FileIndex);
775 Pmsg1(-1, _("count : %u\n"), bsr->count);
776 Pmsg1(-1, _("found : %u\n"), bsr->found);
779 Pmsg1(-1, _("done : %s\n"), bsr->done?_("yes"):_("no"));
780 Pmsg1(-1, _("positioning : %d\n"), bsr->use_positioning);
781 Pmsg1(-1, _("fast_reject : %d\n"), bsr->use_fast_rejection);
782 if (recurse && bsr->next) {
784 dump_bsr(bsr->next, true);
786 debug_level = save_debug;
791 /*********************************************************************
796 static void free_bsr_item(BSR *bsr)
799 free_bsr_item(bsr->next);
804 void free_bsr(BSR *bsr)
809 free_bsr_item((BSR *)bsr->volume);
810 free_bsr_item((BSR *)bsr->client);
811 free_bsr_item((BSR *)bsr->sessid);
812 free_bsr_item((BSR *)bsr->sesstime);
813 free_bsr_item((BSR *)bsr->volfile);
814 free_bsr_item((BSR *)bsr->volblock);
815 free_bsr_item((BSR *)bsr->JobId);
816 free_bsr_item((BSR *)bsr->job);
817 free_bsr_item((BSR *)bsr->FileIndex);
818 free_bsr_item((BSR *)bsr->JobType);
819 free_bsr_item((BSR *)bsr->JobLevel);
824 /*****************************************************************
825 * Routines for handling volumes
827 VOL_LIST *new_restore_volume()
830 vol = (VOL_LIST *)malloc(sizeof(VOL_LIST));
831 memset(vol, 0, sizeof(VOL_LIST));
836 * Add current volume to end of list, only if the Volume
837 * is not already in the list.
839 * returns: 1 if volume added
840 * 0 if volume already in list
842 int add_restore_volume(JCR *jcr, VOL_LIST *vol)
844 VOL_LIST *next = jcr->VolList;
846 if (!next) { /* list empty ? */
847 jcr->VolList = vol; /* yes, add volume */
849 for ( ; next->next; next=next->next) {
850 if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
851 if (vol->start_file < next->start_file) {
852 next->start_file = vol->start_file;
854 return 0; /* already in list */
857 if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
858 if (vol->start_file < next->start_file) {
859 next->start_file = vol->start_file;
861 return 0; /* already in list */
863 next->next = vol; /* add volume */
868 void free_restore_volume_list(JCR *jcr)
870 VOL_LIST *next = jcr->VolList;
882 * Create a list of Volumes (and Slots and Start positions) to be
883 * used in the current restore job.
885 void create_restore_volume_list(JCR *jcr)
891 * Build a list of volumes to be processed
893 jcr->NumReadVolumes = 0;
894 jcr->CurReadVolume = 0;
897 if (!bsr->volume || !bsr->volume->VolumeName) {
900 for ( ; bsr; bsr=bsr->next) {
902 BSR_VOLFILE *volfile;
903 uint32_t sfile = UINT32_MAX;
905 /* Find minimum start file so that we can forward space to it */
906 for (volfile = bsr->volfile; volfile; volfile=volfile->next) {
907 if (volfile->sfile < sfile) {
908 sfile = volfile->sfile;
911 /* Now add volumes for this bsr */
912 for (bsrvol = bsr->volume; bsrvol; bsrvol=bsrvol->next) {
913 vol = new_restore_volume();
914 bstrncpy(vol->VolumeName, bsrvol->VolumeName, sizeof(vol->VolumeName));
915 bstrncpy(vol->MediaType, bsrvol->MediaType, sizeof(vol->MediaType));
916 bstrncpy(vol->device, bsrvol->device, sizeof(vol->device));
917 vol->Slot = bsrvol->Slot;
918 vol->start_file = sfile;
919 if (add_restore_volume(jcr, vol)) {
920 jcr->NumReadVolumes++;
921 Dmsg2(400, "Added volume=%s mediatype=%s\n", vol->VolumeName,
924 Dmsg1(400, "Duplicate volume %s\n", vol->VolumeName);
927 sfile = 0; /* start at beginning of second volume */
931 /* This is the old way -- deprecated */
932 for (p = jcr->dcr->VolumeName; p && *p; ) {
933 n = strchr(p, '|'); /* volume name separator */
935 *n++ = 0; /* Terminate name */
937 vol = new_restore_volume();
938 bstrncpy(vol->VolumeName, p, sizeof(vol->VolumeName));
939 bstrncpy(vol->MediaType, jcr->dcr->media_type, sizeof(vol->MediaType));
940 if (add_restore_volume(jcr, vol)) {
941 jcr->NumReadVolumes++;