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 (jr.JobFiles == 0) { /* zero files is OK, not an error, but */
180 bsr->VolCount = 0; /* there are no volumes */
183 if ((bsr->VolCount=db_get_job_volume_parameters(ua->jcr, ua->db, bsr->JobId,
184 &(bsr->VolParams))) == 0) {
185 ua->error_msg(_("Unable to get Job Volume Parameters. ERR=%s\n"), db_strerror(ua->db));
186 if (bsr->VolParams) {
187 free(bsr->VolParams);
188 bsr->VolParams = NULL;
196 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
197 static uint32_t uniq = 0;
199 static void make_unique_restore_filename(UAContext *ua, POOL_MEM &fname)
202 int i = find_arg_with_value(ua, "bootstrap");
204 Mmsg(fname, "%s", ua->argv[i]);
205 jcr->unlink_bsr = false;
210 Mmsg(fname, "%s/%s.restore.%u.bsr", working_directory, my_name, uniq);
211 jcr->unlink_bsr = true;
213 if (jcr->RestoreBootstrap) {
214 free(jcr->RestoreBootstrap);
216 jcr->RestoreBootstrap = bstrdup(fname.c_str());
220 * Write the bootstrap records to file
222 uint32_t write_bsr_file(UAContext *ua, RESTORE_CTX &rx)
225 POOL_MEM fname(PM_MESSAGE);
229 make_unique_restore_filename(ua, fname);
230 fd = fopen(fname.c_str(), "w+b");
233 ua->error_msg(_("Unable to create bootstrap file %s. ERR=%s\n"),
234 fname.c_str(), be.bstrerror());
237 /* Write them to file */
238 count = write_bsr(ua, rx, fd);
242 ua->info_msg(_("No files found to read. No bootstrap file written.\n"));
246 ua->error_msg(_("Error writing bsr file.\n"));
251 ua->send_msg(_("Bootstrap records written to %s\n"), fname.c_str());
253 if (debug_level >= 10) {
261 static void display_vol_info(UAContext *ua, RESTORE_CTX &rx, JobId_t JobId)
263 POOL_MEM volmsg(PM_MESSAGE);
264 char Device[MAX_NAME_LENGTH];
268 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
269 if (JobId && JobId != bsr->JobId) {
273 for (int i=0; i < bsr->VolCount; i++) {
274 if (bsr->VolParams[i].VolumeName[0]) {
275 if (!get_storage_device(Device, bsr->VolParams[i].Storage)) {
278 if (bsr->VolParams[i].InChanger && bsr->VolParams[i].Slot) {
283 Mmsg(volmsg, "%c%-25.25s %-25.25s %-25.25s",
284 online, bsr->VolParams[i].VolumeName,
285 bsr->VolParams[i].Storage,
287 add_prompt(ua, volmsg.c_str());
293 void display_bsr_info(UAContext *ua, RESTORE_CTX &rx)
298 /* Tell the user what he will need to mount */
300 ua->send_msg(_("The job will require the following\n"
301 " Volume(s) Storage(s) SD Device(s)\n"
302 "===========================================================================\n"));
303 /* Create Unique list of Volumes using prompt list */
304 start_prompt(ua, "");
305 if (*rx.JobIds == 0) {
306 /* Print Volumes in any order */
307 display_vol_info(ua, rx, 0);
309 /* Ensure that the volumes are printed in JobId order */
310 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
311 display_vol_info(ua, rx, JobId);
314 for (int i=0; i < ua->num_prompts; i++) {
315 ua->send_msg(" %s\n", ua->prompt[i]);
318 if (ua->num_prompts == 0) {
319 ua->send_msg(_("No Volumes found to restore.\n"));
321 ua->send_msg(_("\nVolumes marked with \"*\" are online.\n"));
330 * Write bsr data for a single bsr record
332 static uint32_t write_bsr_item(RBSR *bsr, UAContext *ua,
333 RESTORE_CTX &rx, FILE *fd, bool &first, uint32_t &LastIndex)
335 char ed1[50], ed2[50];
337 uint32_t total_count = 0;
338 char device[MAX_NAME_LENGTH];
341 * For a given volume, loop over all the JobMedia records.
342 * VolCount is the number of JobMedia records.
344 for (int i=0; i < bsr->VolCount; i++) {
345 if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
346 bsr->VolParams[i].LastIndex)) {
347 bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
351 find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
352 bsr->VolParams[i].MediaType);
354 fprintf(fd, "Storage=\"%s\"\n", bsr->VolParams[i].Storage);
355 fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
356 fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
357 if (bsr->fileregex) {
358 fprintf(fd, "FileRegex=%s\n", bsr->fileregex);
360 if (get_storage_device(device, bsr->VolParams[i].Storage)) {
361 fprintf(fd, "Device=\"%s\"\n", device);
363 if (bsr->VolParams[i].Slot > 0) {
364 fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot);
366 fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
367 fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
368 fprintf(fd, "VolAddr=%s-%s\n", edit_uint64(bsr->VolParams[i].StartAddr, ed1),
369 edit_uint64(bsr->VolParams[i].EndAddr, ed2));
370 // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
371 // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
373 count = write_findex(bsr->fi, bsr->VolParams[i].FirstIndex,
374 bsr->VolParams[i].LastIndex, fd);
376 fprintf(fd, "Count=%u\n", count);
378 total_count += count;
379 /* If the same file is present on two tapes or in two files
380 * on a tape, it is a continuation, and should not be treated
381 * twice in the totals.
383 if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
387 LastIndex = bsr->VolParams[i].LastIndex;
394 * Here we actually write out the details of the bsr file.
395 * Note, there is one bsr for each JobId, but the bsr may
396 * have multiple volumes, which have been entered in the
397 * order they were written.
398 * The bsrs must be written out in the order the JobIds
399 * are found in the jobid list.
401 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd)
404 uint32_t LastIndex = 0;
405 uint32_t total_count = 0;
409 if (*rx.JobIds == 0) {
410 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
411 total_count += write_bsr_item(bsr, ua, rx, fd, first, LastIndex);
415 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
416 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
417 if (JobId == bsr->JobId) {
418 total_count += write_bsr_item(bsr, ua, rx, fd, first, LastIndex);
425 void print_bsr(UAContext *ua, RESTORE_CTX &rx)
427 write_bsr(ua, rx, stdout);
434 * Add a FileIndex to the list of BootStrap records.
435 * Here we are only dealing with JobId's and the FileIndexes
436 * associated with those JobIds.
437 * We expect that JobId, FileIndex are sorted ascending.
439 void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
442 RBSR_FINDEX *fi, *lfi;
445 return; /* probably a dummy directory */
448 if (bsr->fi == NULL) { /* if no FI add one */
449 /* This is the first FileIndex item in the chain */
450 bsr->fi = new_findex();
452 bsr->fi->findex = findex;
453 bsr->fi->findex2 = findex;
456 /* Walk down list of bsrs until we find the JobId */
457 if (bsr->JobId != JobId) {
458 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
459 if (nbsr->JobId == JobId) {
465 if (!nbsr) { /* Must add new JobId */
466 /* Add new JobId at end of chain */
467 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
469 nbsr->next = new_bsr();
470 nbsr->next->JobId = JobId;
471 nbsr->next->fi = new_findex();
472 nbsr->next->fi->findex = findex;
473 nbsr->next->fi->findex2 = findex;
479 * At this point, bsr points to bsr containing this JobId,
480 * and we are sure that there is at least one fi record.
483 /* Check if this findex is smaller than first item */
484 if (findex < fi->findex) {
485 if ((findex+1) == fi->findex) {
486 fi->findex = findex; /* extend down */
489 fi = new_findex(); /* yes, insert before first item */
491 fi->findex2 = findex;
496 /* Walk down fi chain and find where to insert insert new FileIndex */
497 for ( ; fi; fi=fi->next) {
498 if (findex == (fi->findex2 + 1)) { /* extend up */
500 fi->findex2 = findex;
502 * If the following record contains one higher, merge its
503 * file index by extending it up.
505 if (fi->next && ((findex+1) == fi->next->findex)) {
507 fi->findex2 = nfi->findex2;
508 fi->next = nfi->next;
513 if (findex < fi->findex) { /* add before */
514 if ((findex+1) == fi->findex) {
522 /* Add to last place found */
525 fi->findex2 = findex;
526 fi->next = lfi->next;
532 * Add all possible FileIndexes to the list of BootStrap records.
533 * Here we are only dealing with JobId's and the FileIndexes
534 * associated with those JobIds.
536 void add_findex_all(RBSR *bsr, uint32_t JobId)
541 if (bsr->fi == NULL) { /* if no FI add one */
542 /* This is the first FileIndex item in the chain */
543 bsr->fi = new_findex();
546 bsr->fi->findex2 = INT32_MAX;
549 /* Walk down list of bsrs until we find the JobId */
550 if (bsr->JobId != JobId) {
551 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
552 if (nbsr->JobId == JobId) {
558 if (!nbsr) { /* Must add new JobId */
559 /* Add new JobId at end of chain */
560 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
562 nbsr->next = new_bsr();
563 nbsr->next->JobId = JobId;
564 nbsr->next->fi = new_findex();
565 nbsr->next->fi->findex = 1;
566 nbsr->next->fi->findex2 = INT32_MAX;
572 * At this point, bsr points to bsr containing this JobId,
573 * and we are sure that there is at least one fi record.
577 fi->findex2 = INT32_MAX;