3 * Bacula Director -- Bootstrap Record routines.
5 * BSR (bootstrap record) handling routines split from
6 * ua_restore.c July MMIII
8 * Kern Sibbald, July MMII
13 Bacula® - The Network Backup Solution
15 Copyright (C) 2002-2006 Free Software Foundation Europe e.V.
17 The main author of Bacula is Kern Sibbald, with contributions from
18 many others, a complete list can be found in the file AUTHORS.
19 This program is Free Software; you can redistribute it and/or
20 modify it under the terms of version two of the GNU General Public
21 License as published by the Free Software Foundation plus additions
22 that are listed in the file LICENSE.
24 This program is distributed in the hope that it will be useful, but
25 WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 General Public License for more details.
29 You should have received a copy of the GNU General Public License
30 along with this program; if not, write to the Free Software
31 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
34 Bacula® is a registered trademark of John Walker.
35 The licensor of Bacula is the Free Software Foundation Europe
36 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
37 Switzerland, email:ftf@fsfeurope.org.
43 /* Forward referenced functions */
44 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd);
45 void print_bsr(UAContext *ua, RBSR *bsr);
49 * Create new FileIndex entry for BSR
51 RBSR_FINDEX *new_findex()
53 RBSR_FINDEX *fi = (RBSR_FINDEX *)bmalloc(sizeof(RBSR_FINDEX));
54 memset(fi, 0, sizeof(RBSR_FINDEX));
58 /* Free all BSR FileIndex entries */
59 static void free_findex(RBSR_FINDEX *fi)
62 for ( ; fi; fi=next) {
69 * Get storage device name from Storage resource
71 static bool get_storage_device(char *device, char *storage)
74 if (storage[0] == 0) {
77 store = (STORE *)GetResWithName(R_STORAGE, storage);
81 DEVICE *dev = (DEVICE *)(store->device->first());
85 bstrncpy(device, dev->hdr.name, MAX_NAME_LENGTH);
90 * Our data structures were not designed completely
91 * correctly, so the file indexes cover the full
92 * range regardless of volume. The FirstIndex and LastIndex
93 * passed in here are for the current volume, so when
94 * writing out the fi, constrain them to those values.
96 * We are called here once for each JobMedia record
99 static uint32_t write_findex(RBSR_FINDEX *fi,
100 int32_t FirstIndex, int32_t LastIndex, FILE *fd)
103 for ( ; fi; fi=fi->next) {
104 int32_t findex, findex2;
105 if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
106 (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
107 (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
108 findex = fi->findex < FirstIndex ? FirstIndex : fi->findex;
109 findex2 = fi->findex2 > LastIndex ? LastIndex : fi->findex2;
110 if (findex == findex2) {
111 fprintf(fd, "FileIndex=%d\n", findex);
114 fprintf(fd, "FileIndex=%d-%d\n", findex, findex2);
115 count += findex2 - findex + 1;
123 * Find out if Volume defined with FirstIndex and LastIndex
124 * falls within the range of selected files in the bsr.
126 static bool is_volume_selected(RBSR_FINDEX *fi,
127 int32_t FirstIndex, int32_t LastIndex)
129 for ( ; fi; fi=fi->next) {
130 if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
131 (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
132 (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
141 static void print_findex(UAContext *ua, RBSR_FINDEX *fi)
143 ua->send_msg("fi=0x%lx\n", fi);
144 for ( ; fi; fi=fi->next) {
145 if (fi->findex == fi->findex2) {
146 ua->send_msg("FileIndex=%d\n", fi->findex);
147 Dmsg1(1000, "FileIndex=%d\n", fi->findex);
149 ua->send_msg("FileIndex=%d-%d\n", fi->findex, fi->findex2);
150 Dmsg2(1000, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
155 /* Create a new bootstrap record */
158 RBSR *bsr = (RBSR *)bmalloc(sizeof(RBSR));
159 memset(bsr, 0, sizeof(RBSR));
163 /* Free the entire BSR */
164 void free_bsr(RBSR *bsr)
167 for ( ; bsr; bsr=next) {
168 free_findex(bsr->fi);
169 if (bsr->VolParams) {
170 free(bsr->VolParams);
178 * Complete the BSR by filling in the VolumeName and
179 * VolSessionId and VolSessionTime using the JobId
181 bool complete_bsr(UAContext *ua, RBSR *bsr)
183 for ( ; bsr; bsr=bsr->next) {
185 memset(&jr, 0, sizeof(jr));
186 jr.JobId = bsr->JobId;
187 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
188 ua->error_msg(_("Unable to get Job record. ERR=%s\n"), db_strerror(ua->db));
191 bsr->VolSessionId = jr.VolSessionId;
192 bsr->VolSessionTime = jr.VolSessionTime;
193 if ((bsr->VolCount=db_get_job_volume_parameters(ua->jcr, ua->db, bsr->JobId,
194 &(bsr->VolParams))) == 0) {
195 ua->error_msg(_("Unable to get Job Volume Parameters. ERR=%s\n"), db_strerror(ua->db));
196 if (bsr->VolParams) {
197 free(bsr->VolParams);
198 bsr->VolParams = NULL;
206 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
207 static uint32_t uniq = 0;
209 static void make_unique_restore_filename(UAContext *ua, POOL_MEM &fname)
212 int i = find_arg_with_value(ua, "bootstrap");
214 Mmsg(fname, "%s", ua->argv[i]);
215 jcr->unlink_bsr = false;
220 Mmsg(fname, "%s/%s.restore.%u.bsr", working_directory, my_name, uniq);
221 jcr->unlink_bsr = true;
223 if (jcr->RestoreBootstrap) {
224 free(jcr->RestoreBootstrap);
226 jcr->RestoreBootstrap = bstrdup(fname.c_str());
230 * Write the bootstrap records to file
232 uint32_t write_bsr_file(UAContext *ua, RESTORE_CTX &rx)
235 POOL_MEM fname(PM_MESSAGE);
236 POOL_MEM volmsg(PM_MESSAGE);
241 char Device[MAX_NAME_LENGTH];
243 make_unique_restore_filename(ua, fname);
244 fd = fopen(fname.c_str(), "w+b");
247 ua->error_msg(_("Unable to create bootstrap file %s. ERR=%s\n"),
248 fname.c_str(), be.bstrerror());
251 /* Write them to file */
252 count = write_bsr(ua, rx, fd);
256 ua->info_msg(_("No files found to restore/migrate. No bootstrap file written.\n"));
260 ua->error_msg(_("Error writing bsr file.\n"));
266 ua->send_msg(_("Bootstrap records written to %s\n"), fname.c_str());
268 /* Tell the user what he will need to mount */
270 ua->send_msg(_("The job will require the following\n"
271 " Volume(s) Storage(s) SD Device(s)\n"
272 "===========================================================================\n"));
273 /* Create Unique list of Volumes using prompt list */
274 start_prompt(ua, "");
276 /* Ensure that the volumes are printed in JobId order */
277 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
278 for (RBSR *nbsr=rx.bsr; nbsr; nbsr=nbsr->next) {
279 if (JobId != nbsr->JobId) {
282 for (int i=0; i < nbsr->VolCount; i++) {
283 if (nbsr->VolParams[i].VolumeName[0]) {
284 if (!get_storage_device(Device, nbsr->VolParams[i].Storage)) {
287 Mmsg(volmsg, "%-25.25s %-25.25s %-25.25s",
288 nbsr->VolParams[i].VolumeName,
289 nbsr->VolParams[i].Storage, Device);
290 add_prompt(ua, volmsg.c_str());
296 /* Print Volumes in any order */
297 for (RBSR *nbsr=rx.bsr; nbsr; nbsr=nbsr->next) {
298 for (int i=0; i < nbsr->VolCount; i++) {
299 if (nbsr->VolParams[i].VolumeName[0]) {
300 if (!get_storage_device(Device, nbsr->VolParams[i].Storage)) {
303 Mmsg(volmsg, "%-25.25s %-25.25s %-25.25s",
304 nbsr->VolParams[i].VolumeName,
305 nbsr->VolParams[i].Storage, Device);
306 add_prompt(ua, volmsg.c_str());
311 for (int i=0; i < ua->num_prompts; i++) {
312 ua->send_msg(" %s\n", ua->prompt[i]);
315 if (ua->num_prompts == 0) {
316 ua->send_msg(_("No Volumes found to restore.\n"));
327 * Here we actually write out the details of the bsr file.
328 * Note, there is one bsr for each JobId, but the bsr may
329 * have multiple volumes, which have been entered in the
330 * order they were written.
331 * The bsrs must be written out in the order the JobIds
332 * are found in the jobid list.
334 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd)
337 uint32_t total_count = 0;
338 uint32_t LastIndex = 0;
342 char device[MAX_NAME_LENGTH];
344 if (*rx.JobIds == 0) {
345 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
347 * For a given volume, loop over all the JobMedia records.
348 * VolCount is the number of JobMedia records.
350 for (int i=0; i < bsr->VolCount; i++) {
351 if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
352 bsr->VolParams[i].LastIndex)) {
353 bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
357 find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
358 bsr->VolParams[i].MediaType);
360 fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
361 fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
362 if (get_storage_device(device, bsr->VolParams[i].Storage)) {
363 fprintf(fd, "Device=\"%s\"\n", device);
365 if (bsr->VolParams[i].Slot > 0) {
366 fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot);
368 fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
369 fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
370 if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) {
371 fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartFile);
373 fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
374 bsr->VolParams[i].EndFile);
376 if (bsr->VolParams[i].StartBlock == bsr->VolParams[i].EndBlock) {
377 fprintf(fd, "VolBlock=%u\n", bsr->VolParams[i].StartBlock);
379 fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
380 bsr->VolParams[i].EndBlock);
382 // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
383 // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
385 count = write_findex(bsr->fi, bsr->VolParams[i].FirstIndex,
386 bsr->VolParams[i].LastIndex, fd);
388 fprintf(fd, "Count=%u\n", count);
390 total_count += count;
391 /* If the same file is present on two tapes or in two files
392 * on a tape, it is a continuation, and should not be treated
393 * twice in the totals.
395 if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
399 LastIndex = bsr->VolParams[i].LastIndex;
404 for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
405 for (bsr=rx.bsr; bsr; bsr=bsr->next) {
406 if (JobId != bsr->JobId) {
410 * For a given volume, loop over all the JobMedia records.
411 * VolCount is the number of JobMedia records.
413 for (int i=0; i < bsr->VolCount; i++) {
414 if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
415 bsr->VolParams[i].LastIndex)) {
416 bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
420 find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
421 bsr->VolParams[i].MediaType);
423 fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
424 fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
425 if (get_storage_device(device, bsr->VolParams[i].Storage)) {
426 fprintf(fd, "Device=\"%s\"\n", device);
428 if (bsr->VolParams[i].Slot > 0) {
429 fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot);
431 fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
432 fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
433 if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) {
434 fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartFile);
436 fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
437 bsr->VolParams[i].EndFile);
439 if (bsr->VolParams[i].StartBlock == bsr->VolParams[i].EndBlock) {
440 fprintf(fd, "VolBlock=%u\n", bsr->VolParams[i].StartBlock);
442 fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
443 bsr->VolParams[i].EndBlock);
445 // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
446 // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
448 count = write_findex(bsr->fi, bsr->VolParams[i].FirstIndex,
449 bsr->VolParams[i].LastIndex, fd);
451 fprintf(fd, "Count=%u\n", count);
453 total_count += count;
454 /* If the same file is present on two tapes or in two files
455 * on a tape, it is a continuation, and should not be treated
456 * twice in the totals.
458 if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
462 LastIndex = bsr->VolParams[i].LastIndex;
469 void print_bsr(UAContext *ua, RBSR *bsr)
471 for ( ; bsr; bsr=bsr->next) {
472 for (int i=0; i < bsr->VolCount; i++) {
473 ua->send_msg("Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
474 ua->send_msg("MediaType\"%s\"\n", bsr->VolParams[i].MediaType);
475 ua->send_msg("VolSessionId=%u\n", bsr->VolSessionId);
476 ua->send_msg("VolSessionTime=%u\n", bsr->VolSessionTime);
477 ua->send_msg("VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
478 bsr->VolParams[i].EndFile);
479 ua->send_msg("VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
480 bsr->VolParams[i].EndBlock);
481 print_findex(ua, bsr->fi);
483 print_bsr(ua, bsr->next);
491 * Add a FileIndex to the list of BootStrap records.
492 * Here we are only dealing with JobId's and the FileIndexes
493 * associated with those JobIds.
495 void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
498 RBSR_FINDEX *fi, *lfi;
501 return; /* probably a dummy directory */
504 if (bsr->fi == NULL) { /* if no FI add one */
505 /* This is the first FileIndex item in the chain */
506 bsr->fi = new_findex();
508 bsr->fi->findex = findex;
509 bsr->fi->findex2 = findex;
512 /* Walk down list of bsrs until we find the JobId */
513 if (bsr->JobId != JobId) {
514 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
515 if (nbsr->JobId == JobId) {
521 if (!nbsr) { /* Must add new JobId */
522 /* Add new JobId at end of chain */
523 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
525 nbsr->next = new_bsr();
526 nbsr->next->JobId = JobId;
527 nbsr->next->fi = new_findex();
528 nbsr->next->fi->findex = findex;
529 nbsr->next->fi->findex2 = findex;
535 * At this point, bsr points to bsr containing this JobId,
536 * and we are sure that there is at least one fi record.
539 /* Check if this findex is smaller than first item */
540 if (findex < fi->findex) {
541 if ((findex+1) == fi->findex) {
542 fi->findex = findex; /* extend down */
545 fi = new_findex(); /* yes, insert before first item */
547 fi->findex2 = findex;
552 /* Walk down fi chain and find where to insert insert new FileIndex */
553 for ( ; fi; fi=fi->next) {
554 if (findex == (fi->findex2 + 1)) { /* extend up */
556 fi->findex2 = findex;
558 * If the following record contains one higher, merge its
559 * file index by extending it up.
561 if (fi->next && ((findex+1) == fi->next->findex)) {
563 fi->findex2 = nfi->findex2;
564 fi->next = nfi->next;
569 if (findex < fi->findex) { /* add before */
570 if ((findex+1) == fi->findex) {
578 /* Add to last place found */
581 fi->findex2 = findex;
582 fi->next = lfi->next;
588 * Add all possible FileIndexes to the list of BootStrap records.
589 * Here we are only dealing with JobId's and the FileIndexes
590 * associated with those JobIds.
592 void add_findex_all(RBSR *bsr, uint32_t JobId)
597 if (bsr->fi == NULL) { /* if no FI add one */
598 /* This is the first FileIndex item in the chain */
599 bsr->fi = new_findex();
602 bsr->fi->findex2 = INT32_MAX;
605 /* Walk down list of bsrs until we find the JobId */
606 if (bsr->JobId != JobId) {
607 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
608 if (nbsr->JobId == JobId) {
614 if (!nbsr) { /* Must add new JobId */
615 /* Add new JobId at end of chain */
616 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
618 nbsr->next = new_bsr();
619 nbsr->next->JobId = JobId;
620 nbsr->next->fi = new_findex();
621 nbsr->next->fi->findex = 1;
622 nbsr->next->fi->findex2 = INT32_MAX;
628 * At this point, bsr points to bsr containing this JobId,
629 * and we are sure that there is at least one fi record.
633 fi->findex2 = INT32_MAX;