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);
155 if (bsr->fileregex) {
156 free(bsr->fileregex);
164 * Complete the BSR by filling in the VolumeName and
165 * VolSessionId and VolSessionTime using the JobId
167 bool complete_bsr(UAContext *ua, RBSR *bsr)
169 for ( ; bsr; bsr=bsr->next) {
171 memset(&jr, 0, sizeof(jr));
172 jr.JobId = bsr->JobId;
173 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
174 ua->error_msg(_("Unable to get Job record. ERR=%s\n"), db_strerror(ua->db));
177 bsr->VolSessionId = jr.VolSessionId;
178 bsr->VolSessionTime = jr.VolSessionTime;
179 if ((bsr->VolCount=db_get_job_volume_parameters(ua->jcr, ua->db, bsr->JobId,
180 &(bsr->VolParams))) == 0) {
181 ua->error_msg(_("Unable to get Job Volume Parameters. ERR=%s\n"), db_strerror(ua->db));
182 if (bsr->VolParams) {
183 free(bsr->VolParams);
184 bsr->VolParams = NULL;
192 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
193 static uint32_t uniq = 0;
195 static void make_unique_restore_filename(UAContext *ua, POOL_MEM &fname)
198 int i = find_arg_with_value(ua, "bootstrap");
200 Mmsg(fname, "%s", ua->argv[i]);
201 jcr->unlink_bsr = false;
206 Mmsg(fname, "%s/%s.restore.%u.bsr", working_directory, my_name, uniq);
207 jcr->unlink_bsr = true;
209 if (jcr->RestoreBootstrap) {
210 free(jcr->RestoreBootstrap);
212 jcr->RestoreBootstrap = bstrdup(fname.c_str());
216 * Write the bootstrap records to file
218 uint32_t write_bsr_file(UAContext *ua, RESTORE_CTX &rx)
221 POOL_MEM fname(PM_MESSAGE);
225 make_unique_restore_filename(ua, fname);
226 fd = fopen(fname.c_str(), "w+b");
229 ua->error_msg(_("Unable to create bootstrap file %s. ERR=%s\n"),
230 fname.c_str(), be.bstrerror());
233 /* Write them to file */
234 count = write_bsr(ua, rx, fd);
238 ua->info_msg(_("No files found to read. No bootstrap file written.\n"));
242 ua->error_msg(_("Error writing bsr file.\n"));
247 ua->send_msg(_("Bootstrap records written to %s\n"), fname.c_str());
249 if (debug_level >= 10) {
257 void display_bsr_info(UAContext *ua, RESTORE_CTX &rx)
260 POOL_MEM volmsg(PM_MESSAGE);
262 char Device[MAX_NAME_LENGTH];
265 /* Tell the user what he will need to mount */
267 ua->send_msg(_("The job will require the following\n"
268 " Volume(s) Storage(s) SD Device(s)\n"
269 "===========================================================================\n"));
270 /* Create Unique list of Volumes using prompt list */
271 start_prompt(ua, "");
272 if (*rx.JobIds == 0) {
273 /* Print Volumes in any order */
274 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
275 for (int i=0; i < bsr->VolCount; i++) {
276 if (bsr->VolParams[i].VolumeName[0]) {
277 if (!get_storage_device(Device, bsr->VolParams[i].Storage)) {
280 Mmsg(volmsg, "%-25.25s %-25.25s %-25.25s",
281 bsr->VolParams[i].VolumeName,
282 bsr->VolParams[i].Storage, Device);
283 add_prompt(ua, volmsg.c_str());
288 /* Ensure that the volumes are printed in JobId order */
289 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
290 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
291 if (JobId != bsr->JobId) {
294 for (int i=0; i < bsr->VolCount; i++) {
295 if (bsr->VolParams[i].VolumeName[0]) {
296 if (!get_storage_device(Device, bsr->VolParams[i].Storage)) {
299 Mmsg(volmsg, "%-25.25s %-25.25s %-25.25s",
300 bsr->VolParams[i].VolumeName,
301 bsr->VolParams[i].Storage, Device);
302 add_prompt(ua, volmsg.c_str());
308 for (int i=0; i < ua->num_prompts; i++) {
309 ua->send_msg(" %s\n", ua->prompt[i]);
312 if (ua->num_prompts == 0) {
313 ua->send_msg(_("No Volumes found to restore.\n"));
322 * Here we actually write out the details of the bsr file.
323 * Note, there is one bsr for each JobId, but the bsr may
324 * have multiple volumes, which have been entered in the
325 * order they were written.
326 * The bsrs must be written out in the order the JobIds
327 * are found in the jobid list.
329 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd)
331 char ed1[50], ed2[50];
333 uint32_t total_count = 0;
334 uint32_t LastIndex = 0;
338 char device[MAX_NAME_LENGTH];
340 if (*rx.JobIds == 0) {
341 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
343 * For a given volume, loop over all the JobMedia records.
344 * VolCount is the number of JobMedia records.
346 for (int i=0; i < bsr->VolCount; i++) {
347 if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
348 bsr->VolParams[i].LastIndex)) {
349 bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
353 find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
354 bsr->VolParams[i].MediaType);
356 fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
357 fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
358 if (bsr->fileregex) {
359 fprintf(fd, "FileRegex=%s\n", bsr->fileregex);
361 if (get_storage_device(device, bsr->VolParams[i].Storage)) {
362 fprintf(fd, "Device=\"%s\"\n", device);
364 if (bsr->VolParams[i].Slot > 0) {
365 fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot);
367 fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
368 fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
369 fprintf(fd, "VolAddr=%s-%s\n", edit_uint64(bsr->VolParams[i].StartAddr, ed1),
370 edit_uint64(bsr->VolParams[i].EndAddr, ed2));
371 // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
372 // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
374 count = write_findex(bsr->fi, bsr->VolParams[i].FirstIndex,
375 bsr->VolParams[i].LastIndex, fd);
377 fprintf(fd, "Count=%u\n", count);
379 total_count += count;
380 /* If the same file is present on two tapes or in two files
381 * on a tape, it is a continuation, and should not be treated
382 * twice in the totals.
384 if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
388 LastIndex = bsr->VolParams[i].LastIndex;
393 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
394 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
395 if (JobId != bsr->JobId) {
399 * For a given volume, loop over all the JobMedia records.
400 * VolCount is the number of JobMedia records.
402 for (int i=0; i < bsr->VolCount; i++) {
403 if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
404 bsr->VolParams[i].LastIndex)) {
405 bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
409 find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
410 bsr->VolParams[i].MediaType);
412 fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
413 fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
414 if (bsr->fileregex) {
415 fprintf(fd, "FileRegex=%s\n", bsr->fileregex);
417 if (get_storage_device(device, bsr->VolParams[i].Storage)) {
418 fprintf(fd, "Device=\"%s\"\n", device);
420 if (bsr->VolParams[i].Slot > 0) {
421 fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot);
423 fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
424 fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
425 fprintf(fd, "VolAddr=%s-%s\n", edit_uint64(bsr->VolParams[i].StartAddr, ed1),
426 edit_uint64(bsr->VolParams[i].EndAddr, ed2));
427 // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
428 // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
430 count = write_findex(bsr->fi, bsr->VolParams[i].FirstIndex,
431 bsr->VolParams[i].LastIndex, fd);
433 fprintf(fd, "Count=%u\n", count);
435 total_count += count;
436 /* If the same file is present on two tapes or in two files
437 * on a tape, it is a continuation, and should not be treated
438 * twice in the totals.
440 if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
444 LastIndex = bsr->VolParams[i].LastIndex;
451 void print_bsr(UAContext *ua, RESTORE_CTX &rx)
453 write_bsr(ua, rx, stdout);
460 * Add a FileIndex to the list of BootStrap records.
461 * Here we are only dealing with JobId's and the FileIndexes
462 * associated with those JobIds.
463 * We expect that JobId, FileIndex are sorted ascending.
465 void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
468 RBSR_FINDEX *fi, *lfi;
471 return; /* probably a dummy directory */
474 if (bsr->fi == NULL) { /* if no FI add one */
475 /* This is the first FileIndex item in the chain */
476 bsr->fi = new_findex();
478 bsr->fi->findex = findex;
479 bsr->fi->findex2 = findex;
482 /* Walk down list of bsrs until we find the JobId */
483 if (bsr->JobId != JobId) {
484 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
485 if (nbsr->JobId == JobId) {
491 if (!nbsr) { /* Must add new JobId */
492 /* Add new JobId at end of chain */
493 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
495 nbsr->next = new_bsr();
496 nbsr->next->JobId = JobId;
497 nbsr->next->fi = new_findex();
498 nbsr->next->fi->findex = findex;
499 nbsr->next->fi->findex2 = findex;
505 * At this point, bsr points to bsr containing this JobId,
506 * and we are sure that there is at least one fi record.
509 /* Check if this findex is smaller than first item */
510 if (findex < fi->findex) {
511 if ((findex+1) == fi->findex) {
512 fi->findex = findex; /* extend down */
515 fi = new_findex(); /* yes, insert before first item */
517 fi->findex2 = findex;
522 /* Walk down fi chain and find where to insert insert new FileIndex */
523 for ( ; fi; fi=fi->next) {
524 if (findex == (fi->findex2 + 1)) { /* extend up */
526 fi->findex2 = findex;
528 * If the following record contains one higher, merge its
529 * file index by extending it up.
531 if (fi->next && ((findex+1) == fi->next->findex)) {
533 fi->findex2 = nfi->findex2;
534 fi->next = nfi->next;
539 if (findex < fi->findex) { /* add before */
540 if ((findex+1) == fi->findex) {
548 /* Add to last place found */
551 fi->findex2 = findex;
552 fi->next = lfi->next;
558 * Add all possible FileIndexes to the list of BootStrap records.
559 * Here we are only dealing with JobId's and the FileIndexes
560 * associated with those JobIds.
562 void add_findex_all(RBSR *bsr, uint32_t JobId)
567 if (bsr->fi == NULL) { /* if no FI add one */
568 /* This is the first FileIndex item in the chain */
569 bsr->fi = new_findex();
572 bsr->fi->findex2 = INT32_MAX;
575 /* Walk down list of bsrs until we find the JobId */
576 if (bsr->JobId != JobId) {
577 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
578 if (nbsr->JobId == JobId) {
584 if (!nbsr) { /* Must add new JobId */
585 /* Add new JobId at end of chain */
586 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
588 nbsr->next = new_bsr();
589 nbsr->next->JobId = JobId;
590 nbsr->next->fi = new_findex();
591 nbsr->next->fi->findex = 1;
592 nbsr->next->fi->findex2 = INT32_MAX;
598 * At this point, bsr points to bsr containing this JobId,
599 * and we are sure that there is at least one fi record.
603 fi->findex2 = INT32_MAX;