]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/bsr.c
This commit was manufactured by cvs2svn to create tag
[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
18    version 2 as amended with additional clauses defined in the
19    file LICENSE in the main source directory.
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 
24    the file LICENSE for additional details.
25
26  */
27
28 #include "bacula.h"
29 #include "dird.h"
30
31 /* Forward referenced functions */
32 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd);
33 void print_bsr(UAContext *ua, RBSR *bsr);
34
35
36 /*
37  * Create new FileIndex entry for BSR
38  */
39 RBSR_FINDEX *new_findex()
40 {
41    RBSR_FINDEX *fi = (RBSR_FINDEX *)bmalloc(sizeof(RBSR_FINDEX));
42    memset(fi, 0, sizeof(RBSR_FINDEX));
43    return fi;
44 }
45
46 /* Free all BSR FileIndex entries */
47 static void free_findex(RBSR_FINDEX *fi)
48 {
49    RBSR_FINDEX *next;
50    for ( ; fi; fi=next) {
51       next = fi->next;
52       free(fi);
53    }
54 }
55
56 /*
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.
62  *
63  * We are called here once for each JobMedia record
64  *  for each Volume.
65  */
66 static uint32_t write_findex(UAContext *ua, RBSR_FINDEX *fi,
67               int32_t FirstIndex, int32_t LastIndex, FILE *fd)
68 {
69    uint32_t count = 0;
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);
79             count++;
80          } else {
81             fprintf(fd, "FileIndex=%d-%d\n", findex, findex2);
82             count += findex2 - findex + 1;
83          }
84       }
85    }
86    return count;
87 }
88
89 /*
90  * Find out if Volume defined with FirstIndex and LastIndex
91  *   falls within the range of selected files in the bsr.
92  */
93 static bool is_volume_selected(RBSR_FINDEX *fi,
94               int32_t FirstIndex, int32_t LastIndex)
95 {
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)) {
100          return true;
101       }
102    }
103    return false;
104 }
105
106
107
108 static void print_findex(UAContext *ua, RBSR_FINDEX *fi)
109 {
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(1000, "FileIndex=%d\n", fi->findex);
115       } else {
116          bsendmsg(ua, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
117          Dmsg2(1000, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
118       }
119    }
120 }
121
122 /* Create a new bootstrap record */
123 RBSR *new_bsr()
124 {
125    RBSR *bsr = (RBSR *)bmalloc(sizeof(RBSR));
126    memset(bsr, 0, sizeof(RBSR));
127    return bsr;
128 }
129
130 /* Free the entire BSR */
131 void free_bsr(RBSR *bsr)
132 {
133    RBSR *next;
134    for ( ; bsr; bsr=next) {
135       free_findex(bsr->fi);
136       if (bsr->VolParams) {
137          free(bsr->VolParams);
138       }
139       next = bsr->next;
140       free(bsr);
141    }
142 }
143
144 /*
145  * Complete the BSR by filling in the VolumeName and
146  *  VolSessionId and VolSessionTime using the JobId
147  */
148 bool complete_bsr(UAContext *ua, RBSR *bsr)
149 {
150    for ( ; bsr; bsr=bsr->next) {
151       JOB_DBR jr;
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));
156          return false;
157       }
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;
166          }
167          return false;
168       }
169    }
170    return true;
171 }
172
173 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
174 static uint32_t uniq = 0;
175  
176 void make_unique_restore_filename(UAContext *ua, POOLMEM **fname)
177 {
178    JCR *jcr = ua->jcr;
179    int i = find_arg_with_value(ua, "bootstrap");
180    if (i >= 0) {
181       Mmsg(fname, "%s", ua->argv[i]);              
182       jcr->unlink_bsr = false;
183    } else {
184       P(mutex);
185       uniq++;
186       V(mutex);
187       Mmsg(fname, "%s/%s.%u.restore.bsr", working_directory, my_name, uniq);
188       jcr->unlink_bsr = true;
189    }
190    if (jcr->RestoreBootstrap) {
191       free(jcr->RestoreBootstrap);
192    }
193    jcr->RestoreBootstrap = bstrdup(*fname);
194 }
195
196 /*
197  * Write the bootstrap records to file
198  */
199 uint32_t write_bsr_file(UAContext *ua, RESTORE_CTX &rx)
200 {
201    FILE *fd;
202    POOLMEM *fname = get_pool_memory(PM_MESSAGE);
203    uint32_t count = 0;;
204    bool err;
205    char *p;
206    JobId_t JobId;
207
208    make_unique_restore_filename(ua, &fname);
209    fd = fopen(fname, "w+");
210    if (!fd) {
211       berrno be;
212       bsendmsg(ua, _("Unable to create bootstrap file %s. ERR=%s\n"),
213          fname, be.strerror());
214       goto bail_out;
215    }
216    /* Write them to file */
217    count = write_bsr(ua, rx, fd);
218    err = ferror(fd);
219    fclose(fd);
220    if (err) {
221       bsendmsg(ua, _("Error writing bsr file.\n"));
222       count = 0;
223       goto bail_out;
224    }
225
226
227    bsendmsg(ua, _("Bootstrap records written to %s\n"), fname);
228
229    /* Tell the user what he will need to mount */
230    bsendmsg(ua, "\n");
231    bsendmsg(ua, _("The job will require the following Volumes:\n"));
232    /* Create Unique list of Volumes using prompt list */
233    start_prompt(ua, "");
234    if (*rx.JobIds) {
235       /* Ensure that the volumes are printed in JobId order */
236       for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
237          for (RBSR *nbsr=rx.bsr; nbsr; nbsr=nbsr->next) {
238             if (JobId != nbsr->JobId) {
239                continue;
240             }
241             for (int i=0; i < nbsr->VolCount; i++) {
242                if (nbsr->VolParams[i].VolumeName[0]) {
243                   add_prompt(ua, nbsr->VolParams[i].VolumeName);
244                }
245             }
246          }
247       }
248    } else {
249       /* Print Volumes in any order */
250       for (RBSR *nbsr=rx.bsr; nbsr; nbsr=nbsr->next) {
251          for (int i=0; i < nbsr->VolCount; i++) {
252             if (nbsr->VolParams[i].VolumeName[0]) {
253                add_prompt(ua, nbsr->VolParams[i].VolumeName);
254             }
255          }
256       }
257    }
258    for (int i=0; i < ua->num_prompts; i++) {
259       bsendmsg(ua, "   %s\n", ua->prompt[i]);
260       free(ua->prompt[i]);
261    }
262    if (ua->num_prompts == 0) {
263       bsendmsg(ua, _("No Volumes found to restore.\n"));
264       count = 0;
265    }
266    ua->num_prompts = 0;
267    bsendmsg(ua, "\n");
268
269 bail_out:
270    free_pool_memory(fname);
271    return count;
272 }
273
274 /*
275  * Here we actually write out the details of the bsr file.
276  *  Note, there is one bsr for each JobId, but the bsr may
277  *  have multiple volumes, which have been entered in the
278  *  order they were written.  
279  * The bsrs must be written out in the order the JobIds
280  *  are found in the jobid list.
281  */
282 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd)
283 {
284    uint32_t count = 0;
285    uint32_t total_count = 0;
286    uint32_t LastIndex = 0;
287    bool first = true;
288    char *p;
289    JobId_t JobId;
290    RBSR *bsr;
291    if (*rx.JobIds == 0) {
292       for (bsr=rx.bsr; bsr; bsr=bsr->next) {
293          /*
294           * For a given volume, loop over all the JobMedia records.
295           *   VolCount is the number of JobMedia records.
296           */
297          for (int i=0; i < bsr->VolCount; i++) {
298             if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
299                  bsr->VolParams[i].LastIndex)) {
300                bsr->VolParams[i].VolumeName[0] = 0;  /* zap VolumeName */
301                continue;
302             }
303             fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
304             fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
305             fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
306             fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
307             if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) {
308                fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartFile);
309             } else {
310                fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
311                        bsr->VolParams[i].EndFile);
312             }
313             if (bsr->VolParams[i].StartBlock == bsr->VolParams[i].EndBlock) {
314                fprintf(fd, "VolBlock=%u\n", bsr->VolParams[i].StartBlock);
315             } else {
316                fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
317                        bsr->VolParams[i].EndBlock);
318             }
319    //       Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
320    //          bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
321
322             count = write_findex(ua, bsr->fi, bsr->VolParams[i].FirstIndex,
323                                  bsr->VolParams[i].LastIndex, fd);
324             if (count) {
325                fprintf(fd, "Count=%u\n", count);
326             }
327             total_count += count;
328             /* If the same file is present on two tapes or in two files
329              *   on a tape, it is a continuation, and should not be treated
330              *   twice in the totals.
331              */
332             if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
333                total_count--;
334             }
335             first = false;
336             LastIndex = bsr->VolParams[i].LastIndex;
337          }
338       }
339       return total_count;
340    }
341    for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
342       for (bsr=rx.bsr; bsr; bsr=bsr->next) {
343          if (JobId != bsr->JobId) {
344             continue;
345          }
346          /*
347           * For a given volume, loop over all the JobMedia records.
348           *   VolCount is the number of JobMedia records.
349           */
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 */
354                continue;
355             }
356             fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
357             fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
358             fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
359             fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
360             if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) {
361                fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartFile);
362             } else {
363                fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
364                        bsr->VolParams[i].EndFile);
365             }
366             if (bsr->VolParams[i].StartBlock == bsr->VolParams[i].EndBlock) {
367                fprintf(fd, "VolBlock=%u\n", bsr->VolParams[i].StartBlock);
368             } else {
369                fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
370                        bsr->VolParams[i].EndBlock);
371             }
372    //       Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
373    //          bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
374
375             count = write_findex(ua, bsr->fi, bsr->VolParams[i].FirstIndex,
376                                  bsr->VolParams[i].LastIndex, fd);
377             if (count) {
378                fprintf(fd, "Count=%u\n", count);
379             }
380             total_count += count;
381             /* If the same file is present on two tapes or in two files
382              *   on a tape, it is a continuation, and should not be treated
383              *   twice in the totals.
384              */
385             if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
386                total_count--;
387             }
388             first = false;
389             LastIndex = bsr->VolParams[i].LastIndex;
390          }
391       }
392    }
393    return total_count;
394 }
395
396 void print_bsr(UAContext *ua, RBSR *bsr)
397 {
398    for ( ; bsr; bsr=bsr->next) {
399       for (int i=0; i < bsr->VolCount; i++) {
400          bsendmsg(ua, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
401          bsendmsg(ua, "MediaType\"%s\"\n", bsr->VolParams[i].MediaType);
402          bsendmsg(ua, "VolSessionId=%u\n", bsr->VolSessionId);
403          bsendmsg(ua, "VolSessionTime=%u\n", bsr->VolSessionTime);
404          bsendmsg(ua, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
405                   bsr->VolParams[i].EndFile);
406          bsendmsg(ua, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
407                   bsr->VolParams[i].EndBlock);
408          print_findex(ua, bsr->fi);
409       }
410       print_bsr(ua, bsr->next);
411    }
412 }
413
414
415
416
417 /*
418  * Add a FileIndex to the list of BootStrap records.
419  *  Here we are only dealing with JobId's and the FileIndexes
420  *  associated with those JobIds.
421  */
422 void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
423 {
424    RBSR *nbsr;
425    RBSR_FINDEX *fi, *lfi;
426
427    if (findex == 0) {
428       return;                         /* probably a dummy directory */
429    }
430
431    if (bsr->fi == NULL) {             /* if no FI add one */
432       /* This is the first FileIndex item in the chain */
433       bsr->fi = new_findex();
434       bsr->JobId = JobId;
435       bsr->fi->findex = findex;
436       bsr->fi->findex2 = findex;
437       return;
438    }
439    /* Walk down list of bsrs until we find the JobId */
440    if (bsr->JobId != JobId) {
441       for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
442          if (nbsr->JobId == JobId) {
443             bsr = nbsr;
444             break;
445          }
446       }
447
448       if (!nbsr) {                    /* Must add new JobId */
449          /* Add new JobId at end of chain */
450          for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
451             {  }
452          nbsr->next = new_bsr();
453          nbsr->next->JobId = JobId;
454          nbsr->next->fi = new_findex();
455          nbsr->next->fi->findex = findex;
456          nbsr->next->fi->findex2 = findex;
457          return;
458       }
459    }
460
461    /*
462     * At this point, bsr points to bsr containing this JobId,
463     *  and we are sure that there is at least one fi record.
464     */
465    lfi = fi = bsr->fi;
466    /* Check if this findex is smaller than first item */
467    if (findex < fi->findex) {
468       if ((findex+1) == fi->findex) {
469          fi->findex = findex;         /* extend down */
470          return;
471       }
472       fi = new_findex();              /* yes, insert before first item */
473       fi->findex = findex;
474       fi->findex2 = findex;
475       fi->next = lfi;
476       bsr->fi = fi;
477       return;
478    }
479    /* Walk down fi chain and find where to insert insert new FileIndex */
480    for ( ; fi; fi=fi->next) {
481       if (findex == (fi->findex2 + 1)) {  /* extend up */
482          RBSR_FINDEX *nfi;
483          fi->findex2 = findex;
484          /*
485           * If the following record contains one higher, merge its
486           *   file index by extending it up.
487           */
488          if (fi->next && ((findex+1) == fi->next->findex)) {
489             nfi = fi->next;
490             fi->findex2 = nfi->findex2;
491             fi->next = nfi->next;
492             free(nfi);
493          }
494          return;
495       }
496       if (findex < fi->findex) {      /* add before */
497          if ((findex+1) == fi->findex) {
498             fi->findex = findex;
499             return;
500          }
501          break;
502       }
503       lfi = fi;
504    }
505    /* Add to last place found */
506    fi = new_findex();
507    fi->findex = findex;
508    fi->findex2 = findex;
509    fi->next = lfi->next;
510    lfi->next = fi;
511    return;
512 }
513
514 /*
515  * Add all possible  FileIndexes to the list of BootStrap records.
516  *  Here we are only dealing with JobId's and the FileIndexes
517  *  associated with those JobIds.
518  */
519 void add_findex_all(RBSR *bsr, uint32_t JobId)
520 {
521    RBSR *nbsr;
522    RBSR_FINDEX *fi;
523
524    if (bsr->fi == NULL) {             /* if no FI add one */
525       /* This is the first FileIndex item in the chain */
526       bsr->fi = new_findex();
527       bsr->JobId = JobId;
528       bsr->fi->findex = 1;
529       bsr->fi->findex2 = INT32_MAX;
530       return;
531    }
532    /* Walk down list of bsrs until we find the JobId */
533    if (bsr->JobId != JobId) {
534       for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
535          if (nbsr->JobId == JobId) {
536             bsr = nbsr;
537             break;
538          }
539       }
540
541       if (!nbsr) {                    /* Must add new JobId */
542          /* Add new JobId at end of chain */
543          for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
544             {  }
545          nbsr->next = new_bsr();
546          nbsr->next->JobId = JobId;
547          nbsr->next->fi = new_findex();
548          nbsr->next->fi->findex = 1;
549          nbsr->next->fi->findex2 = INT32_MAX;
550          return;
551       }
552    }
553
554    /*
555     * At this point, bsr points to bsr containing this JobId,
556     *  and we are sure that there is at least one fi record.
557     */
558    fi = bsr->fi;
559    fi->findex = 1;
560    fi->findex2 = INT32_MAX;
561    return;
562 }