2 * Match Bootstrap Records (used for restores) against
5 * 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 ammended 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.
30 #include "lib/fnmatch.h"
33 /* Forward references */
34 static int match_volume(BSR *bsr, BSR_VOLUME *volume, VOLUME_LABEL *volrec, bool done);
35 static int match_sesstime(BSR *bsr, BSR_SESSTIME *sesstime, DEV_RECORD *rec, bool done);
36 static int match_sessid(BSR *bsr, BSR_SESSID *sessid, DEV_RECORD *rec);
37 static int match_client(BSR *bsr, BSR_CLIENT *client, SESSION_LABEL *sessrec, bool done);
38 static int match_job(BSR *bsr, BSR_JOB *job, SESSION_LABEL *sessrec, bool done);
39 static int match_job_type(BSR *bsr, BSR_JOBTYPE *job_type, SESSION_LABEL *sessrec, bool done);
40 static int match_job_level(BSR *bsr, BSR_JOBLEVEL *job_level, SESSION_LABEL *sessrec, bool done);
41 static int match_jobid(BSR *bsr, BSR_JOBID *jobid, SESSION_LABEL *sessrec, bool done);
42 static int match_findex(BSR *bsr, BSR_FINDEX *findex, DEV_RECORD *rec, bool done);
43 static int match_volfile(BSR *bsr, BSR_VOLFILE *volfile, DEV_RECORD *rec, bool done);
44 static int match_stream(BSR *bsr, BSR_STREAM *stream, DEV_RECORD *rec, bool done);
45 static int match_all(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, SESSION_LABEL *sessrec, bool done);
46 static int match_block_sesstime(BSR *bsr, BSR_SESSTIME *sesstime, DEV_BLOCK *block);
47 static int match_block_sessid(BSR *bsr, BSR_SESSID *sessid, DEV_BLOCK *block);
48 static BSR *find_smallest_volfile(BSR *fbsr, BSR *bsr);
51 /*********************************************************************
53 * If possible, position the archive device (tape) to read the
56 void position_bsr_block(BSR *bsr, DEV_BLOCK *block)
58 /* To be implemented */
61 /*********************************************************************
63 * Do fast block rejection based on bootstrap records.
64 * use_fast_rejection will be set if we have VolSessionId and VolSessTime
65 * in each record. When BlockVer is >= 2, we have those in the block header
66 * so can do fast rejection.
68 * returns: 1 if block may contain valid records
69 * 0 if block may be skipped (i.e. it contains no records of
70 * that can match the bsr).
73 int match_bsr_block(BSR *bsr, DEV_BLOCK *block)
75 if (!bsr || !bsr->use_fast_rejection || (block->BlockVer < 2)) {
76 return 1; /* cannot fast reject */
79 for ( ; bsr; bsr=bsr->next) {
80 if (!match_block_sesstime(bsr, bsr->sesstime, block)) {
83 if (!match_block_sessid(bsr, bsr->sessid, block)) {
91 static int match_block_sesstime(BSR *bsr, BSR_SESSTIME *sesstime, DEV_BLOCK *block)
94 return 1; /* no specification matches all */
96 if (sesstime->sesstime == block->VolSessionTime) {
100 return match_block_sesstime(bsr, sesstime->next, block);
105 static int match_block_sessid(BSR *bsr, BSR_SESSID *sessid, DEV_BLOCK *block)
108 return 1; /* no specification matches all */
110 if (sessid->sessid <= block->VolSessionId && sessid->sessid2 >= block->VolSessionId) {
114 return match_block_sessid(bsr, sessid->next, block);
120 /*********************************************************************
122 * Match Bootstrap records
124 * returns 0 no match and reposition is set if we should
125 * reposition the tape
126 * returns -1 no additional matches possible
128 int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, SESSION_LABEL *sessrec)
133 * The bsr->reposition flag is set any time a bsr is done.
134 * In this case, we can probably reposition the
135 * tape to the next available bsr position.
138 bsr->reposition = false;
139 stat = match_all(bsr, rec, volrec, sessrec, true);
141 * Note, bsr->reposition is set by match_all when
142 * a bsr is done. We turn it off if a match was
143 * found or if we cannot use positioning
145 if (stat != 0 || !bsr->use_positioning) {
146 bsr->reposition = false;
149 stat = 1; /* no bsr => match all */
155 * Find the next bsr that applies to the current tape.
156 * It is the one with the smallest VolFile position.
158 BSR *find_next_bsr(BSR *root_bsr, DEVICE *dev)
161 BSR *found_bsr = NULL;
163 if (!root_bsr || !root_bsr->use_positioning ||
164 !root_bsr->reposition /* || !dev->is_tape()*/) {
165 Dmsg2(100, "No nxt_bsr use_pos=%d repos=%d\n", root_bsr->use_positioning, root_bsr->reposition);
168 Dmsg2(100, "use_pos=%d repos=%d\n", root_bsr->use_positioning, root_bsr->reposition);
169 root_bsr->mount_next_volume = false;
170 for (bsr=root_bsr; bsr; bsr=bsr->next) {
171 if (bsr->done || !match_volume(bsr, bsr->volume, &dev->VolHdr, 1)) {
174 if (found_bsr == NULL) {
177 found_bsr = find_smallest_volfile(found_bsr, bsr);
181 * If we get to this point and found no bsr, it means
182 * that any additional bsr's must apply to the next
183 * tape, so set a flag.
185 if (found_bsr == NULL) {
186 root_bsr->mount_next_volume = true;
191 static BSR *find_smallest_volfile(BSR *found_bsr, BSR *bsr)
193 BSR *return_bsr = found_bsr;
196 uint32_t found_bsr_sfile, bsr_sfile;
197 uint32_t found_bsr_sblock, bsr_sblock;
199 vf = found_bsr->volfile;
200 found_bsr_sfile = vf->sfile;
201 while ( (vf=vf->next) ) {
202 if (vf->sfile < found_bsr_sfile) {
203 found_bsr_sfile = vf->sfile;
207 bsr_sfile = vf->sfile;
208 while ( (vf=vf->next) ) {
209 if (vf->sfile < bsr_sfile) {
210 bsr_sfile = vf->sfile;
213 if (found_bsr_sfile > bsr_sfile) {
215 } else if (found_bsr_sfile == bsr_sfile) {
216 /* Must check block */
217 vb = found_bsr->volblock;
218 found_bsr_sblock = vb->sblock;
219 while ( (vb=vb->next) ) {
220 if (vb->sblock < found_bsr_sblock) {
221 found_bsr_sblock = vb->sblock;
225 bsr_sblock = vb->sblock;
226 while ( (vb=vb->next) ) {
227 if (vb->sblock < bsr_sblock) {
228 bsr_sblock = vb->sblock;
231 if (found_bsr_sblock > bsr_sblock) {
240 * Called to tell the matcher that the end of
241 * the current file has been reached.
242 * The bsr argument is not used, but is included
243 * for consistency with the other match calls.
245 * Returns: true if we should reposition
248 bool match_set_eof(BSR *bsr, DEV_RECORD *rec)
250 BSR *rbsr = rec->bsr;
251 Dmsg1(100, "match_set %d\n", rbsr != NULL);
257 if (rbsr->count && rbsr->found >= rbsr->count) {
259 rbsr->root->reposition = true;
260 Dmsg2(100, "match_set_eof reposition count=%d found=%d\n",
261 rbsr->count, rbsr->found);
268 * Match all the components of current record
271 * returns -1 no additional matches possible
273 static int match_all(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec,
274 SESSION_LABEL *sessrec, bool done)
279 if (!match_volume(bsr, bsr->volume, volrec, 1)) {
282 if (!match_volfile(bsr, bsr->volfile, rec, 1)) {
283 Dmsg2(100, "Fail on file. bsr=%d rec=%d\n", bsr->volfile->efile,
287 if (!match_sesstime(bsr, bsr->sesstime, rec, 1)) {
288 Dmsg2(100, "Fail on sesstime. bsr=%d rec=%d\n",
289 bsr->sesstime->sesstime, rec->VolSessionTime);
293 /* NOTE!! This test MUST come after the sesstime test */
294 if (!match_sessid(bsr, bsr->sessid, rec)) {
295 Dmsg2(100, "Fail on sessid. bsr=%d rec=%d\n",
296 bsr->sessid->sessid, rec->VolSessionId);
300 /* NOTE!! This test MUST come after sesstime and sessid tests */
301 if (!match_findex(bsr, bsr->FileIndex, rec, 1)) {
302 Dmsg2(100, "Fail on findex. bsr=%d rec=%d\n",
303 bsr->FileIndex->findex2, rec->FileIndex);
307 * If a count was specified and we have a FileIndex, assume
308 * it is a Bacula created bsr (or the equivalent). We
309 * then save the bsr where the match occurred so that
310 * after processing the record or records, we can update
311 * the found count. I.e. rec->bsr points to the bsr that
312 * satisfied the match.
314 if (bsr->count && bsr->FileIndex) {
316 return 1; /* this is a complete match */
320 * The selections below are not used by Bacula's
321 * restore command, and don't work because of
322 * the rec->bsr = bsr optimization above.
324 if (!match_jobid(bsr, bsr->JobId, sessrec, 1)) {
328 if (!match_job(bsr, bsr->job, sessrec, 1)) {
331 if (!match_client(bsr, bsr->client, sessrec, 1)) {
334 if (!match_job_type(bsr, bsr->JobType, sessrec, 1)) {
337 if (!match_job_level(bsr, bsr->JobLevel, sessrec, 1)) {
340 if (!match_stream(bsr, bsr->stream, rec, 1)) {
347 return match_all(bsr->next, rec, volrec, sessrec, bsr->done && done);
349 if (bsr->done && done) {
355 static int match_volume(BSR *bsr, BSR_VOLUME *volume, VOLUME_LABEL *volrec, bool done)
358 return 0; /* Volume must match */
360 if (strcmp(volume->VolumeName, volrec->VolName) == 0) {
364 return match_volume(bsr, volume->next, volrec, 1);
369 static int match_client(BSR *bsr, BSR_CLIENT *client, SESSION_LABEL *sessrec, bool done)
372 return 1; /* no specification matches all */
374 if (fnmatch(client->ClientName, sessrec->ClientName, 0) == 0) {
378 return match_client(bsr, client->next, sessrec, 1);
383 static int match_job(BSR *bsr, BSR_JOB *job, SESSION_LABEL *sessrec, bool done)
386 return 1; /* no specification matches all */
388 if (fnmatch(job->Job, sessrec->Job, 0) == 0) {
392 return match_job(bsr, job->next, sessrec, 1);
397 static int match_job_type(BSR *bsr, BSR_JOBTYPE *job_type, SESSION_LABEL *sessrec, bool done)
400 return 1; /* no specification matches all */
402 if (job_type->JobType == sessrec->JobType) {
405 if (job_type->next) {
406 return match_job_type(bsr, job_type->next, sessrec, 1);
411 static int match_job_level(BSR *bsr, BSR_JOBLEVEL *job_level, SESSION_LABEL *sessrec, bool done)
414 return 1; /* no specification matches all */
416 if (job_level->JobLevel == sessrec->JobLevel) {
419 if (job_level->next) {
420 return match_job_level(bsr, job_level->next, sessrec, 1);
425 static int match_jobid(BSR *bsr, BSR_JOBID *jobid, SESSION_LABEL *sessrec, bool done)
428 return 1; /* no specification matches all */
430 if (jobid->JobId <= sessrec->JobId && jobid->JobId2 >= sessrec->JobId) {
434 return match_jobid(bsr, jobid->next, sessrec, 1);
439 static int match_volfile(BSR *bsr, BSR_VOLFILE *volfile, DEV_RECORD *rec, bool done)
442 return 1; /* no specification matches all */
444 /* For the moment, these tests work only with tapes. */
445 if (!(rec->state & REC_ISTAPE)) {
446 return 1; /* All File records OK for this match */
448 // Dmsg3(100, "match_volfile: sfile=%d efile=%d recfile=%d\n",
449 // volfile->sfile, volfile->efile, rec->File);
450 if (volfile->sfile <= rec->File && volfile->efile >= rec->File) {
453 /* Once we get past last efile, we are done */
454 if (rec->File > volfile->efile) {
455 volfile->done = true; /* set local done */
458 return match_volfile(bsr, volfile->next, rec, volfile->done && done);
461 /* If we are done and all prior matches are done, this bsr is finished */
462 if (volfile->done && done) {
464 bsr->root->reposition = true;
465 Dmsg2(100, "bsr done from volfile rec=%d volefile=%d\n",
466 rec->File, volfile->efile);
471 static int match_stream(BSR *bsr, BSR_STREAM *stream, DEV_RECORD *rec, bool done)
474 return 1; /* no specification matches all */
476 if (stream->stream == rec->Stream) {
480 return match_stream(bsr, stream->next, rec, 1);
485 static int match_sesstime(BSR *bsr, BSR_SESSTIME *sesstime, DEV_RECORD *rec, bool done)
488 return 1; /* no specification matches all */
490 if (sesstime->sesstime == rec->VolSessionTime) {
493 if (rec->VolSessionTime > sesstime->sesstime) {
494 sesstime->done = true;
496 if (sesstime->next) {
497 return match_sesstime(bsr, sesstime->next, rec, sesstime->done && done);
499 if (sesstime->done && done) {
501 bsr->root->reposition = true;
502 Dmsg0(100, "bsr done from sesstime\n");
507 static int match_sessid(BSR *bsr, BSR_SESSID *sessid, DEV_RECORD *rec)
510 return 1; /* no specification matches all */
512 if (sessid->sessid <= rec->VolSessionId && sessid->sessid2 >= rec->VolSessionId) {
516 return match_sessid(bsr, sessid->next, rec);
522 * When reading the Volume, the Volume Findex (rec->FileIndex) always
523 * are found in sequential order. Thus we can make optimizations.
525 * ***FIXME*** optimizations
526 * We could optimize a lot here by removing the recursion, and
527 * stopping the search earlier -- say when rec->FileIndex > findex->findex2
528 * and findex->next == NULL. Also, the current entry tests could be skipped
529 * if findex->done is set.
531 static int match_findex(BSR *bsr, BSR_FINDEX *findex, DEV_RECORD *rec, bool done)
534 return 1; /* no specification matches all */
536 if (findex->findex <= rec->FileIndex && findex->findex2 >= rec->FileIndex) {
539 if (rec->FileIndex > findex->findex2) {
543 return match_findex(bsr, findex->next, rec, findex->done && done);
545 if (findex->done && done) {
547 bsr->root->reposition = true;
548 Dmsg1(100, "bsr done from findex %d\n", rec->FileIndex);