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)) {
138 /* Create a new bootstrap record */
141 RBSR *bsr = (RBSR *)bmalloc(sizeof(RBSR));
142 memset(bsr, 0, sizeof(RBSR));
146 /* Free the entire BSR */
147 void free_bsr(RBSR *bsr)
150 for ( ; bsr; bsr=next) {
151 free_findex(bsr->fi);
152 if (bsr->VolParams) {
153 free(bsr->VolParams);
161 * Complete the BSR by filling in the VolumeName and
162 * VolSessionId and VolSessionTime using the JobId
164 bool complete_bsr(UAContext *ua, RBSR *bsr)
166 for ( ; bsr; bsr=bsr->next) {
168 memset(&jr, 0, sizeof(jr));
169 jr.JobId = bsr->JobId;
170 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
171 ua->error_msg(_("Unable to get Job record. ERR=%s\n"), db_strerror(ua->db));
174 bsr->VolSessionId = jr.VolSessionId;
175 bsr->VolSessionTime = jr.VolSessionTime;
176 if ((bsr->VolCount=db_get_job_volume_parameters(ua->jcr, ua->db, bsr->JobId,
177 &(bsr->VolParams))) == 0) {
178 ua->error_msg(_("Unable to get Job Volume Parameters. ERR=%s\n"), db_strerror(ua->db));
179 if (bsr->VolParams) {
180 free(bsr->VolParams);
181 bsr->VolParams = NULL;
189 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
190 static uint32_t uniq = 0;
192 static void make_unique_restore_filename(UAContext *ua, POOL_MEM &fname)
195 int i = find_arg_with_value(ua, "bootstrap");
197 Mmsg(fname, "%s", ua->argv[i]);
198 jcr->unlink_bsr = false;
203 Mmsg(fname, "%s/%s.restore.%u.bsr", working_directory, my_name, uniq);
204 jcr->unlink_bsr = true;
206 if (jcr->RestoreBootstrap) {
207 free(jcr->RestoreBootstrap);
209 jcr->RestoreBootstrap = bstrdup(fname.c_str());
213 * Write the bootstrap records to file
215 uint32_t write_bsr_file(UAContext *ua, RESTORE_CTX &rx)
218 POOL_MEM fname(PM_MESSAGE);
222 make_unique_restore_filename(ua, fname);
223 fd = fopen(fname.c_str(), "w+b");
226 ua->error_msg(_("Unable to create bootstrap file %s. ERR=%s\n"),
227 fname.c_str(), be.bstrerror());
230 /* Write them to file */
231 count = write_bsr(ua, rx, fd);
235 ua->info_msg(_("No files found to read. No bootstrap file written.\n"));
239 ua->error_msg(_("Error writing bsr file.\n"));
244 ua->send_msg(_("Bootstrap records written to %s\n"), fname.c_str());
246 if (debug_level >= 10) {
254 void display_bsr_info(UAContext *ua, RESTORE_CTX &rx)
257 POOL_MEM volmsg(PM_MESSAGE);
259 char Device[MAX_NAME_LENGTH];
262 /* Tell the user what he will need to mount */
264 ua->send_msg(_("The job will require the following\n"
265 " Volume(s) Storage(s) SD Device(s)\n"
266 "===========================================================================\n"));
267 /* Create Unique list of Volumes using prompt list */
268 start_prompt(ua, "");
269 if (*rx.JobIds == 0) {
270 /* Print Volumes in any order */
271 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
272 for (int i=0; i < bsr->VolCount; i++) {
273 if (bsr->VolParams[i].VolumeName[0]) {
274 if (!get_storage_device(Device, bsr->VolParams[i].Storage)) {
277 Mmsg(volmsg, "%-25.25s %-25.25s %-25.25s",
278 bsr->VolParams[i].VolumeName,
279 bsr->VolParams[i].Storage, Device);
280 add_prompt(ua, volmsg.c_str());
285 /* Ensure that the volumes are printed in JobId order */
286 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
287 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
288 if (JobId != bsr->JobId) {
291 for (int i=0; i < bsr->VolCount; i++) {
292 if (bsr->VolParams[i].VolumeName[0]) {
293 if (!get_storage_device(Device, bsr->VolParams[i].Storage)) {
296 Mmsg(volmsg, "%-25.25s %-25.25s %-25.25s",
297 bsr->VolParams[i].VolumeName,
298 bsr->VolParams[i].Storage, Device);
299 add_prompt(ua, volmsg.c_str());
305 for (int i=0; i < ua->num_prompts; i++) {
306 ua->send_msg(" %s\n", ua->prompt[i]);
309 if (ua->num_prompts == 0) {
310 ua->send_msg(_("No Volumes found to restore.\n"));
319 * Here we actually write out the details of the bsr file.
320 * Note, there is one bsr for each JobId, but the bsr may
321 * have multiple volumes, which have been entered in the
322 * order they were written.
323 * The bsrs must be written out in the order the JobIds
324 * are found in the jobid list.
326 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd)
329 uint32_t total_count = 0;
330 uint32_t LastIndex = 0;
334 char device[MAX_NAME_LENGTH];
336 if (*rx.JobIds == 0) {
337 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
339 * For a given volume, loop over all the JobMedia records.
340 * VolCount is the number of JobMedia records.
342 for (int i=0; i < bsr->VolCount; i++) {
343 if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
344 bsr->VolParams[i].LastIndex)) {
345 bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
349 find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
350 bsr->VolParams[i].MediaType);
352 fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
353 fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
354 if (bsr->fileregex) {
355 fprintf(fd, "FileRegex=%s\n", bsr->fileregex);
357 if (get_storage_device(device, bsr->VolParams[i].Storage)) {
358 fprintf(fd, "Device=\"%s\"\n", device);
360 if (bsr->VolParams[i].Slot > 0) {
361 fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot);
363 fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
364 fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
365 if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) {
366 fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartFile);
368 fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
369 bsr->VolParams[i].EndFile);
371 if (bsr->VolParams[i].StartBlock == bsr->VolParams[i].EndBlock) {
372 fprintf(fd, "VolBlock=%u\n", bsr->VolParams[i].StartBlock);
374 fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
375 bsr->VolParams[i].EndBlock);
377 // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
378 // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
380 count = write_findex(bsr->fi, bsr->VolParams[i].FirstIndex,
381 bsr->VolParams[i].LastIndex, fd);
383 fprintf(fd, "Count=%u\n", count);
385 total_count += count;
386 /* If the same file is present on two tapes or in two files
387 * on a tape, it is a continuation, and should not be treated
388 * twice in the totals.
390 if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
394 LastIndex = bsr->VolParams[i].LastIndex;
399 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
400 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
401 if (JobId != bsr->JobId) {
405 * For a given volume, loop over all the JobMedia records.
406 * VolCount is the number of JobMedia records.
408 for (int i=0; i < bsr->VolCount; i++) {
409 if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
410 bsr->VolParams[i].LastIndex)) {
411 bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
415 find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
416 bsr->VolParams[i].MediaType);
418 fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
419 fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
420 if (bsr->fileregex) {
421 fprintf(fd, "FileRegex=%s\n", bsr->fileregex);
423 if (get_storage_device(device, bsr->VolParams[i].Storage)) {
424 fprintf(fd, "Device=\"%s\"\n", device);
426 if (bsr->VolParams[i].Slot > 0) {
427 fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot);
429 fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
430 fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
431 if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) {
432 fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartFile);
434 fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
435 bsr->VolParams[i].EndFile);
437 if (bsr->VolParams[i].StartBlock == bsr->VolParams[i].EndBlock) {
438 fprintf(fd, "VolBlock=%u\n", bsr->VolParams[i].StartBlock);
440 fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
441 bsr->VolParams[i].EndBlock);
443 // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
444 // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
446 count = write_findex(bsr->fi, bsr->VolParams[i].FirstIndex,
447 bsr->VolParams[i].LastIndex, fd);
449 fprintf(fd, "Count=%u\n", count);
451 total_count += count;
452 /* If the same file is present on two tapes or in two files
453 * on a tape, it is a continuation, and should not be treated
454 * twice in the totals.
456 if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
460 LastIndex = bsr->VolParams[i].LastIndex;
467 void print_bsr(UAContext *ua, RESTORE_CTX &rx)
469 write_bsr(ua, rx, stdout);
476 * Add a FileIndex to the list of BootStrap records.
477 * Here we are only dealing with JobId's and the FileIndexes
478 * associated with those JobIds.
479 * We expect that JobId, FileIndex are sorted ascending.
481 void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
484 RBSR_FINDEX *fi, *lfi;
487 return; /* probably a dummy directory */
490 if (bsr->fi == NULL) { /* if no FI add one */
491 /* This is the first FileIndex item in the chain */
492 bsr->fi = new_findex();
494 bsr->fi->findex = findex;
495 bsr->fi->findex2 = findex;
498 /* Walk down list of bsrs until we find the JobId */
499 if (bsr->JobId != JobId) {
500 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
501 if (nbsr->JobId == JobId) {
507 if (!nbsr) { /* Must add new JobId */
508 /* Add new JobId at end of chain */
509 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
511 nbsr->next = new_bsr();
512 nbsr->next->JobId = JobId;
513 nbsr->next->fi = new_findex();
514 nbsr->next->fi->findex = findex;
515 nbsr->next->fi->findex2 = findex;
521 * At this point, bsr points to bsr containing this JobId,
522 * and we are sure that there is at least one fi record.
525 /* Check if this findex is smaller than first item */
526 if (findex < fi->findex) {
527 if ((findex+1) == fi->findex) {
528 fi->findex = findex; /* extend down */
531 fi = new_findex(); /* yes, insert before first item */
533 fi->findex2 = findex;
538 /* Walk down fi chain and find where to insert insert new FileIndex */
539 for ( ; fi; fi=fi->next) {
540 if (findex == (fi->findex2 + 1)) { /* extend up */
542 fi->findex2 = findex;
544 * If the following record contains one higher, merge its
545 * file index by extending it up.
547 if (fi->next && ((findex+1) == fi->next->findex)) {
549 fi->findex2 = nfi->findex2;
550 fi->next = nfi->next;
555 if (findex < fi->findex) { /* add before */
556 if ((findex+1) == fi->findex) {
564 /* Add to last place found */
567 fi->findex2 = findex;
568 fi->next = lfi->next;
574 * Add all possible FileIndexes to the list of BootStrap records.
575 * Here we are only dealing with JobId's and the FileIndexes
576 * associated with those JobIds.
578 void add_findex_all(RBSR *bsr, uint32_t JobId)
583 if (bsr->fi == NULL) { /* if no FI add one */
584 /* This is the first FileIndex item in the chain */
585 bsr->fi = new_findex();
588 bsr->fi->findex2 = INT32_MAX;
591 /* Walk down list of bsrs until we find the JobId */
592 if (bsr->JobId != JobId) {
593 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
594 if (nbsr->JobId == JobId) {
600 if (!nbsr) { /* Must add new JobId */
601 /* Add new JobId at end of chain */
602 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
604 nbsr->next = new_bsr();
605 nbsr->next->JobId = JobId;
606 nbsr->next->fi = new_findex();
607 nbsr->next->fi->findex = 1;
608 nbsr->next->fi->findex2 = INT32_MAX;
614 * At this point, bsr points to bsr containing this JobId,
615 * and we are sure that there is at least one fi record.
619 fi->findex2 = INT32_MAX;