2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * Bacula Director -- Bootstrap Record routines.
32 * BSR (bootstrap record) handling routines split from
33 * ua_restore.c July MMIII
35 * Kern Sibbald, July MMII
43 /* Forward referenced functions */
44 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd);
47 * Create new FileIndex entry for BSR
49 RBSR_FINDEX *new_findex()
51 RBSR_FINDEX *fi = (RBSR_FINDEX *)bmalloc(sizeof(RBSR_FINDEX));
52 memset(fi, 0, sizeof(RBSR_FINDEX));
56 /* Free all BSR FileIndex entries */
57 static void free_findex(RBSR_FINDEX *fi)
60 for ( ; fi; fi=next) {
67 * Get storage device name from Storage resource
69 static bool get_storage_device(char *device, char *storage)
72 if (storage[0] == 0) {
75 store = (STORE *)GetResWithName(R_STORAGE, storage);
79 DEVICE *dev = (DEVICE *)(store->device->first());
83 bstrncpy(device, dev->hdr.name, MAX_NAME_LENGTH);
88 * Our data structures were not designed completely
89 * correctly, so the file indexes cover the full
90 * range regardless of volume. The FirstIndex and LastIndex
91 * passed in here are for the current volume, so when
92 * writing out the fi, constrain them to those values.
94 * We are called here once for each JobMedia record
97 static uint32_t write_findex(RBSR_FINDEX *fi,
98 int32_t FirstIndex, int32_t LastIndex, FILE *fd)
101 for ( ; fi; fi=fi->next) {
102 int32_t findex, findex2;
103 if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
104 (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
105 (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
106 findex = fi->findex < FirstIndex ? FirstIndex : fi->findex;
107 findex2 = fi->findex2 > LastIndex ? LastIndex : fi->findex2;
108 if (findex == findex2) {
109 fprintf(fd, "FileIndex=%d\n", findex);
112 fprintf(fd, "FileIndex=%d-%d\n", findex, findex2);
113 count += findex2 - findex + 1;
121 * Find out if Volume defined with FirstIndex and LastIndex
122 * falls within the range of selected files in the bsr.
124 static bool is_volume_selected(RBSR_FINDEX *fi,
125 int32_t FirstIndex, int32_t LastIndex)
127 for ( ; fi; fi=fi->next) {
128 if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
129 (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
130 (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
139 static void print_findex(UAContext *ua, RBSR_FINDEX *fi)
141 ua->send_msg("fi=0x%lx\n", fi);
142 for ( ; fi; fi=fi->next) {
143 if (fi->findex == fi->findex2) {
144 ua->send_msg("FileIndex=%d\n", fi->findex);
145 Dmsg1(1000, "FileIndex=%d\n", fi->findex);
147 ua->send_msg("FileIndex=%d-%d\n", fi->findex, fi->findex2);
148 Dmsg2(1000, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
153 /* Create a new bootstrap record */
156 RBSR *bsr = (RBSR *)bmalloc(sizeof(RBSR));
157 memset(bsr, 0, sizeof(RBSR));
161 /* Free the entire BSR */
162 void free_bsr(RBSR *bsr)
165 for ( ; bsr; bsr=next) {
166 free_findex(bsr->fi);
167 if (bsr->VolParams) {
168 free(bsr->VolParams);
176 * Complete the BSR by filling in the VolumeName and
177 * VolSessionId and VolSessionTime using the JobId
179 bool complete_bsr(UAContext *ua, RBSR *bsr)
181 for ( ; bsr; bsr=bsr->next) {
183 memset(&jr, 0, sizeof(jr));
184 jr.JobId = bsr->JobId;
185 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
186 ua->error_msg(_("Unable to get Job record. ERR=%s\n"), db_strerror(ua->db));
189 bsr->VolSessionId = jr.VolSessionId;
190 bsr->VolSessionTime = jr.VolSessionTime;
191 if ((bsr->VolCount=db_get_job_volume_parameters(ua->jcr, ua->db, bsr->JobId,
192 &(bsr->VolParams))) == 0) {
193 ua->error_msg(_("Unable to get Job Volume Parameters. ERR=%s\n"), db_strerror(ua->db));
194 if (bsr->VolParams) {
195 free(bsr->VolParams);
196 bsr->VolParams = NULL;
204 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
205 static uint32_t uniq = 0;
207 static void make_unique_restore_filename(UAContext *ua, POOL_MEM &fname)
210 int i = find_arg_with_value(ua, "bootstrap");
212 Mmsg(fname, "%s", ua->argv[i]);
213 jcr->unlink_bsr = false;
218 Mmsg(fname, "%s/%s.restore.%u.bsr", working_directory, my_name, uniq);
219 jcr->unlink_bsr = true;
221 if (jcr->RestoreBootstrap) {
222 free(jcr->RestoreBootstrap);
224 jcr->RestoreBootstrap = bstrdup(fname.c_str());
228 * Write the bootstrap records to file
230 uint32_t write_bsr_file(UAContext *ua, RESTORE_CTX &rx)
233 POOL_MEM fname(PM_MESSAGE);
237 make_unique_restore_filename(ua, fname);
238 fd = fopen(fname.c_str(), "w+b");
241 ua->error_msg(_("Unable to create bootstrap file %s. ERR=%s\n"),
242 fname.c_str(), be.bstrerror());
245 /* Write them to file */
246 count = write_bsr(ua, rx, fd);
250 ua->info_msg(_("No files found to read. No bootstrap file written.\n"));
254 ua->error_msg(_("Error writing bsr file.\n"));
259 ua->send_msg(_("Bootstrap records written to %s\n"), fname.c_str());
265 void display_bsr_info(UAContext *ua, RESTORE_CTX &rx)
268 POOL_MEM volmsg(PM_MESSAGE);
270 char Device[MAX_NAME_LENGTH];
273 /* Tell the user what he will need to mount */
275 ua->send_msg(_("The job will require the following\n"
276 " Volume(s) Storage(s) SD Device(s)\n"
277 "===========================================================================\n"));
278 /* Create Unique list of Volumes using prompt list */
279 start_prompt(ua, "");
280 if (*rx.JobIds == 0) {
281 /* Print Volumes in any order */
282 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
283 for (int i=0; i < bsr->VolCount; i++) {
284 if (bsr->VolParams[i].VolumeName[0]) {
285 if (!get_storage_device(Device, bsr->VolParams[i].Storage)) {
288 Mmsg(volmsg, "%-25.25s %-25.25s %-25.25s",
289 bsr->VolParams[i].VolumeName,
290 bsr->VolParams[i].Storage, Device);
291 add_prompt(ua, volmsg.c_str());
296 /* Ensure that the volumes are printed in JobId order */
297 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
298 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
299 if (JobId != bsr->JobId) {
302 for (int i=0; i < bsr->VolCount; i++) {
303 if (bsr->VolParams[i].VolumeName[0]) {
304 if (!get_storage_device(Device, bsr->VolParams[i].Storage)) {
307 Mmsg(volmsg, "%-25.25s %-25.25s %-25.25s",
308 bsr->VolParams[i].VolumeName,
309 bsr->VolParams[i].Storage, Device);
310 add_prompt(ua, volmsg.c_str());
316 for (int i=0; i < ua->num_prompts; i++) {
317 ua->send_msg(" %s\n", ua->prompt[i]);
320 if (ua->num_prompts == 0) {
321 ua->send_msg(_("No Volumes found to restore.\n"));
330 * Here we actually write out the details of the bsr file.
331 * Note, there is one bsr for each JobId, but the bsr may
332 * have multiple volumes, which have been entered in the
333 * order they were written.
334 * The bsrs must be written out in the order the JobIds
335 * are found in the jobid list.
337 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd)
340 uint32_t total_count = 0;
341 uint32_t LastIndex = 0;
345 char device[MAX_NAME_LENGTH];
347 if (*rx.JobIds == 0) {
348 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
350 * For a given volume, loop over all the JobMedia records.
351 * VolCount is the number of JobMedia records.
353 for (int i=0; i < bsr->VolCount; i++) {
354 if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
355 bsr->VolParams[i].LastIndex)) {
356 bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
360 find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
361 bsr->VolParams[i].MediaType);
363 fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
364 fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
365 if (get_storage_device(device, bsr->VolParams[i].Storage)) {
366 fprintf(fd, "Device=\"%s\"\n", device);
368 if (bsr->VolParams[i].Slot > 0) {
369 fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot);
371 fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
372 fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
373 if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) {
374 fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartFile);
376 fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
377 bsr->VolParams[i].EndFile);
379 if (bsr->VolParams[i].StartBlock == bsr->VolParams[i].EndBlock) {
380 fprintf(fd, "VolBlock=%u\n", bsr->VolParams[i].StartBlock);
382 fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
383 bsr->VolParams[i].EndBlock);
385 // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
386 // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
388 count = write_findex(bsr->fi, bsr->VolParams[i].FirstIndex,
389 bsr->VolParams[i].LastIndex, fd);
391 fprintf(fd, "Count=%u\n", count);
393 total_count += count;
394 /* If the same file is present on two tapes or in two files
395 * on a tape, it is a continuation, and should not be treated
396 * twice in the totals.
398 if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
402 LastIndex = bsr->VolParams[i].LastIndex;
407 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
408 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
409 if (JobId != bsr->JobId) {
413 * For a given volume, loop over all the JobMedia records.
414 * VolCount is the number of JobMedia records.
416 for (int i=0; i < bsr->VolCount; i++) {
417 if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
418 bsr->VolParams[i].LastIndex)) {
419 bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
423 find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
424 bsr->VolParams[i].MediaType);
426 fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
427 fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
428 if (get_storage_device(device, bsr->VolParams[i].Storage)) {
429 fprintf(fd, "Device=\"%s\"\n", device);
431 if (bsr->VolParams[i].Slot > 0) {
432 fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot);
434 fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
435 fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
436 if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) {
437 fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartFile);
439 fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
440 bsr->VolParams[i].EndFile);
442 if (bsr->VolParams[i].StartBlock == bsr->VolParams[i].EndBlock) {
443 fprintf(fd, "VolBlock=%u\n", bsr->VolParams[i].StartBlock);
445 fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
446 bsr->VolParams[i].EndBlock);
448 // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
449 // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
451 count = write_findex(bsr->fi, bsr->VolParams[i].FirstIndex,
452 bsr->VolParams[i].LastIndex, fd);
454 fprintf(fd, "Count=%u\n", count);
456 total_count += count;
457 /* If the same file is present on two tapes or in two files
458 * on a tape, it is a continuation, and should not be treated
459 * twice in the totals.
461 if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
465 LastIndex = bsr->VolParams[i].LastIndex;
472 void print_bsr(UAContext *ua, RBSR *bsr)
474 for ( ; bsr; bsr=bsr->next) {
475 for (int i=0; i < bsr->VolCount; i++) {
476 ua->send_msg("Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
477 ua->send_msg("MediaType\"%s\"\n", bsr->VolParams[i].MediaType);
478 ua->send_msg("VolSessionId=%u\n", bsr->VolSessionId);
479 ua->send_msg("VolSessionTime=%u\n", bsr->VolSessionTime);
480 ua->send_msg("VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
481 bsr->VolParams[i].EndFile);
482 ua->send_msg("VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
483 bsr->VolParams[i].EndBlock);
484 print_findex(ua, bsr->fi);
486 print_bsr(ua, bsr->next);
494 * Add a FileIndex to the list of BootStrap records.
495 * Here we are only dealing with JobId's and the FileIndexes
496 * associated with those JobIds.
497 * We expect that JobId, FileIndex are sorted ascending.
499 void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
502 RBSR_FINDEX *fi, *lfi;
505 return; /* probably a dummy directory */
508 if (bsr->fi == NULL) { /* if no FI add one */
509 /* This is the first FileIndex item in the chain */
510 bsr->fi = new_findex();
512 bsr->fi->findex = findex;
513 bsr->fi->findex2 = findex;
516 /* Walk down list of bsrs until we find the JobId */
517 if (bsr->JobId != JobId) {
518 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
519 if (nbsr->JobId == JobId) {
525 if (!nbsr) { /* Must add new JobId */
526 /* Add new JobId at end of chain */
527 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
529 nbsr->next = new_bsr();
530 nbsr->next->JobId = JobId;
531 nbsr->next->fi = new_findex();
532 nbsr->next->fi->findex = findex;
533 nbsr->next->fi->findex2 = findex;
539 * At this point, bsr points to bsr containing this JobId,
540 * and we are sure that there is at least one fi record.
543 /* Check if this findex is smaller than first item */
544 if (findex < fi->findex) {
545 if ((findex+1) == fi->findex) {
546 fi->findex = findex; /* extend down */
549 fi = new_findex(); /* yes, insert before first item */
551 fi->findex2 = findex;
556 /* Walk down fi chain and find where to insert insert new FileIndex */
557 for ( ; fi; fi=fi->next) {
558 if (findex == (fi->findex2 + 1)) { /* extend up */
560 fi->findex2 = findex;
562 * If the following record contains one higher, merge its
563 * file index by extending it up.
565 if (fi->next && ((findex+1) == fi->next->findex)) {
567 fi->findex2 = nfi->findex2;
568 fi->next = nfi->next;
573 if (findex < fi->findex) { /* add before */
574 if ((findex+1) == fi->findex) {
582 /* Add to last place found */
585 fi->findex2 = findex;
586 fi->next = lfi->next;
592 * Add all possible FileIndexes to the list of BootStrap records.
593 * Here we are only dealing with JobId's and the FileIndexes
594 * associated with those JobIds.
596 void add_findex_all(RBSR *bsr, uint32_t JobId)
601 if (bsr->fi == NULL) { /* if no FI add one */
602 /* This is the first FileIndex item in the chain */
603 bsr->fi = new_findex();
606 bsr->fi->findex2 = INT32_MAX;
609 /* Walk down list of bsrs until we find the JobId */
610 if (bsr->JobId != JobId) {
611 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
612 if (nbsr->JobId == JobId) {
618 if (!nbsr) { /* Must add new JobId */
619 /* Add new JobId at end of chain */
620 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
622 nbsr->next = new_bsr();
623 nbsr->next->JobId = JobId;
624 nbsr->next->fi = new_findex();
625 nbsr->next->fi->findex = 1;
626 nbsr->next->fi->findex2 = INT32_MAX;
632 * At this point, bsr points to bsr containing this JobId,
633 * and we are sure that there is at least one fi record.
637 fi->findex2 = INT32_MAX;