3 * Bacula Director -- Bootstrap Record routines.
5 * BSR (bootstrap record) handling routines split from
6 * ua_restore.c July MMIII
8 * Kern Sibbald, July MMII
14 Copyright (C) 2002-2005 Kern Sibbald
16 This program is free software; you can redistribute it and/or
17 modify it under the terms of the GNU General Public License
18 version 2 as amended with additional clauses defined in the
19 file LICENSE in the main source directory.
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 the file LICENSE for additional details.
31 /* Forward referenced functions */
32 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd);
33 void print_bsr(UAContext *ua, RBSR *bsr);
37 * Create new FileIndex entry for BSR
39 RBSR_FINDEX *new_findex()
41 RBSR_FINDEX *fi = (RBSR_FINDEX *)bmalloc(sizeof(RBSR_FINDEX));
42 memset(fi, 0, sizeof(RBSR_FINDEX));
46 /* Free all BSR FileIndex entries */
47 static void free_findex(RBSR_FINDEX *fi)
50 for ( ; fi; fi=next) {
57 * Our data structures were not designed completely
58 * correctly, so the file indexes cover the full
59 * range regardless of volume. The FirstIndex and LastIndex
60 * passed in here are for the current volume, so when
61 * writing out the fi, constrain them to those values.
63 * We are called here once for each JobMedia record
66 static uint32_t write_findex(UAContext *ua, RBSR_FINDEX *fi,
67 int32_t FirstIndex, int32_t LastIndex, FILE *fd)
70 for ( ; fi; fi=fi->next) {
71 int32_t findex, findex2;
72 if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
73 (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
74 (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
75 findex = fi->findex < FirstIndex ? FirstIndex : fi->findex;
76 findex2 = fi->findex2 > LastIndex ? LastIndex : fi->findex2;
77 if (findex == findex2) {
78 fprintf(fd, "FileIndex=%d\n", findex);
81 fprintf(fd, "FileIndex=%d-%d\n", findex, findex2);
82 count += findex2 - findex + 1;
90 * Find out if Volume defined with FirstIndex and LastIndex
91 * falls within the range of selected files in the bsr.
93 static bool is_volume_selected(RBSR_FINDEX *fi,
94 int32_t FirstIndex, int32_t LastIndex)
96 for ( ; fi; fi=fi->next) {
97 if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
98 (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
99 (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
108 static void print_findex(UAContext *ua, RBSR_FINDEX *fi)
110 bsendmsg(ua, "fi=0x%lx\n", fi);
111 for ( ; fi; fi=fi->next) {
112 if (fi->findex == fi->findex2) {
113 bsendmsg(ua, "FileIndex=%d\n", fi->findex);
114 Dmsg1(1000, "FileIndex=%d\n", fi->findex);
116 bsendmsg(ua, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
117 Dmsg2(1000, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
122 /* Create a new bootstrap record */
125 RBSR *bsr = (RBSR *)bmalloc(sizeof(RBSR));
126 memset(bsr, 0, sizeof(RBSR));
130 /* Free the entire BSR */
131 void free_bsr(RBSR *bsr)
134 for ( ; bsr; bsr=next) {
135 free_findex(bsr->fi);
136 if (bsr->VolParams) {
137 free(bsr->VolParams);
145 * Complete the BSR by filling in the VolumeName and
146 * VolSessionId and VolSessionTime using the JobId
148 bool complete_bsr(UAContext *ua, RBSR *bsr)
150 for ( ; bsr; bsr=bsr->next) {
152 memset(&jr, 0, sizeof(jr));
153 jr.JobId = bsr->JobId;
154 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
155 bsendmsg(ua, _("Unable to get Job record. ERR=%s\n"), db_strerror(ua->db));
158 bsr->VolSessionId = jr.VolSessionId;
159 bsr->VolSessionTime = jr.VolSessionTime;
160 if ((bsr->VolCount=db_get_job_volume_parameters(ua->jcr, ua->db, bsr->JobId,
161 &(bsr->VolParams))) == 0) {
162 bsendmsg(ua, _("Unable to get Job Volume Parameters. ERR=%s\n"), db_strerror(ua->db));
163 if (bsr->VolParams) {
164 free(bsr->VolParams);
165 bsr->VolParams = NULL;
173 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
174 static uint32_t uniq = 0;
176 void make_unique_restore_filename(UAContext *ua, POOLMEM **fname)
179 int i = find_arg_with_value(ua, "bootstrap");
181 Mmsg(fname, "%s", ua->argv[i]);
182 jcr->unlink_bsr = false;
187 Mmsg(fname, "%s/%s.%u.restore.bsr", working_directory, my_name, uniq);
188 jcr->unlink_bsr = true;
190 if (jcr->RestoreBootstrap) {
191 free(jcr->RestoreBootstrap);
193 jcr->RestoreBootstrap = bstrdup(*fname);
197 * Write the bootstrap records to file
199 uint32_t write_bsr_file(UAContext *ua, RESTORE_CTX &rx)
202 POOLMEM *fname = get_pool_memory(PM_MESSAGE);
208 make_unique_restore_filename(ua, &fname);
209 fd = fopen(fname, "w+");
212 bsendmsg(ua, _("Unable to create bootstrap file %s. ERR=%s\n"),
213 fname, be.strerror());
216 /* Write them to file */
217 count = write_bsr(ua, rx, fd);
221 bsendmsg(ua, _("Error writing bsr file.\n"));
227 bsendmsg(ua, _("Bootstrap records written to %s\n"), fname);
229 /* Tell the user what he will need to mount */
231 bsendmsg(ua, _("The job will require the following Volumes:\n"));
232 /* Create Unique list of Volumes using prompt list */
233 start_prompt(ua, "");
235 /* Ensure that the volumes are printed in JobId order */
236 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
237 for (RBSR *nbsr=rx.bsr; nbsr; nbsr=nbsr->next) {
238 if (JobId != nbsr->JobId) {
241 for (int i=0; i < nbsr->VolCount; i++) {
242 if (nbsr->VolParams[i].VolumeName[0]) {
243 add_prompt(ua, nbsr->VolParams[i].VolumeName);
249 /* Print Volumes in any order */
250 for (RBSR *nbsr=rx.bsr; nbsr; nbsr=nbsr->next) {
251 for (int i=0; i < nbsr->VolCount; i++) {
252 if (nbsr->VolParams[i].VolumeName[0]) {
253 add_prompt(ua, nbsr->VolParams[i].VolumeName);
258 for (int i=0; i < ua->num_prompts; i++) {
259 bsendmsg(ua, " %s\n", ua->prompt[i]);
262 if (ua->num_prompts == 0) {
263 bsendmsg(ua, _("No Volumes found to restore.\n"));
270 free_pool_memory(fname);
275 * Here we actually write out the details of the bsr file.
276 * Note, there is one bsr for each JobId, but the bsr may
277 * have multiple volumes, which have been entered in the
278 * order they were written.
279 * The bsrs must be written out in the order the JobIds
280 * are found in the jobid list.
282 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd)
285 uint32_t total_count = 0;
286 uint32_t LastIndex = 0;
291 if (*rx.JobIds == 0) {
292 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
294 * For a given volume, loop over all the JobMedia records.
295 * VolCount is the number of JobMedia records.
297 for (int i=0; i < bsr->VolCount; i++) {
298 if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
299 bsr->VolParams[i].LastIndex)) {
300 bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
303 fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
304 fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
305 fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
306 fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
307 if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) {
308 fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartFile);
310 fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
311 bsr->VolParams[i].EndFile);
313 if (bsr->VolParams[i].StartBlock == bsr->VolParams[i].EndBlock) {
314 fprintf(fd, "VolBlock=%u\n", bsr->VolParams[i].StartBlock);
316 fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
317 bsr->VolParams[i].EndBlock);
319 // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
320 // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
322 count = write_findex(ua, bsr->fi, bsr->VolParams[i].FirstIndex,
323 bsr->VolParams[i].LastIndex, fd);
325 fprintf(fd, "Count=%u\n", count);
327 total_count += count;
328 /* If the same file is present on two tapes or in two files
329 * on a tape, it is a continuation, and should not be treated
330 * twice in the totals.
332 if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
336 LastIndex = bsr->VolParams[i].LastIndex;
341 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
342 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
343 if (JobId != bsr->JobId) {
347 * For a given volume, loop over all the JobMedia records.
348 * VolCount is the number of JobMedia records.
350 for (int i=0; i < bsr->VolCount; i++) {
351 if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
352 bsr->VolParams[i].LastIndex)) {
353 bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
356 fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
357 fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
358 fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
359 fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
360 if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) {
361 fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartFile);
363 fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
364 bsr->VolParams[i].EndFile);
366 if (bsr->VolParams[i].StartBlock == bsr->VolParams[i].EndBlock) {
367 fprintf(fd, "VolBlock=%u\n", bsr->VolParams[i].StartBlock);
369 fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
370 bsr->VolParams[i].EndBlock);
372 // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
373 // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
375 count = write_findex(ua, bsr->fi, bsr->VolParams[i].FirstIndex,
376 bsr->VolParams[i].LastIndex, fd);
378 fprintf(fd, "Count=%u\n", count);
380 total_count += count;
381 /* If the same file is present on two tapes or in two files
382 * on a tape, it is a continuation, and should not be treated
383 * twice in the totals.
385 if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
389 LastIndex = bsr->VolParams[i].LastIndex;
396 void print_bsr(UAContext *ua, RBSR *bsr)
398 for ( ; bsr; bsr=bsr->next) {
399 for (int i=0; i < bsr->VolCount; i++) {
400 bsendmsg(ua, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
401 bsendmsg(ua, "MediaType\"%s\"\n", bsr->VolParams[i].MediaType);
402 bsendmsg(ua, "VolSessionId=%u\n", bsr->VolSessionId);
403 bsendmsg(ua, "VolSessionTime=%u\n", bsr->VolSessionTime);
404 bsendmsg(ua, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
405 bsr->VolParams[i].EndFile);
406 bsendmsg(ua, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
407 bsr->VolParams[i].EndBlock);
408 print_findex(ua, bsr->fi);
410 print_bsr(ua, bsr->next);
418 * Add a FileIndex to the list of BootStrap records.
419 * Here we are only dealing with JobId's and the FileIndexes
420 * associated with those JobIds.
422 void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
425 RBSR_FINDEX *fi, *lfi;
428 return; /* probably a dummy directory */
431 if (bsr->fi == NULL) { /* if no FI add one */
432 /* This is the first FileIndex item in the chain */
433 bsr->fi = new_findex();
435 bsr->fi->findex = findex;
436 bsr->fi->findex2 = findex;
439 /* Walk down list of bsrs until we find the JobId */
440 if (bsr->JobId != JobId) {
441 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
442 if (nbsr->JobId == JobId) {
448 if (!nbsr) { /* Must add new JobId */
449 /* Add new JobId at end of chain */
450 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
452 nbsr->next = new_bsr();
453 nbsr->next->JobId = JobId;
454 nbsr->next->fi = new_findex();
455 nbsr->next->fi->findex = findex;
456 nbsr->next->fi->findex2 = findex;
462 * At this point, bsr points to bsr containing this JobId,
463 * and we are sure that there is at least one fi record.
466 /* Check if this findex is smaller than first item */
467 if (findex < fi->findex) {
468 if ((findex+1) == fi->findex) {
469 fi->findex = findex; /* extend down */
472 fi = new_findex(); /* yes, insert before first item */
474 fi->findex2 = findex;
479 /* Walk down fi chain and find where to insert insert new FileIndex */
480 for ( ; fi; fi=fi->next) {
481 if (findex == (fi->findex2 + 1)) { /* extend up */
483 fi->findex2 = findex;
485 * If the following record contains one higher, merge its
486 * file index by extending it up.
488 if (fi->next && ((findex+1) == fi->next->findex)) {
490 fi->findex2 = nfi->findex2;
491 fi->next = nfi->next;
496 if (findex < fi->findex) { /* add before */
497 if ((findex+1) == fi->findex) {
505 /* Add to last place found */
508 fi->findex2 = findex;
509 fi->next = lfi->next;
515 * Add all possible FileIndexes to the list of BootStrap records.
516 * Here we are only dealing with JobId's and the FileIndexes
517 * associated with those JobIds.
519 void add_findex_all(RBSR *bsr, uint32_t JobId)
524 if (bsr->fi == NULL) { /* if no FI add one */
525 /* This is the first FileIndex item in the chain */
526 bsr->fi = new_findex();
529 bsr->fi->findex2 = INT32_MAX;
532 /* Walk down list of bsrs until we find the JobId */
533 if (bsr->JobId != JobId) {
534 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
535 if (nbsr->JobId == JobId) {
541 if (!nbsr) { /* Must add new JobId */
542 /* Add new JobId at end of chain */
543 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
545 nbsr->next = new_bsr();
546 nbsr->next->JobId = JobId;
547 nbsr->next->fi = new_findex();
548 nbsr->next->fi->findex = 1;
549 nbsr->next->fi->findex2 = INT32_MAX;
555 * At this point, bsr points to bsr containing this JobId,
556 * and we are sure that there is at least one fi record.
560 fi->findex2 = INT32_MAX;