2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 Bacula® is a registered trademark of Kern Sibbald.
18 * Bacula Director -- Bootstrap Record routines.
20 * BSR (bootstrap record) handling routines split from
21 * ua_restore.c July MMIII
23 * Kern Sibbald, July MMII
30 /* Forward referenced functions */
31 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd);
34 * Create new FileIndex entry for BSR
36 RBSR_FINDEX *new_findex()
38 RBSR_FINDEX *fi = (RBSR_FINDEX *)bmalloc(sizeof(RBSR_FINDEX));
39 memset(fi, 0, sizeof(RBSR_FINDEX));
43 /* Free all BSR FileIndex entries */
44 static void free_findex(RBSR_FINDEX *fi)
47 for ( ; fi; fi=next) {
54 * Get storage device name from Storage resource
56 static bool get_storage_device(char *device, char *storage)
59 if (storage[0] == 0) {
62 store = (STORE *)GetResWithName(R_STORAGE, storage);
66 DEVICE *dev = (DEVICE *)(store->device->first());
70 bstrncpy(device, dev->hdr.name, MAX_NAME_LENGTH);
75 * Our data structures were not designed completely
76 * correctly, so the file indexes cover the full
77 * range regardless of volume. The FirstIndex and LastIndex
78 * passed in here are for the current volume, so when
79 * writing out the fi, constrain them to those values.
81 * We are called here once for each JobMedia record
84 static uint32_t write_findex(RBSR_FINDEX *fi,
85 int32_t FirstIndex, int32_t LastIndex, FILE *fd)
88 for ( ; fi; fi=fi->next) {
89 int32_t findex, findex2;
90 if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
91 (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
92 (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
93 findex = fi->findex < FirstIndex ? FirstIndex : fi->findex;
94 findex2 = fi->findex2 > LastIndex ? LastIndex : fi->findex2;
95 if (findex == findex2) {
96 fprintf(fd, "FileIndex=%d\n", findex);
99 fprintf(fd, "FileIndex=%d-%d\n", findex, findex2);
100 count += findex2 - findex + 1;
108 * Find out if Volume defined with FirstIndex and LastIndex
109 * falls within the range of selected files in the bsr.
111 static bool is_volume_selected(RBSR_FINDEX *fi,
112 int32_t FirstIndex, int32_t LastIndex)
114 for ( ; fi; fi=fi->next) {
115 if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
116 (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
117 (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
125 /* Create a new bootstrap record */
128 RBSR *bsr = (RBSR *)bmalloc(sizeof(RBSR));
129 memset(bsr, 0, sizeof(RBSR));
133 /* Free the entire BSR */
134 void free_bsr(RBSR *bsr)
137 for ( ; bsr; bsr=next) {
138 free_findex(bsr->fi);
139 if (bsr->VolParams) {
140 free(bsr->VolParams);
142 if (bsr->fileregex) {
143 free(bsr->fileregex);
151 * Complete the BSR by filling in the VolumeName and
152 * VolSessionId and VolSessionTime using the JobId
154 bool complete_bsr(UAContext *ua, RBSR *bsr)
156 for ( ; bsr; bsr=bsr->next) {
158 memset(&jr, 0, sizeof(jr));
159 jr.JobId = bsr->JobId;
160 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
161 ua->error_msg(_("Unable to get Job record. ERR=%s\n"), db_strerror(ua->db));
164 bsr->VolSessionId = jr.VolSessionId;
165 bsr->VolSessionTime = jr.VolSessionTime;
166 if (jr.JobFiles == 0) { /* zero files is OK, not an error, but */
167 bsr->VolCount = 0; /* there are no volumes */
170 if ((bsr->VolCount=db_get_job_volume_parameters(ua->jcr, ua->db, bsr->JobId,
171 &(bsr->VolParams))) == 0) {
172 ua->error_msg(_("Unable to get Job Volume Parameters. ERR=%s\n"), db_strerror(ua->db));
173 if (bsr->VolParams) {
174 free(bsr->VolParams);
175 bsr->VolParams = NULL;
183 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
184 static uint32_t uniq = 0;
186 static void make_unique_restore_filename(UAContext *ua, POOL_MEM &fname)
189 int i = find_arg_with_value(ua, "bootstrap");
191 Mmsg(fname, "%s", ua->argv[i]);
192 jcr->unlink_bsr = false;
197 Mmsg(fname, "%s/%s.restore.%u.bsr", working_directory, my_name, uniq);
198 jcr->unlink_bsr = true;
200 if (jcr->RestoreBootstrap) {
201 free(jcr->RestoreBootstrap);
203 jcr->RestoreBootstrap = bstrdup(fname.c_str());
207 * Write the bootstrap records to file
209 uint32_t write_bsr_file(UAContext *ua, RESTORE_CTX &rx)
212 POOL_MEM fname(PM_MESSAGE);
216 make_unique_restore_filename(ua, fname);
217 fd = fopen(fname.c_str(), "w+b");
220 ua->error_msg(_("Unable to create bootstrap file %s. ERR=%s\n"),
221 fname.c_str(), be.bstrerror());
224 /* Write them to file */
225 count = write_bsr(ua, rx, fd);
229 ua->info_msg(_("No files found to read. No bootstrap file written.\n"));
233 ua->error_msg(_("Error writing bsr file.\n"));
238 ua->send_msg(_("Bootstrap records written to %s\n"), fname.c_str());
240 if (chk_dbglvl(10)) {
248 static void display_vol_info(UAContext *ua, RESTORE_CTX &rx, JobId_t JobId)
250 POOL_MEM volmsg(PM_MESSAGE);
251 char Device[MAX_NAME_LENGTH];
255 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
256 if (JobId && JobId != bsr->JobId) {
260 for (int i=0; i < bsr->VolCount; i++) {
261 if (bsr->VolParams[i].VolumeName[0]) {
262 if (!get_storage_device(Device, bsr->VolParams[i].Storage)) {
265 if (bsr->VolParams[i].InChanger && bsr->VolParams[i].Slot) {
270 Mmsg(volmsg, "%c%-25s %-25s %-25s",
271 online, bsr->VolParams[i].VolumeName,
272 bsr->VolParams[i].Storage, Device);
273 add_prompt(ua, volmsg.c_str());
279 void display_bsr_info(UAContext *ua, RESTORE_CTX &rx)
284 /* Tell the user what he will need to mount */
286 ua->send_msg(_("The Job will require the following (*=>InChanger):\n"
287 " Volume(s) Storage(s) SD Device(s)\n"
288 "===========================================================================\n"));
289 /* Create Unique list of Volumes using prompt list */
290 start_prompt(ua, "");
291 if (*rx.JobIds == 0) {
292 /* Print Volumes in any order */
293 display_vol_info(ua, rx, 0);
295 /* Ensure that the volumes are printed in JobId order */
296 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
297 display_vol_info(ua, rx, JobId);
300 for (int i=0; i < ua->num_prompts; i++) {
301 ua->send_msg(" %s\n", ua->prompt[i]);
303 if (ua->unique[i]) free(ua->unique[i]);
305 if (ua->num_prompts == 0) {
306 ua->send_msg(_("No Volumes found to restore.\n"));
308 ua->send_msg(_("\nVolumes marked with \"*\" are in the Autochanger.\n"));
317 * Write bsr data for a single bsr record
319 static uint32_t write_bsr_item(RBSR *bsr, UAContext *ua,
320 RESTORE_CTX &rx, FILE *fd, bool &first, uint32_t &LastIndex)
322 char ed1[50], ed2[50];
324 uint32_t total_count = 0;
325 char device[MAX_NAME_LENGTH];
328 * For a given volume, loop over all the JobMedia records.
329 * VolCount is the number of JobMedia records.
331 for (int i=0; i < bsr->VolCount; i++) {
332 if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
333 bsr->VolParams[i].LastIndex)) {
334 bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
338 find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
339 bsr->VolParams[i].MediaType);
341 fprintf(fd, "Storage=\"%s\"\n", bsr->VolParams[i].Storage);
342 fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
343 fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
344 if (bsr->fileregex) {
345 fprintf(fd, "FileRegex=%s\n", bsr->fileregex);
347 if (get_storage_device(device, bsr->VolParams[i].Storage)) {
348 fprintf(fd, "Device=\"%s\"\n", device);
350 if (bsr->VolParams[i].Slot > 0) {
351 fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot);
353 fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
354 fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
355 fprintf(fd, "VolAddr=%s-%s\n", edit_uint64(bsr->VolParams[i].StartAddr, ed1),
356 edit_uint64(bsr->VolParams[i].EndAddr, ed2));
357 // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
358 // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
360 count = write_findex(bsr->fi, bsr->VolParams[i].FirstIndex,
361 bsr->VolParams[i].LastIndex, fd);
363 fprintf(fd, "Count=%u\n", count);
365 total_count += count;
366 /* If the same file is present on two tapes or in two files
367 * on a tape, it is a continuation, and should not be treated
368 * twice in the totals.
370 if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
374 LastIndex = bsr->VolParams[i].LastIndex;
381 * Here we actually write out the details of the bsr file.
382 * Note, there is one bsr for each JobId, but the bsr may
383 * have multiple volumes, which have been entered in the
384 * order they were written.
385 * The bsrs must be written out in the order the JobIds
386 * are found in the jobid list.
388 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd)
391 uint32_t LastIndex = 0;
392 uint32_t total_count = 0;
396 if (*rx.JobIds == 0) {
397 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
398 total_count += write_bsr_item(bsr, ua, rx, fd, first, LastIndex);
402 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
403 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
404 if (JobId == bsr->JobId) {
405 total_count += write_bsr_item(bsr, ua, rx, fd, first, LastIndex);
412 void print_bsr(UAContext *ua, RESTORE_CTX &rx)
414 write_bsr(ua, rx, stdout);
421 * Add a FileIndex to the list of BootStrap records.
422 * Here we are only dealing with JobId's and the FileIndexes
423 * associated with those JobIds.
424 * We expect that JobId, FileIndex are sorted ascending.
426 void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
429 RBSR_FINDEX *fi, *lfi;
432 return; /* probably a dummy directory */
435 if (bsr->fi == NULL) { /* if no FI add one */
436 /* This is the first FileIndex item in the chain */
437 bsr->fi = new_findex();
439 bsr->fi->findex = findex;
440 bsr->fi->findex2 = findex;
443 /* Walk down list of bsrs until we find the JobId */
444 if (bsr->JobId != JobId) {
445 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
446 if (nbsr->JobId == JobId) {
452 if (!nbsr) { /* Must add new JobId */
453 /* Add new JobId at end of chain */
454 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
456 nbsr->next = new_bsr();
457 nbsr->next->JobId = JobId;
458 nbsr->next->fi = new_findex();
459 nbsr->next->fi->findex = findex;
460 nbsr->next->fi->findex2 = findex;
466 * At this point, bsr points to bsr containing this JobId,
467 * and we are sure that there is at least one fi record.
470 /* Check if this findex is smaller than first item */
471 if (findex < fi->findex) {
472 if ((findex+1) == fi->findex) {
473 fi->findex = findex; /* extend down */
476 fi = new_findex(); /* yes, insert before first item */
478 fi->findex2 = findex;
483 /* Walk down fi chain and find where to insert insert new FileIndex */
484 for ( ; fi; fi=fi->next) {
485 if (findex == (fi->findex2 + 1)) { /* extend up */
487 fi->findex2 = findex;
489 * If the following record contains one higher, merge its
490 * file index by extending it up.
492 if (fi->next && ((findex+1) == fi->next->findex)) {
494 fi->findex2 = nfi->findex2;
495 fi->next = nfi->next;
500 if (findex < fi->findex) { /* add before */
501 if ((findex+1) == fi->findex) {
509 /* Add to last place found */
512 fi->findex2 = findex;
513 fi->next = lfi->next;
519 * Add all possible FileIndexes to the list of BootStrap records.
520 * Here we are only dealing with JobId's and the FileIndexes
521 * associated with those JobIds.
523 void add_findex_all(RBSR *bsr, uint32_t JobId)
528 if (bsr->fi == NULL) { /* if no FI add one */
529 /* This is the first FileIndex item in the chain */
530 bsr->fi = new_findex();
533 bsr->fi->findex2 = INT32_MAX;
536 /* Walk down list of bsrs until we find the JobId */
537 if (bsr->JobId != JobId) {
538 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
539 if (nbsr->JobId == JobId) {
545 if (!nbsr) { /* Must add new JobId */
546 /* Add new JobId at end of chain */
547 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
550 nbsr->next = new_bsr();
551 nbsr->next->JobId = JobId;
553 /* If we use regexp to restore, set it for each jobid */
554 if (bsr->fileregex) {
555 nbsr->next->fileregex = bstrdup(bsr->fileregex);
558 nbsr->next->fi = new_findex();
559 nbsr->next->fi->findex = 1;
560 nbsr->next->fi->findex2 = INT32_MAX;
566 * At this point, bsr points to bsr containing this JobId,
567 * and we are sure that there is at least one fi record.
571 fi->findex2 = INT32_MAX;