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(200, "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.strerror());
147 lc->caller_ctx = (void *)jcr;
148 while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
149 Dmsg1(200, "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 (200, "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(200, "calling handler for %s\n", items[i].name);
163 /* Call item handler */
164 bsr = items[i].handler(lc, bsr);
170 Dmsg1(200, "Keyword = %s\n", lc->str);
171 scan_err1(lc, "Keyword %s not found", lc->str);
179 lc = lex_close_file(lc);
180 Dmsg0(200, "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);
757 void dump_bsr(BSR *bsr, bool recurse)
759 int save_debug = debug_level;
762 Pmsg0(-1, _("BSR is NULL\n"));
763 debug_level = save_debug;
766 Pmsg1(-1, _("Next : 0x%x\n"), bsr->next);
767 Pmsg1(-1, _("Root bsr : 0x%x\n"), bsr->root);
768 dump_volume(bsr->volume);
769 dump_sessid(bsr->sessid);
770 dump_sesstime(bsr->sesstime);
771 dump_volfile(bsr->volfile);
772 dump_volblock(bsr->volblock);
773 dump_client(bsr->client);
774 dump_jobid(bsr->JobId);
776 dump_findex(bsr->FileIndex);
778 Pmsg1(-1, _("count : %u\n"), bsr->count);
779 Pmsg1(-1, _("found : %u\n"), bsr->found);
782 Pmsg1(-1, _("done : %s\n"), bsr->done?_("yes"):_("no"));
783 Pmsg1(-1, _("positioning : %d\n"), bsr->use_positioning);
784 Pmsg1(-1, _("fast_reject : %d\n"), bsr->use_fast_rejection);
785 if (recurse && bsr->next) {
787 dump_bsr(bsr->next, true);
789 debug_level = save_debug;
794 /*********************************************************************
799 static void free_bsr_item(BSR *bsr)
802 free_bsr_item(bsr->next);
807 void free_bsr(BSR *bsr)
812 free_bsr_item((BSR *)bsr->volume);
813 free_bsr_item((BSR *)bsr->client);
814 free_bsr_item((BSR *)bsr->sessid);
815 free_bsr_item((BSR *)bsr->sesstime);
816 free_bsr_item((BSR *)bsr->volfile);
817 free_bsr_item((BSR *)bsr->volblock);
818 free_bsr_item((BSR *)bsr->JobId);
819 free_bsr_item((BSR *)bsr->job);
820 free_bsr_item((BSR *)bsr->FileIndex);
821 free_bsr_item((BSR *)bsr->JobType);
822 free_bsr_item((BSR *)bsr->JobLevel);
827 /*****************************************************************
828 * Routines for handling volumes
830 VOL_LIST *new_restore_volume()
833 vol = (VOL_LIST *)malloc(sizeof(VOL_LIST));
834 memset(vol, 0, sizeof(VOL_LIST));
839 * Add current volume to end of list, only if the Volume
840 * is not already in the list.
842 * returns: 1 if volume added
843 * 0 if volume already in list
845 int add_restore_volume(JCR *jcr, VOL_LIST *vol)
847 VOL_LIST *next = jcr->VolList;
849 if (!next) { /* list empty ? */
850 jcr->VolList = vol; /* yes, add volume */
852 for ( ; next->next; next=next->next) {
853 if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
854 if (vol->start_file < next->start_file) {
855 next->start_file = vol->start_file;
857 return 0; /* already in list */
860 if (strcmp(vol->VolumeName, next->VolumeName) == 0) {
861 if (vol->start_file < next->start_file) {
862 next->start_file = vol->start_file;
864 return 0; /* already in list */
866 next->next = vol; /* add volume */
871 void free_restore_volume_list(JCR *jcr)
873 VOL_LIST *next = jcr->VolList;
885 * Create a list of Volumes (and Slots and Start positions) to be
886 * used in the current restore job.
888 void create_restore_volume_list(JCR *jcr)
894 * Build a list of volumes to be processed
900 if (!bsr->volume || !bsr->volume->VolumeName) {
903 for ( ; bsr; bsr=bsr->next) {
905 BSR_VOLFILE *volfile;
906 uint32_t sfile = UINT32_MAX;
908 /* Find minimum start file so that we can forward space to it */
909 for (volfile = bsr->volfile; volfile; volfile=volfile->next) {
910 if (volfile->sfile < sfile) {
911 sfile = volfile->sfile;
914 /* Now add volumes for this bsr */
915 for (bsrvol = bsr->volume; bsrvol; bsrvol=bsrvol->next) {
916 vol = new_restore_volume();
917 bstrncpy(vol->VolumeName, bsrvol->VolumeName, sizeof(vol->VolumeName));
918 bstrncpy(vol->MediaType, bsrvol->MediaType, sizeof(vol->MediaType));
919 bstrncpy(vol->device, bsrvol->device, sizeof(vol->device));
920 vol->Slot = bsrvol->Slot;
921 vol->start_file = sfile;
922 if (add_restore_volume(jcr, vol)) {
924 Dmsg2(400, "Added volume=%s mediatype=%s\n", vol->VolumeName,
927 Dmsg1(400, "Duplicate volume %s\n", vol->VolumeName);
930 sfile = 0; /* start at beginning of second volume */
934 /* This is the old way -- deprecated */
935 for (p = jcr->dcr->VolumeName; p && *p; ) {
936 n = strchr(p, '|'); /* volume name separator */
938 *n++ = 0; /* Terminate name */
940 vol = new_restore_volume();
941 bstrncpy(vol->VolumeName, p, sizeof(vol->VolumeName));
942 bstrncpy(vol->MediaType, jcr->dcr->media_type, sizeof(vol->MediaType));
943 if (add_restore_volume(jcr, vol)) {