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