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 and included
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 Kern Sibbald.
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 BSR *store_fileregex(LEX *lc, BSR *bsr);
61 static bool is_fast_rejection_ok(BSR *bsr);
62 static bool is_positioning_ok(BSR *bsr);
66 ITEM_HANDLER *handler;
70 * List of all keywords permitted in bsr files and their handlers
72 struct kw_items items[] = {
73 {"volume", store_vol},
74 {"mediatype", store_mediatype},
75 {"client", store_client},
77 {"jobid", store_jobid},
78 {"count", store_count},
79 {"fileindex", store_findex},
80 {"jobtype", store_jobtype},
81 {"joblevel", store_joblevel},
82 {"volsessionid", store_sessid},
83 {"volsessiontime", store_sesstime},
84 {"include", store_include},
85 {"exclude", store_exclude},
86 {"volfile", store_volfile},
87 {"volblock", store_volblock},
88 {"stream", store_stream},
90 {"device", store_device},
91 {"fileregex", store_fileregex},
100 BSR *bsr = (BSR *)malloc(sizeof(BSR));
101 memset(bsr, 0, sizeof(BSR));
106 * Format a scanner error message
108 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
110 JCR *jcr = (JCR *)(lc->caller_ctx);
114 va_start(arg_ptr, msg);
115 bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
119 Jmsg(jcr, M_FATAL, 0, _("Bootstrap file error: %s\n"
120 " : Line %d, col %d of file %s\n%s\n"),
121 buf, lc->line_no, lc->col_no, lc->fname, lc->line);
123 e_msg(file, line, M_FATAL, 0, _("Bootstrap file error: %s\n"
124 " : Line %d, col %d of file %s\n%s\n"),
125 buf, lc->line_no, lc->col_no, lc->fname, lc->line);
130 /*********************************************************************
132 * Parse Bootstrap file
135 BSR *parse_bsr(JCR *jcr, char *fname)
139 BSR *root_bsr = new_bsr();
142 Dmsg1(300, "Enter parse_bsf %s\n", fname);
143 if ((lc = lex_open_file(lc, fname, s_err)) == NULL) {
145 Emsg2(M_ERROR_TERM, 0, _("Cannot open bootstrap file %s: %s\n"),
146 fname, be.bstrerror());
148 lc->caller_ctx = (void *)jcr;
149 while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
150 Dmsg1(300, "parse got token=%s\n", lex_tok_to_str(token));
151 if (token == T_EOL) {
154 for (i=0; items[i].name; i++) {
155 if (strcasecmp(items[i].name, lc->str) == 0) {
156 token = lex_get_token(lc, T_ALL);
157 Dmsg1 (300, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
158 if (token != T_EQUALS) {
159 scan_err1(lc, "expected an equals, got: %s", lc->str);
163 Dmsg1(300, "calling handler for %s\n", items[i].name);
164 /* Call item handler */
165 bsr = items[i].handler(lc, bsr);
171 Dmsg1(300, "Keyword = %s\n", lc->str);
172 scan_err1(lc, "Keyword %s not found", lc->str);
180 lc = lex_close_file(lc);
181 Dmsg0(300, "Leave parse_bsf()\n");
187 root_bsr->use_fast_rejection = is_fast_rejection_ok(root_bsr);
188 root_bsr->use_positioning = is_positioning_ok(root_bsr);
190 for (bsr=root_bsr; bsr; bsr=bsr->next) {
191 bsr->root = root_bsr;
196 static bool is_fast_rejection_ok(BSR *bsr)
199 * Although, this can be optimized, for the moment, require
200 * all bsrs to have both sesstime and sessid set before
201 * we do fast rejection.
203 for ( ; bsr; bsr=bsr->next) {
204 if (!(bsr->sesstime && bsr->sessid)) {
211 static bool is_positioning_ok(BSR *bsr)
214 * Every bsr should have a volfile entry and a volblock entry
215 * if we are going to use positioning
217 for ( ; bsr; bsr=bsr->next) {
218 if (!bsr->volfile || !bsr->volblock) {
226 static BSR *store_vol(LEX *lc, BSR *bsr)
232 token = lex_get_token(lc, T_STRING);
233 if (token == T_ERROR) {
237 bsr->next = new_bsr();
240 /* This may actually be more than one volume separated by a |
241 * If so, separate them.
243 for (p=lc->str; p && *p; ) {
248 volume = (BSR_VOLUME *)malloc(sizeof(BSR_VOLUME));
249 memset(volume, 0, sizeof(BSR_VOLUME));
250 bstrncpy(volume->VolumeName, p, sizeof(volume->VolumeName));
251 /* Add it to the end of the volume chain */
253 bsr->volume = volume;
255 BSR_VOLUME *bc = bsr->volume;
256 for ( ;bc->next; bc=bc->next)
265 /* Shove the MediaType in each Volume in the current bsr */
266 static BSR *store_mediatype(LEX *lc, BSR *bsr)
270 token = lex_get_token(lc, T_STRING);
271 if (token == T_ERROR) {
275 Emsg1(M_ERROR,0, _("MediaType %s in bsr at inappropriate place.\n"),
280 for (bv=bsr->volume; bv; bv=bv->next) {
281 bstrncpy(bv->MediaType, lc->str, sizeof(bv->MediaType));
286 /* Shove the Device name in each Volume in the current bsr */
287 static BSR *store_device(LEX *lc, BSR *bsr)
291 token = lex_get_token(lc, T_STRING);
292 if (token == T_ERROR) {
296 Emsg1(M_ERROR,0, _("Device \"%s\" in bsr at inappropriate place.\n"),
301 for (bv=bsr->volume; bv; bv=bv->next) {
302 bstrncpy(bv->device, lc->str, sizeof(bv->device));
309 static BSR *store_client(LEX *lc, BSR *bsr)
315 token = lex_get_token(lc, T_NAME);
316 if (token == T_ERROR) {
319 client = (BSR_CLIENT *)malloc(sizeof(BSR_CLIENT));
320 memset(client, 0, sizeof(BSR_CLIENT));
321 bstrncpy(client->ClientName, lc->str, sizeof(client->ClientName));
322 /* Add it to the end of the client chain */
324 bsr->client = client;
326 BSR_CLIENT *bc = bsr->client;
327 for ( ;bc->next; bc=bc->next)
331 token = lex_get_token(lc, T_ALL);
332 if (token != T_COMMA) {
339 static BSR *store_job(LEX *lc, BSR *bsr)
345 token = lex_get_token(lc, T_NAME);
346 if (token == T_ERROR) {
349 job = (BSR_JOB *)malloc(sizeof(BSR_JOB));
350 memset(job, 0, sizeof(BSR_JOB));
351 bstrncpy(job->Job, lc->str, sizeof(job->Job));
352 /* Add it to the end of the client chain */
356 /* Add to end of chain */
357 BSR_JOB *bc = bsr->job;
358 for ( ;bc->next; bc=bc->next)
362 token = lex_get_token(lc, T_ALL);
363 if (token != T_COMMA) {
370 static BSR *store_findex(LEX *lc, BSR *bsr)
376 token = lex_get_token(lc, T_PINT32_RANGE);
377 if (token == T_ERROR) {
380 findex = (BSR_FINDEX *)malloc(sizeof(BSR_FINDEX));
381 memset(findex, 0, sizeof(BSR_FINDEX));
382 findex->findex = lc->pint32_val;
383 findex->findex2 = lc->pint32_val2;
384 /* Add it to the end of the chain */
385 if (!bsr->FileIndex) {
386 bsr->FileIndex = findex;
388 /* Add to end of chain */
389 BSR_FINDEX *bs = bsr->FileIndex;
390 for ( ;bs->next; bs=bs->next)
394 token = lex_get_token(lc, T_ALL);
395 if (token != T_COMMA) {
403 static BSR *store_jobid(LEX *lc, BSR *bsr)
409 token = lex_get_token(lc, T_PINT32_RANGE);
410 if (token == T_ERROR) {
413 jobid = (BSR_JOBID *)malloc(sizeof(BSR_JOBID));
414 memset(jobid, 0, sizeof(BSR_JOBID));
415 jobid->JobId = lc->pint32_val;
416 jobid->JobId2 = lc->pint32_val2;
417 /* Add it to the end of the chain */
421 /* Add to end of chain */
422 BSR_JOBID *bs = bsr->JobId;
423 for ( ;bs->next; bs=bs->next)
427 token = lex_get_token(lc, T_ALL);
428 if (token != T_COMMA) {
436 static BSR *store_count(LEX *lc, BSR *bsr)
440 token = lex_get_token(lc, T_PINT32);
441 if (token == T_ERROR) {
444 bsr->count = lc->pint32_val;
449 static BSR *store_fileregex(LEX *lc, BSR *bsr)
454 token = lex_get_token(lc, T_STRING);
455 if (token == T_ERROR) {
459 if (bsr->fileregex) free(bsr->fileregex);
460 bsr->fileregex = bstrdup(lc->str);
462 if (bsr->fileregex_re == NULL)
463 bsr->fileregex_re = (regex_t *)bmalloc(sizeof(regex_t));
465 rc = regcomp(bsr->fileregex_re, bsr->fileregex, REG_EXTENDED|REG_NOSUB);
468 regerror(rc, bsr->fileregex_re, prbuf, sizeof(prbuf));
469 Emsg2(M_ERROR, 0, _("REGEX '%s' compile error. ERR=%s\n"),
470 bsr->fileregex, prbuf);
476 static BSR *store_jobtype(LEX *lc, BSR *bsr)
478 /* *****FIXME****** */
479 Pmsg0(-1, _("JobType not yet implemented\n"));
484 static BSR *store_joblevel(LEX *lc, BSR *bsr)
486 /* *****FIXME****** */
487 Pmsg0(-1, _("JobLevel not yet implemented\n"));
495 * Routine to handle Volume start/end file
497 static BSR *store_volfile(LEX *lc, BSR *bsr)
500 BSR_VOLFILE *volfile;
503 token = lex_get_token(lc, T_PINT32_RANGE);
504 if (token == T_ERROR) {
507 volfile = (BSR_VOLFILE *)malloc(sizeof(BSR_VOLFILE));
508 memset(volfile, 0, sizeof(BSR_VOLFILE));
509 volfile->sfile = lc->pint32_val;
510 volfile->efile = lc->pint32_val2;
511 /* Add it to the end of the chain */
513 bsr->volfile = volfile;
515 /* Add to end of chain */
516 BSR_VOLFILE *bs = bsr->volfile;
517 for ( ;bs->next; bs=bs->next)
521 token = lex_get_token(lc, T_ALL);
522 if (token != T_COMMA) {
531 * Routine to handle Volume start/end Block
533 static BSR *store_volblock(LEX *lc, BSR *bsr)
536 BSR_VOLBLOCK *volblock;
539 token = lex_get_token(lc, T_PINT32_RANGE);
540 if (token == T_ERROR) {
543 volblock = (BSR_VOLBLOCK *)malloc(sizeof(BSR_VOLBLOCK));
544 memset(volblock, 0, sizeof(BSR_VOLBLOCK));
545 volblock->sblock = lc->pint32_val;
546 volblock->eblock = lc->pint32_val2;
547 /* Add it to the end of the chain */
548 if (!bsr->volblock) {
549 bsr->volblock = volblock;
551 /* Add to end of chain */
552 BSR_VOLBLOCK *bs = bsr->volblock;
553 for ( ;bs->next; bs=bs->next)
557 token = lex_get_token(lc, T_ALL);
558 if (token != T_COMMA) {
566 static BSR *store_sessid(LEX *lc, BSR *bsr)
572 token = lex_get_token(lc, T_PINT32_RANGE);
573 if (token == T_ERROR) {
576 sid = (BSR_SESSID *)malloc(sizeof(BSR_SESSID));
577 memset(sid, 0, sizeof(BSR_SESSID));
578 sid->sessid = lc->pint32_val;
579 sid->sessid2 = lc->pint32_val2;
580 /* Add it to the end of the chain */
584 /* Add to end of chain */
585 BSR_SESSID *bs = bsr->sessid;
586 for ( ;bs->next; bs=bs->next)
590 token = lex_get_token(lc, T_ALL);
591 if (token != T_COMMA) {
598 static BSR *store_sesstime(LEX *lc, BSR *bsr)
604 token = lex_get_token(lc, T_PINT32);
605 if (token == T_ERROR) {
608 stime = (BSR_SESSTIME *)malloc(sizeof(BSR_SESSTIME));
609 memset(stime, 0, sizeof(BSR_SESSTIME));
610 stime->sesstime = lc->pint32_val;
611 /* Add it to the end of the chain */
612 if (!bsr->sesstime) {
613 bsr->sesstime = stime;
615 /* Add to end of chain */
616 BSR_SESSTIME *bs = bsr->sesstime;
617 for ( ;bs->next; bs=bs->next)
621 token = lex_get_token(lc, T_ALL);
622 if (token != T_COMMA) {
630 static BSR *store_stream(LEX *lc, BSR *bsr)
636 token = lex_get_token(lc, T_INT32);
637 if (token == T_ERROR) {
640 stream = (BSR_STREAM *)malloc(sizeof(BSR_STREAM));
641 memset(stream, 0, sizeof(BSR_STREAM));
642 stream->stream = lc->int32_val;
643 /* Add it to the end of the chain */
645 bsr->stream = stream;
647 /* Add to end of chain */
648 BSR_STREAM *bs = bsr->stream;
649 for ( ;bs->next; bs=bs->next)
653 token = lex_get_token(lc, T_ALL);
654 if (token != T_COMMA) {
661 static BSR *store_slot(LEX *lc, BSR *bsr)
665 token = lex_get_token(lc, T_PINT32);
666 if (token == T_ERROR) {
670 Emsg1(M_ERROR,0, _("Slot %d in bsr at inappropriate place.\n"),
674 bsr->volume->Slot = lc->pint32_val;
679 static BSR *store_include(LEX *lc, BSR *bsr)
685 static BSR *store_exclude(LEX *lc, BSR *bsr)
691 void dump_volfile(BSR_VOLFILE *volfile)
694 Pmsg2(-1, _("VolFile : %u-%u\n"), volfile->sfile, volfile->efile);
695 dump_volfile(volfile->next);
699 void dump_volblock(BSR_VOLBLOCK *volblock)
702 Pmsg2(-1, _("VolBlock : %u-%u\n"), volblock->sblock, volblock->eblock);
703 dump_volblock(volblock->next);
708 void dump_findex(BSR_FINDEX *FileIndex)
711 if (FileIndex->findex == FileIndex->findex2) {
712 Pmsg1(-1, _("FileIndex : %u\n"), FileIndex->findex);
714 Pmsg2(-1, _("FileIndex : %u-%u\n"), FileIndex->findex, FileIndex->findex2);
716 dump_findex(FileIndex->next);
720 void dump_jobid(BSR_JOBID *jobid)
723 if (jobid->JobId == jobid->JobId2) {
724 Pmsg1(-1, _("JobId : %u\n"), jobid->JobId);
726 Pmsg2(-1, _("JobId : %u-%u\n"), jobid->JobId, jobid->JobId2);
728 dump_jobid(jobid->next);
732 void dump_sessid(BSR_SESSID *sessid)
735 if (sessid->sessid == sessid->sessid2) {
736 Pmsg1(-1, _("SessId : %u\n"), sessid->sessid);
738 Pmsg2(-1, _("SessId : %u-%u\n"), sessid->sessid, sessid->sessid2);
740 dump_sessid(sessid->next);
744 void dump_volume(BSR_VOLUME *volume)
747 Pmsg1(-1, _("VolumeName : %s\n"), volume->VolumeName);
748 Pmsg1(-1, _(" MediaType : %s\n"), volume->MediaType);
749 Pmsg1(-1, _(" Device : %s\n"), volume->device);
750 Pmsg1(-1, _(" Slot : %d\n"), volume->Slot);
751 dump_volume(volume->next);
756 void dump_client(BSR_CLIENT *client)
759 Pmsg1(-1, _("Client : %s\n"), client->ClientName);
760 dump_client(client->next);
764 void dump_job(BSR_JOB *job)
767 Pmsg1(-1, _("Job : %s\n"), job->Job);
772 void dump_sesstime(BSR_SESSTIME *sesstime)
775 Pmsg1(-1, _("SessTime : %u\n"), sesstime->sesstime);
776 dump_sesstime(sesstime->next);
781 void dump_bsr(BSR *bsr, bool recurse)
783 int save_debug = debug_level;
786 Pmsg0(-1, _("BSR is NULL\n"));
787 debug_level = save_debug;
790 Pmsg1(-1, _("Next : 0x%x\n"), bsr->next);
791 Pmsg1(-1, _("Root bsr : 0x%x\n"), bsr->root);
792 dump_volume(bsr->volume);
793 dump_sessid(bsr->sessid);
794 dump_sesstime(bsr->sesstime);
795 dump_volfile(bsr->volfile);
796 dump_volblock(bsr->volblock);
797 dump_client(bsr->client);
798 dump_jobid(bsr->JobId);
800 dump_findex(bsr->FileIndex);
802 Pmsg1(-1, _("count : %u\n"), bsr->count);
803 Pmsg1(-1, _("found : %u\n"), bsr->found);
806 Pmsg1(-1, _("done : %s\n"), bsr->done?_("yes"):_("no"));
807 Pmsg1(-1, _("positioning : %d\n"), bsr->use_positioning);
808 Pmsg1(-1, _("fast_reject : %d\n"), bsr->use_fast_rejection);
809 if (recurse && bsr->next) {
811 dump_bsr(bsr->next, true);
813 debug_level = save_debug;
818 /*********************************************************************
823 static void free_bsr_item(BSR *bsr)
826 free_bsr_item(bsr->next);
831 void free_bsr(BSR *bsr)
836 free_bsr_item((BSR *)bsr->volume);
837 free_bsr_item((BSR *)bsr->client);
838 free_bsr_item((BSR *)bsr->sessid);
839 free_bsr_item((BSR *)bsr->sesstime);
840 free_bsr_item((BSR *)bsr->volfile);
841 free_bsr_item((BSR *)bsr->volblock);
842 free_bsr_item((BSR *)bsr->JobId);
843 free_bsr_item((BSR *)bsr->job);
844 free_bsr_item((BSR *)bsr->FileIndex);
845 free_bsr_item((BSR *)bsr->JobType);
846 free_bsr_item((BSR *)bsr->JobLevel);
847 if (bsr->fileregex) bfree(bsr->fileregex);
848 if (bsr->fileregex_re) {
849 regfree(bsr->fileregex_re);
850 free(bsr->fileregex_re);
852 if (bsr->attr) free_attr(bsr->attr);
858 /*****************************************************************
859 * Routines for handling volumes
861 VOL_LIST *new_restore_volume()
864 vol = (VOL_LIST *)malloc(sizeof(VOL_LIST));
865 memset(vol, 0, sizeof(VOL_LIST));
870 * Add current volume to end of list, only if the Volume
871 * is not already in the list.
873 * returns: 1 if volume added
874 * 0 if volume already in list
876 int add_restore_volume(JCR *jcr, VOL_LIST *vol)
878 VOL_LIST *next = jcr->VolList;
880 if (!next) { /* list empty ? */
881 jcr->VolList = vol; /* yes, add volume */
883 for ( ; next->next; next=next->next) {
884 if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
885 if (vol->start_file < next->start_file) {
886 next->start_file = vol->start_file;
888 return 0; /* already in list */
891 if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
892 if (vol->start_file < next->start_file) {
893 next->start_file = vol->start_file;
895 return 0; /* already in list */
897 next->next = vol; /* add volume */
902 void free_restore_volume_list(JCR *jcr)
904 VOL_LIST *next = jcr->VolList;
916 * Create a list of Volumes (and Slots and Start positions) to be
917 * used in the current restore job.
919 void create_restore_volume_list(JCR *jcr)
925 * Build a list of volumes to be processed
927 jcr->NumReadVolumes = 0;
928 jcr->CurReadVolume = 0;
931 if (!bsr->volume || !bsr->volume->VolumeName) {
934 for ( ; bsr; bsr=bsr->next) {
936 BSR_VOLFILE *volfile;
937 uint32_t sfile = UINT32_MAX;
939 /* Find minimum start file so that we can forward space to it */
940 for (volfile = bsr->volfile; volfile; volfile=volfile->next) {
941 if (volfile->sfile < sfile) {
942 sfile = volfile->sfile;
945 /* Now add volumes for this bsr */
946 for (bsrvol = bsr->volume; bsrvol; bsrvol=bsrvol->next) {
947 vol = new_restore_volume();
948 bstrncpy(vol->VolumeName, bsrvol->VolumeName, sizeof(vol->VolumeName));
949 bstrncpy(vol->MediaType, bsrvol->MediaType, sizeof(vol->MediaType));
950 bstrncpy(vol->device, bsrvol->device, sizeof(vol->device));
951 vol->Slot = bsrvol->Slot;
952 vol->start_file = sfile;
953 if (add_restore_volume(jcr, vol)) {
954 jcr->NumReadVolumes++;
955 Dmsg2(400, "Added volume=%s mediatype=%s\n", vol->VolumeName,
958 Dmsg1(400, "Duplicate volume %s\n", vol->VolumeName);
961 sfile = 0; /* start at beginning of second volume */
965 /* This is the old way -- deprecated */
966 for (p = jcr->dcr->VolumeName; p && *p; ) {
967 n = strchr(p, '|'); /* volume name separator */
969 *n++ = 0; /* Terminate name */
971 vol = new_restore_volume();
972 bstrncpy(vol->VolumeName, p, sizeof(vol->VolumeName));
973 bstrncpy(vol->MediaType, jcr->dcr->media_type, sizeof(vol->MediaType));
974 if (add_restore_volume(jcr, vol)) {
975 jcr->NumReadVolumes++;