2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2010 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
42 /* Forward referenced functions */
43 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd);
46 * Create new FileIndex entry for BSR
48 RBSR_FINDEX *new_findex()
50 RBSR_FINDEX *fi = (RBSR_FINDEX *)bmalloc(sizeof(RBSR_FINDEX));
51 memset(fi, 0, sizeof(RBSR_FINDEX));
55 /* Free all BSR FileIndex entries */
56 static void free_findex(RBSR_FINDEX *fi)
59 for ( ; fi; fi=next) {
66 * Get storage device name from Storage resource
68 static bool get_storage_device(char *device, char *storage)
71 if (storage[0] == 0) {
74 store = (STORE *)GetResWithName(R_STORAGE, storage);
78 DEVICE *dev = (DEVICE *)(store->device->first());
82 bstrncpy(device, dev->hdr.name, MAX_NAME_LENGTH);
87 * Our data structures were not designed completely
88 * correctly, so the file indexes cover the full
89 * range regardless of volume. The FirstIndex and LastIndex
90 * passed in here are for the current volume, so when
91 * writing out the fi, constrain them to those values.
93 * We are called here once for each JobMedia record
96 static uint32_t write_findex(RBSR_FINDEX *fi,
97 int32_t FirstIndex, int32_t LastIndex, FILE *fd)
100 for ( ; fi; fi=fi->next) {
101 int32_t findex, findex2;
102 if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
103 (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
104 (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
105 findex = fi->findex < FirstIndex ? FirstIndex : fi->findex;
106 findex2 = fi->findex2 > LastIndex ? LastIndex : fi->findex2;
107 if (findex == findex2) {
108 fprintf(fd, "FileIndex=%d\n", findex);
111 fprintf(fd, "FileIndex=%d-%d\n", findex, findex2);
112 count += findex2 - findex + 1;
120 * Find out if Volume defined with FirstIndex and LastIndex
121 * falls within the range of selected files in the bsr.
123 static bool is_volume_selected(RBSR_FINDEX *fi,
124 int32_t FirstIndex, int32_t LastIndex)
126 for ( ; fi; fi=fi->next) {
127 if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
128 (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
129 (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
137 /* Create a new bootstrap record */
140 RBSR *bsr = (RBSR *)bmalloc(sizeof(RBSR));
141 memset(bsr, 0, sizeof(RBSR));
145 /* Free the entire BSR */
146 void free_bsr(RBSR *bsr)
149 for ( ; bsr; bsr=next) {
150 free_findex(bsr->fi);
151 if (bsr->VolParams) {
152 free(bsr->VolParams);
154 if (bsr->fileregex) {
155 free(bsr->fileregex);
163 * Complete the BSR by filling in the VolumeName and
164 * VolSessionId and VolSessionTime using the JobId
166 bool complete_bsr(UAContext *ua, RBSR *bsr)
168 for ( ; bsr; bsr=bsr->next) {
170 memset(&jr, 0, sizeof(jr));
171 jr.JobId = bsr->JobId;
172 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
173 ua->error_msg(_("Unable to get Job record. ERR=%s\n"), db_strerror(ua->db));
176 bsr->VolSessionId = jr.VolSessionId;
177 bsr->VolSessionTime = jr.VolSessionTime;
178 if (jr.JobFiles == 0) { /* zero files is OK, not an error, but */
179 bsr->VolCount = 0; /* there are no volumes */
182 if ((bsr->VolCount=db_get_job_volume_parameters(ua->jcr, ua->db, bsr->JobId,
183 &(bsr->VolParams))) == 0) {
184 ua->error_msg(_("Unable to get Job Volume Parameters. ERR=%s\n"), db_strerror(ua->db));
185 if (bsr->VolParams) {
186 free(bsr->VolParams);
187 bsr->VolParams = NULL;
195 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
196 static uint32_t uniq = 0;
198 static void make_unique_restore_filename(UAContext *ua, POOL_MEM &fname)
201 int i = find_arg_with_value(ua, "bootstrap");
203 Mmsg(fname, "%s", ua->argv[i]);
204 jcr->unlink_bsr = false;
209 Mmsg(fname, "%s/%s.restore.%u.bsr", working_directory, my_name, uniq);
210 jcr->unlink_bsr = true;
212 if (jcr->RestoreBootstrap) {
213 free(jcr->RestoreBootstrap);
215 jcr->RestoreBootstrap = bstrdup(fname.c_str());
219 * Write the bootstrap records to file
221 uint32_t write_bsr_file(UAContext *ua, RESTORE_CTX &rx)
224 POOL_MEM fname(PM_MESSAGE);
228 make_unique_restore_filename(ua, fname);
229 fd = fopen(fname.c_str(), "w+b");
232 ua->error_msg(_("Unable to create bootstrap file %s. ERR=%s\n"),
233 fname.c_str(), be.bstrerror());
236 /* Write them to file */
237 count = write_bsr(ua, rx, fd);
241 ua->info_msg(_("No files found to read. No bootstrap file written.\n"));
245 ua->error_msg(_("Error writing bsr file.\n"));
250 ua->send_msg(_("Bootstrap records written to %s\n"), fname.c_str());
252 if (debug_level >= 10) {
260 static void display_vol_info(UAContext *ua, RESTORE_CTX &rx, JobId_t JobId)
262 POOL_MEM volmsg(PM_MESSAGE);
263 char Device[MAX_NAME_LENGTH];
267 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
268 if (JobId && JobId != bsr->JobId) {
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 if (bsr->VolParams[i].InChanger && bsr->VolParams[i].Slot) {
282 Mmsg(volmsg, "%c%-25s %-25s %-25s",
283 online, bsr->VolParams[i].VolumeName,
284 bsr->VolParams[i].Storage, Device);
285 add_prompt(ua, volmsg.c_str());
291 void display_bsr_info(UAContext *ua, RESTORE_CTX &rx)
296 /* Tell the user what he will need to mount */
298 ua->send_msg(_("The job will require the following\n"
299 " Volume(s) Storage(s) SD Device(s)\n"
300 "===========================================================================\n"));
301 /* Create Unique list of Volumes using prompt list */
302 start_prompt(ua, "");
303 if (*rx.JobIds == 0) {
304 /* Print Volumes in any order */
305 display_vol_info(ua, rx, 0);
307 /* Ensure that the volumes are printed in JobId order */
308 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
309 display_vol_info(ua, rx, JobId);
312 for (int i=0; i < ua->num_prompts; i++) {
313 ua->send_msg(" %s\n", ua->prompt[i]);
316 if (ua->num_prompts == 0) {
317 ua->send_msg(_("No Volumes found to restore.\n"));
319 ua->send_msg(_("\nVolumes marked with \"*\" are online.\n"));
328 * Write bsr data for a single bsr record
330 static uint32_t write_bsr_item(RBSR *bsr, UAContext *ua,
331 RESTORE_CTX &rx, FILE *fd, bool &first, uint32_t &LastIndex)
333 char ed1[50], ed2[50];
335 uint32_t total_count = 0;
336 char device[MAX_NAME_LENGTH];
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, "Storage=\"%s\"\n", bsr->VolParams[i].Storage);
353 fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
354 fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
355 if (bsr->fileregex) {
356 fprintf(fd, "FileRegex=%s\n", bsr->fileregex);
358 if (get_storage_device(device, bsr->VolParams[i].Storage)) {
359 fprintf(fd, "Device=\"%s\"\n", device);
361 if (bsr->VolParams[i].Slot > 0) {
362 fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot);
364 fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
365 fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
366 fprintf(fd, "VolAddr=%s-%s\n", edit_uint64(bsr->VolParams[i].StartAddr, ed1),
367 edit_uint64(bsr->VolParams[i].EndAddr, ed2));
368 // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
369 // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
371 count = write_findex(bsr->fi, bsr->VolParams[i].FirstIndex,
372 bsr->VolParams[i].LastIndex, fd);
374 fprintf(fd, "Count=%u\n", count);
376 total_count += count;
377 /* If the same file is present on two tapes or in two files
378 * on a tape, it is a continuation, and should not be treated
379 * twice in the totals.
381 if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
385 LastIndex = bsr->VolParams[i].LastIndex;
392 * Here we actually write out the details of the bsr file.
393 * Note, there is one bsr for each JobId, but the bsr may
394 * have multiple volumes, which have been entered in the
395 * order they were written.
396 * The bsrs must be written out in the order the JobIds
397 * are found in the jobid list.
399 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd)
402 uint32_t LastIndex = 0;
403 uint32_t total_count = 0;
407 if (*rx.JobIds == 0) {
408 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
409 total_count += write_bsr_item(bsr, ua, rx, fd, first, LastIndex);
413 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
414 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
415 if (JobId == bsr->JobId) {
416 total_count += write_bsr_item(bsr, ua, rx, fd, first, LastIndex);
423 void print_bsr(UAContext *ua, RESTORE_CTX &rx)
425 write_bsr(ua, rx, stdout);
432 * Add a FileIndex to the list of BootStrap records.
433 * Here we are only dealing with JobId's and the FileIndexes
434 * associated with those JobIds.
435 * We expect that JobId, FileIndex are sorted ascending.
437 void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
440 RBSR_FINDEX *fi, *lfi;
443 return; /* probably a dummy directory */
446 if (bsr->fi == NULL) { /* if no FI add one */
447 /* This is the first FileIndex item in the chain */
448 bsr->fi = new_findex();
450 bsr->fi->findex = findex;
451 bsr->fi->findex2 = findex;
454 /* Walk down list of bsrs until we find the JobId */
455 if (bsr->JobId != JobId) {
456 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
457 if (nbsr->JobId == JobId) {
463 if (!nbsr) { /* Must add new JobId */
464 /* Add new JobId at end of chain */
465 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
467 nbsr->next = new_bsr();
468 nbsr->next->JobId = JobId;
469 nbsr->next->fi = new_findex();
470 nbsr->next->fi->findex = findex;
471 nbsr->next->fi->findex2 = findex;
477 * At this point, bsr points to bsr containing this JobId,
478 * and we are sure that there is at least one fi record.
481 /* Check if this findex is smaller than first item */
482 if (findex < fi->findex) {
483 if ((findex+1) == fi->findex) {
484 fi->findex = findex; /* extend down */
487 fi = new_findex(); /* yes, insert before first item */
489 fi->findex2 = findex;
494 /* Walk down fi chain and find where to insert insert new FileIndex */
495 for ( ; fi; fi=fi->next) {
496 if (findex == (fi->findex2 + 1)) { /* extend up */
498 fi->findex2 = findex;
500 * If the following record contains one higher, merge its
501 * file index by extending it up.
503 if (fi->next && ((findex+1) == fi->next->findex)) {
505 fi->findex2 = nfi->findex2;
506 fi->next = nfi->next;
511 if (findex < fi->findex) { /* add before */
512 if ((findex+1) == fi->findex) {
520 /* Add to last place found */
523 fi->findex2 = findex;
524 fi->next = lfi->next;
530 * Add all possible FileIndexes to the list of BootStrap records.
531 * Here we are only dealing with JobId's and the FileIndexes
532 * associated with those JobIds.
534 void add_findex_all(RBSR *bsr, uint32_t JobId)
539 if (bsr->fi == NULL) { /* if no FI add one */
540 /* This is the first FileIndex item in the chain */
541 bsr->fi = new_findex();
544 bsr->fi->findex2 = INT32_MAX;
547 /* Walk down list of bsrs until we find the JobId */
548 if (bsr->JobId != JobId) {
549 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
550 if (nbsr->JobId == JobId) {
556 if (!nbsr) { /* Must add new JobId */
557 /* Add new JobId at end of chain */
558 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
561 nbsr->next = new_bsr();
562 nbsr->next->JobId = JobId;
564 /* If we use regexp to restore, set it for each jobid */
565 if (bsr->fileregex) {
566 nbsr->next->fileregex = bstrdup(bsr->fileregex);
569 nbsr->next->fi = new_findex();
570 nbsr->next->fi->findex = 1;
571 nbsr->next->fi->findex2 = INT32_MAX;
577 * At this point, bsr points to bsr containing this JobId,
578 * and we are sure that there is at least one fi record.
582 fi->findex2 = INT32_MAX;