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
14 Copyright (C) 2002-2005 Kern Sibbald
16 This program is free software; you can redistribute it and/or
17 modify it under the terms of the GNU General Public License
18 version 2 as amended with additional clauses defined in the
19 file LICENSE in the main source directory.
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 the file LICENSE for additional details.
31 /* Forward referenced functions */
32 static uint32_t write_bsr(UAContext *ua, RBSR *bsr, FILE *fd);
33 void print_bsr(UAContext *ua, RBSR *bsr);
37 * Create new FileIndex entry for BSR
39 RBSR_FINDEX *new_findex()
41 RBSR_FINDEX *fi = (RBSR_FINDEX *)bmalloc(sizeof(RBSR_FINDEX));
42 memset(fi, 0, sizeof(RBSR_FINDEX));
46 /* Free all BSR FileIndex entries */
47 static void free_findex(RBSR_FINDEX *fi)
50 for ( ; fi; fi=next) {
57 * Our data structures were not designed completely
58 * correctly, so the file indexes cover the full
59 * range regardless of volume. The FirstIndex and LastIndex
60 * passed in here are for the current volume, so when
61 * writing out the fi, constrain them to those values.
63 * We are called here once for each JobMedia record
66 static uint32_t write_findex(UAContext *ua, RBSR_FINDEX *fi,
67 int32_t FirstIndex, int32_t LastIndex, FILE *fd)
70 for ( ; fi; fi=fi->next) {
71 int32_t findex, findex2;
72 if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
73 (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
74 (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
75 findex = fi->findex < FirstIndex ? FirstIndex : fi->findex;
76 findex2 = fi->findex2 > LastIndex ? LastIndex : fi->findex2;
77 if (findex == findex2) {
78 fprintf(fd, "FileIndex=%d\n", findex);
81 fprintf(fd, "FileIndex=%d-%d\n", findex, findex2);
82 count += findex2 - findex + 1;
90 * Find out if Volume defined with FirstIndex and LastIndex
91 * falls within the range of selected files in the bsr.
93 static bool is_volume_selected(RBSR_FINDEX *fi,
94 int32_t FirstIndex, int32_t LastIndex)
96 for ( ; fi; fi=fi->next) {
97 if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
98 (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
99 (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
108 static void print_findex(UAContext *ua, RBSR_FINDEX *fi)
110 bsendmsg(ua, "fi=0x%lx\n", fi);
111 for ( ; fi; fi=fi->next) {
112 if (fi->findex == fi->findex2) {
113 bsendmsg(ua, "FileIndex=%d\n", fi->findex);
114 // Dmsg1(100, "FileIndex=%d\n", fi->findex);
116 bsendmsg(ua, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
117 // Dmsg2(100, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
122 /* Create a new bootstrap record */
125 RBSR *bsr = (RBSR *)bmalloc(sizeof(RBSR));
126 memset(bsr, 0, sizeof(RBSR));
130 /* Free the entire BSR */
131 void free_bsr(RBSR *bsr)
134 for ( ; bsr; bsr=next) {
135 free_findex(bsr->fi);
136 if (bsr->VolParams) {
137 free(bsr->VolParams);
145 * Complete the BSR by filling in the VolumeName and
146 * VolSessionId and VolSessionTime using the JobId
148 bool complete_bsr(UAContext *ua, RBSR *bsr)
150 for ( ; bsr; bsr=bsr->next) {
152 memset(&jr, 0, sizeof(jr));
153 jr.JobId = bsr->JobId;
154 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
155 bsendmsg(ua, _("Unable to get Job record. ERR=%s\n"), db_strerror(ua->db));
158 bsr->VolSessionId = jr.VolSessionId;
159 bsr->VolSessionTime = jr.VolSessionTime;
160 if ((bsr->VolCount=db_get_job_volume_parameters(ua->jcr, ua->db, bsr->JobId,
161 &(bsr->VolParams))) == 0) {
162 bsendmsg(ua, _("Unable to get Job Volume Parameters. ERR=%s\n"), db_strerror(ua->db));
163 if (bsr->VolParams) {
164 free(bsr->VolParams);
165 bsr->VolParams = NULL;
173 void make_unique_restore_filename(UAContext *ua, POOLMEM **fname)
176 int i = find_arg_with_value(ua, "bootstrap");
178 Mmsg(fname, "%s", ua->argv[i]);
179 jcr->unlink_bsr = false;
181 Mmsg(fname, "%s/%s.restore.%s.bsr", working_directory, my_name,
183 jcr->unlink_bsr = true;
188 * Write the bootstrap records to file
190 uint32_t write_bsr_file(UAContext *ua, RBSR *bsr)
193 POOLMEM *fname = get_pool_memory(PM_MESSAGE);
197 make_unique_restore_filename(ua, &fname);
198 fd = fopen(fname, "w+");
201 bsendmsg(ua, _("Unable to create bootstrap file %s. ERR=%s\n"),
202 fname, be.strerror());
205 /* Write them to file */
206 count = write_bsr(ua, bsr, fd);
210 bsendmsg(ua, _("Error writing bsr file.\n"));
216 bsendmsg(ua, _("Bootstrap records written to %s\n"), fname);
218 /* Tell the user what he will need to mount */
220 bsendmsg(ua, _("The job will require the following Volumes:\n"));
221 /* Create Unique list of Volumes using prompt list */
222 start_prompt(ua, "");
223 for (RBSR *nbsr=bsr; nbsr; nbsr=nbsr->next) {
224 for (int i=0; i < nbsr->VolCount; i++) {
225 if (nbsr->VolParams[i].VolumeName[0]) {
226 add_prompt(ua, nbsr->VolParams[i].VolumeName);
230 for (int i=0; i < ua->num_prompts; i++) {
231 bsendmsg(ua, " %s\n", ua->prompt[i]);
234 if (ua->num_prompts == 0) {
235 bsendmsg(ua, _("No Volumes found to restore.\n"));
242 free_pool_memory(fname);
246 static uint32_t write_bsr(UAContext *ua, RBSR *bsr, FILE *fd)
249 uint32_t total_count = 0;
250 uint32_t LastIndex = 0;
252 for ( ; bsr; bsr=bsr->next) {
254 * For a given volume, loop over all the JobMedia records.
255 * VolCount is the number of JobMedia records.
257 for (int i=0; i < bsr->VolCount; i++) {
258 if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
259 bsr->VolParams[i].LastIndex)) {
260 bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
263 fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
264 fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
265 fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
266 fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
267 if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) {
268 fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartFile);
270 fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
271 bsr->VolParams[i].EndFile);
273 if (bsr->VolParams[i].StartBlock == bsr->VolParams[i].EndBlock) {
274 fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartBlock);
276 fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
277 bsr->VolParams[i].EndBlock);
279 // Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
280 // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
282 count = write_findex(ua, bsr->fi, bsr->VolParams[i].FirstIndex,
283 bsr->VolParams[i].LastIndex, fd);
285 fprintf(fd, "Count=%u\n", count);
287 total_count += count;
288 /* If the same file is present on two tapes or in two files
289 * on a tape, it is a continuation, and should not be treated
290 * twice in the totals.
292 if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
296 LastIndex = bsr->VolParams[i].LastIndex;
302 void print_bsr(UAContext *ua, RBSR *bsr)
304 for ( ; bsr; bsr=bsr->next) {
305 for (int i=0; i < bsr->VolCount; i++) {
306 bsendmsg(ua, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
307 bsendmsg(ua, "MediaType\"%s\"\n", bsr->VolParams[i].MediaType);
308 bsendmsg(ua, "VolSessionId=%u\n", bsr->VolSessionId);
309 bsendmsg(ua, "VolSessionTime=%u\n", bsr->VolSessionTime);
310 bsendmsg(ua, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
311 bsr->VolParams[i].EndFile);
312 bsendmsg(ua, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
313 bsr->VolParams[i].EndBlock);
314 print_findex(ua, bsr->fi);
316 print_bsr(ua, bsr->next);
324 * Add a FileIndex to the list of BootStrap records.
325 * Here we are only dealing with JobId's and the FileIndexes
326 * associated with those JobIds.
328 void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
331 RBSR_FINDEX *fi, *lfi;
334 return; /* probably a dummy directory */
337 if (bsr->fi == NULL) { /* if no FI add one */
338 /* This is the first FileIndex item in the chain */
339 bsr->fi = new_findex();
341 bsr->fi->findex = findex;
342 bsr->fi->findex2 = findex;
345 /* Walk down list of bsrs until we find the JobId */
346 if (bsr->JobId != JobId) {
347 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
348 if (nbsr->JobId == JobId) {
354 if (!nbsr) { /* Must add new JobId */
355 /* Add new JobId at end of chain */
356 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
358 nbsr->next = new_bsr();
359 nbsr->next->JobId = JobId;
360 nbsr->next->fi = new_findex();
361 nbsr->next->fi->findex = findex;
362 nbsr->next->fi->findex2 = findex;
368 * At this point, bsr points to bsr containing this JobId,
369 * and we are sure that there is at least one fi record.
372 /* Check if this findex is smaller than first item */
373 if (findex < fi->findex) {
374 if ((findex+1) == fi->findex) {
375 fi->findex = findex; /* extend down */
378 fi = new_findex(); /* yes, insert before first item */
380 fi->findex2 = findex;
385 /* Walk down fi chain and find where to insert insert new FileIndex */
386 for ( ; fi; fi=fi->next) {
387 if (findex == (fi->findex2 + 1)) { /* extend up */
389 fi->findex2 = findex;
391 * If the following record contains one higher, merge its
392 * file index by extending it up.
394 if (fi->next && ((findex+1) == fi->next->findex)) {
396 fi->findex2 = nfi->findex2;
397 fi->next = nfi->next;
402 if (findex < fi->findex) { /* add before */
403 if ((findex+1) == fi->findex) {
411 /* Add to last place found */
414 fi->findex2 = findex;
415 fi->next = lfi->next;
421 * Add all possible FileIndexes to the list of BootStrap records.
422 * Here we are only dealing with JobId's and the FileIndexes
423 * associated with those JobIds.
425 void add_findex_all(RBSR *bsr, uint32_t JobId)
430 if (bsr->fi == NULL) { /* if no FI add one */
431 /* This is the first FileIndex item in the chain */
432 bsr->fi = new_findex();
435 bsr->fi->findex2 = INT32_MAX;
438 /* Walk down list of bsrs until we find the JobId */
439 if (bsr->JobId != JobId) {
440 for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
441 if (nbsr->JobId == JobId) {
447 if (!nbsr) { /* Must add new JobId */
448 /* Add new JobId at end of chain */
449 for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
451 nbsr->next = new_bsr();
452 nbsr->next->JobId = JobId;
453 nbsr->next->fi = new_findex();
454 nbsr->next->fi->findex = 1;
455 nbsr->next->fi->findex2 = INT32_MAX;
461 * At this point, bsr points to bsr containing this JobId,
462 * and we are sure that there is at least one fi record.
466 fi->findex2 = INT32_MAX;