]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/bsr.c
Constrain BSR indexes, fix bscan, add some new alist code
[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          add_prompt(ua, nbsr->VolParams[i].VolumeName);
191       }
192    }
193    for (int i=0; i < ua->num_prompts; i++) {
194       bsendmsg(ua, "   %s\n", ua->prompt[i]);
195       free(ua->prompt[i]);
196    }
197    ua->num_prompts = 0;
198    bsendmsg(ua, "\n");
199    free_pool_memory(fname);
200    return stat;
201 }
202
203 static void write_bsr(UAContext *ua, RBSR *bsr, FILE *fd)
204 {
205    if (bsr) {
206       for (int i=0; i < bsr->VolCount; i++) {
207          if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
208               bsr->VolParams[i].LastIndex)) {
209             continue;
210          }
211          fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
212          fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
213          fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
214          fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile, 
215                  bsr->VolParams[i].EndFile);
216          fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
217                  bsr->VolParams[i].EndBlock);
218
219 //       Dmsg2(000, "bsr VolParam FI=%u LI=%u\n",
220 //          bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
221          write_findex(ua, bsr->fi, bsr->VolParams[i].FirstIndex,
222             bsr->VolParams[i].LastIndex, fd);
223       }
224       write_bsr(ua, bsr->next, fd);
225    }
226 }
227
228 static void print_bsr(UAContext *ua, RBSR *bsr)
229 {
230    if (bsr) {
231       for (int i=0; i < bsr->VolCount; i++) {
232          bsendmsg(ua, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
233          bsendmsg(ua, "VolSessionId=%u\n", bsr->VolSessionId);
234          bsendmsg(ua, "VolSessionTime=%u\n", bsr->VolSessionTime);
235          bsendmsg(ua, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile, 
236                   bsr->VolParams[i].EndFile);
237          bsendmsg(ua, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
238                   bsr->VolParams[i].EndBlock);
239          print_findex(ua, bsr->fi);
240       }
241       print_bsr(ua, bsr->next);
242    }
243 }
244
245
246 /*
247  * Add a FileIndex to the list of BootStrap records.
248  *  Here we are only dealing with JobId's and the FileIndexes
249  *  associated with those JobIds.
250  */
251 void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
252 {
253    RBSR *nbsr;
254    RBSR_FINDEX *fi, *lfi;
255
256    if (findex == 0) {
257       return;                         /* probably a dummy directory */
258    }
259    
260    if (!bsr->fi) {                    /* if no FI add one */
261       /* This is the first FileIndex item in the chain */
262       bsr->fi = new_findex();
263       bsr->JobId = JobId;
264       bsr->fi->findex = findex;
265       bsr->fi->findex2 = findex;
266       return;
267    }
268    /* Walk down list of bsrs until we find the JobId */
269    if (bsr->JobId != JobId) {
270       for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
271          if (nbsr->JobId == JobId) {
272             bsr = nbsr;
273             break;
274          }
275       }
276
277       if (!nbsr) {                    /* Must add new JobId */
278          /* Add new JobId at end of chain */
279          for (nbsr=bsr; nbsr->next; nbsr=nbsr->next) 
280             {  }
281          nbsr->next = new_bsr();
282          nbsr->next->JobId = JobId;
283          nbsr->next->fi = new_findex();
284          nbsr->next->fi->findex = findex;
285          nbsr->next->fi->findex2 = findex;
286          return;
287       }
288    }
289
290    /* 
291     * At this point, bsr points to bsr containing JobId,
292     *  and we are sure that there is at least one fi record.
293     */
294    lfi = fi = bsr->fi;
295    /* Check if this findex is smaller than first item */
296    if (findex < fi->findex) {
297       if ((findex+1) == fi->findex) {
298          fi->findex = findex;         /* extend down */
299          return;
300       }
301       fi = new_findex();              /* yes, insert before first item */
302       fi->findex = findex;
303       fi->findex2 = findex;
304       fi->next = lfi;
305       bsr->fi = fi;
306       return;
307    }
308    /* Walk down fi chain and find where to insert insert new FileIndex */
309    for ( ; fi; fi=fi->next) {
310       if (findex == (fi->findex2 + 1)) {  /* extend up */
311          RBSR_FINDEX *nfi;     
312          fi->findex2 = findex;
313          if (fi->next && ((findex+1) == fi->next->findex)) { 
314             nfi = fi->next;
315             fi->findex2 = nfi->findex2;
316             fi->next = nfi->next;
317             free(nfi);
318          }
319          return;
320       }
321       if (findex < fi->findex) {      /* add before */
322          if ((findex+1) == fi->findex) {
323             fi->findex = findex;
324             return;
325          }
326          break;
327       }
328       lfi = fi;
329    }
330    /* Add to last place found */
331    fi = new_findex();
332    fi->findex = findex;
333    fi->findex2 = findex;
334    fi->next = lfi->next;
335    lfi->next = fi;
336    return;
337 }