]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/bsr.c
Remove more recursion in src/dird/bsr.c as pointed out
[bacula/bacula] / bacula / src / dird / bsr.c
1 /*
2  *
3  *   Bacula Director -- Bootstrap Record routines.
4  *
5  *      BSR (bootstrap record) handling routines split from
6  *        ua_restore.c July MMIII
7  *
8  *     Kern Sibbald, July MMII
9  *
10  *   Version $Id$
11  */
12
13 /*
14    Copyright (C) 2002-2005 Kern Sibbald
15
16    This program is free software; you can redistribute it and/or
17    modify it under the terms of the GNU General Public License as
18    published by the Free Software Foundation; either version 2 of
19    the License, or (at your option) any later version.
20
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 GNU
24    General Public License for more details.
25
26    You should have received a copy of the GNU General Public
27    License along with this program; if not, write to the Free
28    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
29    MA 02111-1307, USA.
30
31  */
32
33 #include "bacula.h"
34 #include "dird.h"
35
36 /* Forward referenced functions */
37 static uint32_t write_bsr(UAContext *ua, RBSR *bsr, FILE *fd);
38 void print_bsr(UAContext *ua, RBSR *bsr);
39
40
41 /*
42  * Create new FileIndex entry for BSR
43  */
44 RBSR_FINDEX *new_findex()
45 {
46    RBSR_FINDEX *fi = (RBSR_FINDEX *)bmalloc(sizeof(RBSR_FINDEX));
47    memset(fi, 0, sizeof(RBSR_FINDEX));
48    return fi;
49 }
50
51 /* Free all BSR FileIndex entries */
52 static void free_findex(RBSR_FINDEX *fi)
53 {
54    RBSR_FINDEX *next;
55    for ( ; fi; fi=next) {
56       next = fi->next;
57       free(fi);
58    }
59 }
60
61 /*
62  * Our data structures were not designed completely
63  *  correctly, so the file indexes cover the full
64  *  range regardless of volume. The FirstIndex and LastIndex
65  *  passed in here are for the current volume, so when
66  *  writing out the fi, constrain them to those values.
67  *
68  * We are called here once for each JobMedia record
69  *  for each Volume.
70  */
71 static uint32_t write_findex(UAContext *ua, RBSR_FINDEX *fi,
72               int32_t FirstIndex, int32_t LastIndex, FILE *fd)
73 {
74    uint32_t count = 0;
75    for ( ; fi; fi=fi->next) {
76       int32_t findex, findex2;
77       if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
78           (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
79           (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
80          findex = fi->findex < FirstIndex ? FirstIndex : fi->findex;
81          findex2 = fi->findex2 > LastIndex ? LastIndex : fi->findex2;
82          if (findex == findex2) {
83             fprintf(fd, "FileIndex=%d\n", findex);
84             count++;
85          } else {
86             fprintf(fd, "FileIndex=%d-%d\n", findex, findex2);
87             count += findex2 - findex + 1;
88          }
89       }
90    }
91    return count;
92 }
93
94 /*
95  * Find out if Volume defined with FirstIndex and LastIndex
96  *   falls within the range of selected files in the bsr.
97  */
98 static bool is_volume_selected(RBSR_FINDEX *fi,
99               int32_t FirstIndex, int32_t LastIndex)
100 {
101    for ( ; fi; fi=fi->next) {
102       if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
103           (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
104           (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
105          return true;
106       }
107    }
108    return false;
109 }
110
111
112
113 static void print_findex(UAContext *ua, RBSR_FINDEX *fi)
114 {
115    bsendmsg(ua, "fi=0x%lx\n", fi);
116    for ( ; fi; fi=fi->next) {
117       if (fi->findex == fi->findex2) {
118          bsendmsg(ua, "FileIndex=%d\n", fi->findex);
119 //       Dmsg1(100, "FileIndex=%d\n", fi->findex);
120       } else {
121          bsendmsg(ua, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
122 //       Dmsg2(100, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
123       }
124    }
125 }
126
127 /* Create a new bootstrap record */
128 RBSR *new_bsr()
129 {
130    RBSR *bsr = (RBSR *)bmalloc(sizeof(RBSR));
131    memset(bsr, 0, sizeof(RBSR));
132    return bsr;
133 }
134
135 /* Free the entire BSR */
136 void free_bsr(RBSR *bsr)
137 {
138    RBSR *next;
139    for ( ; bsr; bsr=next) {
140       free_findex(bsr->fi);
141       if (bsr->VolParams) {
142          free(bsr->VolParams);
143       }
144       next = bsr->next;
145       free(bsr);
146    }
147 }
148
149 /*
150  * Complete the BSR by filling in the VolumeName and
151  *  VolSessionId and VolSessionTime using the JobId
152  */
153 bool complete_bsr(UAContext *ua, RBSR *bsr)
154 {
155    for ( ; bsr; bsr=bsr->next) {
156       JOB_DBR jr;
157       memset(&jr, 0, sizeof(jr));
158       jr.JobId = bsr->JobId;
159       if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
160          bsendmsg(ua, _("Unable to get Job record. ERR=%s\n"), db_strerror(ua->db));
161          return false;
162       }
163       bsr->VolSessionId = jr.VolSessionId;
164       bsr->VolSessionTime = jr.VolSessionTime;
165       if ((bsr->VolCount=db_get_job_volume_parameters(ua->jcr, ua->db, bsr->JobId,
166            &(bsr->VolParams))) == 0) {
167          bsendmsg(ua, _("Unable to get Job Volume Parameters. ERR=%s\n"), db_strerror(ua->db));
168          if (bsr->VolParams) {
169             free(bsr->VolParams);
170             bsr->VolParams = NULL;
171          }
172          return false;
173       }
174    }
175    return true;
176 }
177
178 /*
179  * Write the bootstrap records to file
180  */
181 uint32_t write_bsr_file(UAContext *ua, RBSR *bsr)
182 {
183    FILE *fd;
184    POOLMEM *fname = get_pool_memory(PM_MESSAGE);
185    uint32_t count = 0;;
186    bool err;
187
188    Mmsg(fname, "%s/restore.bsr", working_directory);
189    fd = fopen(fname, "w+");
190    if (!fd) {
191       berrno be;
192       bsendmsg(ua, _("Unable to create bootstrap file %s. ERR=%s\n"),
193          fname, be.strerror());
194       goto bail_out;
195    }
196    /* Write them to file */
197    count = write_bsr(ua, bsr, fd);
198    err = ferror(fd);
199    fclose(fd);
200    if (err) {
201       bsendmsg(ua, _("Error writing bsr file.\n"));
202       count = 0;
203       goto bail_out;
204    }
205
206
207    bsendmsg(ua, _("Bootstrap records written to %s\n"), fname);
208
209    /* Tell the user what he will need to mount */
210    bsendmsg(ua, "\n");
211    bsendmsg(ua, _("The job will require the following Volumes:\n"));
212    /* Create Unique list of Volumes using prompt list */
213    start_prompt(ua, "");
214    for (RBSR *nbsr=bsr; nbsr; nbsr=nbsr->next) {
215       for (int i=0; i < nbsr->VolCount; i++) {
216          if (nbsr->VolParams[i].VolumeName[0]) {
217             add_prompt(ua, nbsr->VolParams[i].VolumeName);
218          }
219       }
220    }
221    for (int i=0; i < ua->num_prompts; i++) {
222       bsendmsg(ua, "   %s\n", ua->prompt[i]);
223       free(ua->prompt[i]);
224    }
225    if (ua->num_prompts == 0) {
226       bsendmsg(ua, _("No Volumes found to restore.\n"));
227       count = 0;
228    }
229    ua->num_prompts = 0;
230    bsendmsg(ua, "\n");
231
232 bail_out:
233    free_pool_memory(fname);
234    return count;
235 }
236
237 static uint32_t write_bsr(UAContext *ua, RBSR *bsr, FILE *fd)
238 {
239    uint32_t count = 0;
240    uint32_t total_count = 0;
241    uint32_t LastIndex = 0;
242    bool first = true;
243    for ( ; bsr; bsr=bsr->next) {
244       /*
245        * For a given volume, loop over all the JobMedia records.
246        *   VolCount is the number of JobMedia records.
247        */
248       for (int i=0; i < bsr->VolCount; i++) {
249          if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
250               bsr->VolParams[i].LastIndex)) {
251             bsr->VolParams[i].VolumeName[0] = 0;  /* zap VolumeName */
252             continue;
253          }
254          fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
255          fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
256          fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
257          fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
258          if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) {
259             fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartFile);
260          } else {
261             fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
262                     bsr->VolParams[i].EndFile);
263          }
264          if (bsr->VolParams[i].StartBlock == bsr->VolParams[i].EndBlock) {
265             fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartBlock);
266          } else {
267             fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
268                     bsr->VolParams[i].EndBlock);
269          }
270 //       Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
271 //          bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
272
273          count = write_findex(ua, bsr->fi, bsr->VolParams[i].FirstIndex,
274                               bsr->VolParams[i].LastIndex, fd);
275          if (count) {
276             fprintf(fd, "Count=%u\n", count);
277          }
278          total_count += count;
279          /* If the same file is present on two tapes or in two files
280           *   on a tape, it is a continuation, and should not be treated
281           *   twice in the totals.
282           */
283          if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
284             total_count--;
285          }
286          first = false;
287          LastIndex = bsr->VolParams[i].LastIndex;
288       }
289    }
290    return total_count;
291 }
292
293 void print_bsr(UAContext *ua, RBSR *bsr)
294 {
295    for ( ; bsr; bsr=bsr->next) {
296       for (int i=0; i < bsr->VolCount; i++) {
297          bsendmsg(ua, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
298          bsendmsg(ua, "MediaType\"%s\"\n", bsr->VolParams[i].MediaType);
299          bsendmsg(ua, "VolSessionId=%u\n", bsr->VolSessionId);
300          bsendmsg(ua, "VolSessionTime=%u\n", bsr->VolSessionTime);
301          bsendmsg(ua, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
302                   bsr->VolParams[i].EndFile);
303          bsendmsg(ua, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
304                   bsr->VolParams[i].EndBlock);
305          print_findex(ua, bsr->fi);
306       }
307       print_bsr(ua, bsr->next);
308    }
309 }
310
311
312
313
314 /*
315  * Add a FileIndex to the list of BootStrap records.
316  *  Here we are only dealing with JobId's and the FileIndexes
317  *  associated with those JobIds.
318  */
319 void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
320 {
321    RBSR *nbsr;
322    RBSR_FINDEX *fi, *lfi;
323
324    if (findex == 0) {
325       return;                         /* probably a dummy directory */
326    }
327
328    if (bsr->fi == NULL) {             /* if no FI add one */
329       /* This is the first FileIndex item in the chain */
330       bsr->fi = new_findex();
331       bsr->JobId = JobId;
332       bsr->fi->findex = findex;
333       bsr->fi->findex2 = findex;
334       return;
335    }
336    /* Walk down list of bsrs until we find the JobId */
337    if (bsr->JobId != JobId) {
338       for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
339          if (nbsr->JobId == JobId) {
340             bsr = nbsr;
341             break;
342          }
343       }
344
345       if (!nbsr) {                    /* Must add new JobId */
346          /* Add new JobId at end of chain */
347          for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
348             {  }
349          nbsr->next = new_bsr();
350          nbsr->next->JobId = JobId;
351          nbsr->next->fi = new_findex();
352          nbsr->next->fi->findex = findex;
353          nbsr->next->fi->findex2 = findex;
354          return;
355       }
356    }
357
358    /*
359     * At this point, bsr points to bsr containing this JobId,
360     *  and we are sure that there is at least one fi record.
361     */
362    lfi = fi = bsr->fi;
363    /* Check if this findex is smaller than first item */
364    if (findex < fi->findex) {
365       if ((findex+1) == fi->findex) {
366          fi->findex = findex;         /* extend down */
367          return;
368       }
369       fi = new_findex();              /* yes, insert before first item */
370       fi->findex = findex;
371       fi->findex2 = findex;
372       fi->next = lfi;
373       bsr->fi = fi;
374       return;
375    }
376    /* Walk down fi chain and find where to insert insert new FileIndex */
377    for ( ; fi; fi=fi->next) {
378       if (findex == (fi->findex2 + 1)) {  /* extend up */
379          RBSR_FINDEX *nfi;
380          fi->findex2 = findex;
381          /*
382           * If the following record contains one higher, merge its
383           *   file index by extending it up.
384           */
385          if (fi->next && ((findex+1) == fi->next->findex)) {
386             nfi = fi->next;
387             fi->findex2 = nfi->findex2;
388             fi->next = nfi->next;
389             free(nfi);
390          }
391          return;
392       }
393       if (findex < fi->findex) {      /* add before */
394          if ((findex+1) == fi->findex) {
395             fi->findex = findex;
396             return;
397          }
398          break;
399       }
400       lfi = fi;
401    }
402    /* Add to last place found */
403    fi = new_findex();
404    fi->findex = findex;
405    fi->findex2 = findex;
406    fi->next = lfi->next;
407    lfi->next = fi;
408    return;
409 }
410
411 /*
412  * Add all possible  FileIndexes to the list of BootStrap records.
413  *  Here we are only dealing with JobId's and the FileIndexes
414  *  associated with those JobIds.
415  */
416 void add_findex_all(RBSR *bsr, uint32_t JobId)
417 {
418    RBSR *nbsr;
419    RBSR_FINDEX *fi;
420
421    if (bsr->fi == NULL) {             /* if no FI add one */
422       /* This is the first FileIndex item in the chain */
423       bsr->fi = new_findex();
424       bsr->JobId = JobId;
425       bsr->fi->findex = 1;
426       bsr->fi->findex2 = INT32_MAX;
427       return;
428    }
429    /* Walk down list of bsrs until we find the JobId */
430    if (bsr->JobId != JobId) {
431       for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
432          if (nbsr->JobId == JobId) {
433             bsr = nbsr;
434             break;
435          }
436       }
437
438       if (!nbsr) {                    /* Must add new JobId */
439          /* Add new JobId at end of chain */
440          for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
441             {  }
442          nbsr->next = new_bsr();
443          nbsr->next->JobId = JobId;
444          nbsr->next->fi = new_findex();
445          nbsr->next->fi->findex = 1;
446          nbsr->next->fi->findex2 = INT32_MAX;
447          return;
448       }
449    }
450
451    /*
452     * At this point, bsr points to bsr containing this JobId,
453     *  and we are sure that there is at least one fi record.
454     */
455    fi = bsr->fi;
456    fi->findex = 1;
457    fi->findex2 = INT32_MAX;
458    return;
459 }