]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/bsr.c
Fix breaks in bextract + in restore print only volumes to be actually used
[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-2003 Kern Sibbald and John Walker
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 void write_bsr(UAContext *ua, RBSR *bsr, FILE *fd);
38
39
40 /*
41  * Create new FileIndex entry for BSR 
42  */
43 RBSR_FINDEX *new_findex() 
44 {
45    RBSR_FINDEX *fi = (RBSR_FINDEX *)bmalloc(sizeof(RBSR_FINDEX));
46    memset(fi, 0, sizeof(RBSR_FINDEX));
47    return fi;
48 }
49
50 /* Free all BSR FileIndex entries */
51 static void free_findex(RBSR_FINDEX *fi)
52 {
53    if (fi) {
54       free_findex(fi->next);
55       free(fi);
56    }
57 }
58
59 /*
60  * Our data structures were not designed completely
61  *  correctly, so the file indexes cover the full
62  *  range regardless of volume. The FirstIndex and LastIndex
63  *  passed in here are for the current volume, so when 
64  *  writing out the fi, constrain them to those values.
65  */
66 static void write_findex(UAContext *ua, RBSR_FINDEX *fi, 
67               int32_t FirstIndex, int32_t LastIndex, FILE *fd) 
68 {
69    if (fi) {
70       int32_t findex, findex2;
71       findex = fi->findex < FirstIndex ? FirstIndex : fi->findex;
72       findex2 = fi->findex2 > LastIndex ? LastIndex : fi->findex2;
73       if (findex == findex2) {
74          fprintf(fd, "FileIndex=%d\n", findex);
75       } else {
76          fprintf(fd, "FileIndex=%d-%d\n", findex, findex2);
77       }
78       write_findex(ua, fi->next, FirstIndex, LastIndex, fd);
79    }
80 }
81
82 static bool is_volume_selected(RBSR_FINDEX *fi, 
83               int32_t FirstIndex, int32_t LastIndex) 
84 {
85    if (fi) {
86       if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
87           (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex)) {
88          return true;
89       }
90       return is_volume_selected(fi->next, FirstIndex, LastIndex);
91    }
92    return false;
93 }
94
95
96
97 static void print_findex(UAContext *ua, RBSR_FINDEX *fi)
98 {
99    if (fi) {
100       if (fi->findex == fi->findex2) {
101          bsendmsg(ua, "FileIndex=%d\n", fi->findex);
102       } else {
103          bsendmsg(ua, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
104       }
105       print_findex(ua, fi->next);
106    }
107 }
108
109 /* Create a new bootstrap record */
110 RBSR *new_bsr()
111 {
112    RBSR *bsr = (RBSR *)bmalloc(sizeof(RBSR));
113    memset(bsr, 0, sizeof(RBSR));
114    return bsr;
115 }
116
117 /* Free the entire BSR */
118 void free_bsr(RBSR *bsr)
119 {
120    if (bsr) {
121       free_findex(bsr->fi);
122       free_bsr(bsr->next);
123       if (bsr->VolParams) {
124          free(bsr->VolParams);
125       }
126       free(bsr);
127    }
128 }
129
130 /*
131  * Complete the BSR by filling in the VolumeName and
132  *  VolSessionId and VolSessionTime using the JobId
133  */
134 int complete_bsr(UAContext *ua, RBSR *bsr)
135 {
136    if (bsr) {
137       JOB_DBR jr;
138       memset(&jr, 0, sizeof(jr));
139       jr.JobId = bsr->JobId;
140       if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
141          bsendmsg(ua, _("Unable to get Job record. ERR=%s\n"), db_strerror(ua->db));
142          return 0;
143       }
144       bsr->VolSessionId = jr.VolSessionId;
145       bsr->VolSessionTime = jr.VolSessionTime;
146       if ((bsr->VolCount=db_get_job_volume_parameters(ua->jcr, ua->db, bsr->JobId, 
147            &(bsr->VolParams))) == 0) {
148          bsendmsg(ua, _("Unable to get Job Volume Parameters. ERR=%s\n"), db_strerror(ua->db));
149          if (bsr->VolParams) {
150             free(bsr->VolParams);
151             bsr->VolParams = NULL;
152          }
153          return 0;
154       }
155       return complete_bsr(ua, bsr->next);
156    }
157    return 1;
158 }
159
160 /*
161  * Write the bootstrap record to file
162  */
163 int write_bsr_file(UAContext *ua, RBSR *bsr)
164 {
165    FILE *fd;
166    POOLMEM *fname = get_pool_memory(PM_MESSAGE);
167    int stat;
168
169    Mmsg(&fname, "%s/restore.bsr", working_directory);
170    fd = fopen(fname, "w+");
171    if (!fd) {
172       bsendmsg(ua, _("Unable to create bootstrap file %s. ERR=%s\n"), 
173          fname, strerror(errno));
174       free_pool_memory(fname);
175       return 0;
176    }
177    /* Write them to file */
178    write_bsr(ua, bsr, fd);
179    stat = !ferror(fd);
180    fclose(fd);
181    bsendmsg(ua, _("Bootstrap records written to %s\n"), fname);
182
183    /* Tell the user what he will need to mount */
184    bsendmsg(ua, "\n");
185    bsendmsg(ua, _("The restore job will require the following Volumes:\n"));
186    /* Create Unique list of Volumes using prompt list */
187    start_prompt(ua, "");
188    for (RBSR *nbsr=bsr; nbsr; nbsr=nbsr->next) {
189       for (int i=0; i < nbsr->VolCount; i++) {
190          if (nbsr->VolParams[i].VolumeName[0]) {
191             add_prompt(ua, nbsr->VolParams[i].VolumeName);
192          }
193       }
194    }
195    for (int i=0; i < ua->num_prompts; i++) {
196       bsendmsg(ua, "   %s\n", ua->prompt[i]);
197       free(ua->prompt[i]);
198    }
199    ua->num_prompts = 0;
200    bsendmsg(ua, "\n");
201    free_pool_memory(fname);
202    return stat;
203 }
204
205 static void write_bsr(UAContext *ua, RBSR *bsr, FILE *fd)
206 {
207    if (bsr) {
208       for (int i=0; i < bsr->VolCount; i++) {
209          if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
210               bsr->VolParams[i].LastIndex)) {
211             bsr->VolParams[i].VolumeName[0] = 0;  /* zap VolumeName */
212             continue;
213          }
214          fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
215          fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
216          fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
217          fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile, 
218                  bsr->VolParams[i].EndFile);
219          fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
220                  bsr->VolParams[i].EndBlock);
221
222 //       Dmsg2(000, "bsr VolParam FI=%u LI=%u\n",
223 //          bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
224          write_findex(ua, bsr->fi, bsr->VolParams[i].FirstIndex,
225             bsr->VolParams[i].LastIndex, fd);
226       }
227       write_bsr(ua, bsr->next, fd);
228    }
229 }
230
231 static void print_bsr(UAContext *ua, RBSR *bsr)
232 {
233    if (bsr) {
234       for (int i=0; i < bsr->VolCount; i++) {
235          bsendmsg(ua, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
236          bsendmsg(ua, "VolSessionId=%u\n", bsr->VolSessionId);
237          bsendmsg(ua, "VolSessionTime=%u\n", bsr->VolSessionTime);
238          bsendmsg(ua, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile, 
239                   bsr->VolParams[i].EndFile);
240          bsendmsg(ua, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
241                   bsr->VolParams[i].EndBlock);
242          print_findex(ua, bsr->fi);
243       }
244       print_bsr(ua, bsr->next);
245    }
246 }
247
248
249 /*
250  * Add a FileIndex to the list of BootStrap records.
251  *  Here we are only dealing with JobId's and the FileIndexes
252  *  associated with those JobIds.
253  */
254 void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
255 {
256    RBSR *nbsr;
257    RBSR_FINDEX *fi, *lfi;
258
259    if (findex == 0) {
260       return;                         /* probably a dummy directory */
261    }
262    
263    if (!bsr->fi) {                    /* if no FI add one */
264       /* This is the first FileIndex item in the chain */
265       bsr->fi = new_findex();
266       bsr->JobId = JobId;
267       bsr->fi->findex = findex;
268       bsr->fi->findex2 = findex;
269       return;
270    }
271    /* Walk down list of bsrs until we find the JobId */
272    if (bsr->JobId != JobId) {
273       for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
274          if (nbsr->JobId == JobId) {
275             bsr = nbsr;
276             break;
277          }
278       }
279
280       if (!nbsr) {                    /* Must add new JobId */
281          /* Add new JobId at end of chain */
282          for (nbsr=bsr; nbsr->next; nbsr=nbsr->next) 
283             {  }
284          nbsr->next = new_bsr();
285          nbsr->next->JobId = JobId;
286          nbsr->next->fi = new_findex();
287          nbsr->next->fi->findex = findex;
288          nbsr->next->fi->findex2 = findex;
289          return;
290       }
291    }
292
293    /* 
294     * At this point, bsr points to bsr containing JobId,
295     *  and we are sure that there is at least one fi record.
296     */
297    lfi = fi = bsr->fi;
298    /* Check if this findex is smaller than first item */
299    if (findex < fi->findex) {
300       if ((findex+1) == fi->findex) {
301          fi->findex = findex;         /* extend down */
302          return;
303       }
304       fi = new_findex();              /* yes, insert before first item */
305       fi->findex = findex;
306       fi->findex2 = findex;
307       fi->next = lfi;
308       bsr->fi = fi;
309       return;
310    }
311    /* Walk down fi chain and find where to insert insert new FileIndex */
312    for ( ; fi; fi=fi->next) {
313       if (findex == (fi->findex2 + 1)) {  /* extend up */
314          RBSR_FINDEX *nfi;     
315          fi->findex2 = findex;
316          if (fi->next && ((findex+1) == fi->next->findex)) { 
317             nfi = fi->next;
318             fi->findex2 = nfi->findex2;
319             fi->next = nfi->next;
320             free(nfi);
321          }
322          return;
323       }
324       if (findex < fi->findex) {      /* add before */
325          if ((findex+1) == fi->findex) {
326             fi->findex = findex;
327             return;
328          }
329          break;
330       }
331       lfi = fi;
332    }
333    /* Add to last place found */
334    fi = new_findex();
335    fi->findex = findex;
336    fi->findex2 = findex;
337    fi->next = lfi->next;
338    lfi->next = fi;
339    return;
340 }