]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/bsr.c
Remove -lnsl from tpc wrappers link unless needed
[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 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    if (fi) {
55       free_findex(fi->next);
56       free(fi);
57    }
58 }
59
60 /*
61  * Our data structures were not designed completely
62  *  correctly, so the file indexes cover the full
63  *  range regardless of volume. The FirstIndex and LastIndex
64  *  passed in here are for the current volume, so when 
65  *  writing out the fi, constrain them to those values.
66  *
67  * We are called here once for each JobMedia record
68  *  for each Volume.
69  */
70 static void write_findex(UAContext *ua, RBSR_FINDEX *fi, 
71               int32_t FirstIndex, int32_t LastIndex, FILE *fd) 
72 {
73    for ( ; fi; fi=fi->next) {
74       int32_t findex, findex2;
75       if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
76           (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
77           (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
78          findex = fi->findex < FirstIndex ? FirstIndex : fi->findex;
79          findex2 = fi->findex2 > LastIndex ? LastIndex : fi->findex2;
80          if (findex == findex2) {
81             fprintf(fd, "FileIndex=%d\n", findex);
82          } else {
83             fprintf(fd, "FileIndex=%d-%d\n", findex, findex2);
84          }
85       }
86    }
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    if (fi) {
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       return is_volume_selected(fi->next, FirstIndex, LastIndex);
103    }
104    return false;
105 }
106
107
108
109 static void print_findex(UAContext *ua, RBSR_FINDEX *fi)
110 {
111    bsendmsg(ua, "fi=0x%x\n", (unsigned)fi);
112    for ( ; fi; fi=fi->next) {
113       if (fi->findex == fi->findex2) {
114          bsendmsg(ua, "FileIndex=%d\n", fi->findex);
115 //       Dmsg1(000, "FileIndex=%d\n", fi->findex);
116       } else {
117          bsendmsg(ua, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
118 //       Dmsg2(000, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
119       }
120    }
121 }
122
123 /* Create a new bootstrap record */
124 RBSR *new_bsr()
125 {
126    RBSR *bsr = (RBSR *)bmalloc(sizeof(RBSR));
127    memset(bsr, 0, sizeof(RBSR));
128    return bsr;
129 }
130
131 /* Free the entire BSR */
132 void free_bsr(RBSR *bsr)
133 {
134    if (bsr) {
135       free_findex(bsr->fi);
136       free_bsr(bsr->next);
137       if (bsr->VolParams) {
138          free(bsr->VolParams);
139       }
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 int complete_bsr(UAContext *ua, RBSR *bsr)
149 {
150    if (bsr) {
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 0;
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 0;
168       }
169       return complete_bsr(ua, bsr->next);
170    }
171    return 1;
172 }
173
174 /*
175  * Write the bootstrap record to file
176  */
177 int write_bsr_file(UAContext *ua, RBSR *bsr)
178 {
179    FILE *fd;
180    POOLMEM *fname = get_pool_memory(PM_MESSAGE);
181    int stat;
182
183    Mmsg(&fname, "%s/restore.bsr", working_directory);
184    fd = fopen(fname, "w+");
185    if (!fd) {
186       bsendmsg(ua, _("Unable to create bootstrap file %s. ERR=%s\n"), 
187          fname, strerror(errno));
188       free_pool_memory(fname);
189       return 0;
190    }
191    /* Write them to file */
192    write_bsr(ua, bsr, fd);
193    stat = !ferror(fd);
194    fclose(fd);
195    bsendmsg(ua, _("Bootstrap records written to %s\n"), fname);
196
197    /* Tell the user what he will need to mount */
198    bsendmsg(ua, "\n");
199    bsendmsg(ua, _("The restore job will require the following Volumes:\n"));
200    /* Create Unique list of Volumes using prompt list */
201    start_prompt(ua, "");
202    for (RBSR *nbsr=bsr; nbsr; nbsr=nbsr->next) {
203       for (int i=0; i < nbsr->VolCount; i++) {
204          if (nbsr->VolParams[i].VolumeName[0]) {
205             add_prompt(ua, nbsr->VolParams[i].VolumeName);
206          }
207       }
208    }
209    for (int i=0; i < ua->num_prompts; i++) {
210       bsendmsg(ua, "   %s\n", ua->prompt[i]);
211       free(ua->prompt[i]);
212    }
213    ua->num_prompts = 0;
214    bsendmsg(ua, "\n");
215    free_pool_memory(fname);
216    return stat;
217 }
218
219 static void write_bsr(UAContext *ua, RBSR *bsr, FILE *fd)
220 {
221    if (bsr) {
222       /*
223        * For a given volume, loop over all the JobMedia records.
224        *   VolCount is the number of JobMedia records.
225        */
226       for (int i=0; i < bsr->VolCount; i++) {
227          if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
228               bsr->VolParams[i].LastIndex)) {
229             bsr->VolParams[i].VolumeName[0] = 0;  /* zap VolumeName */
230             continue;
231          }
232          fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
233          fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
234          fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
235          fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile, 
236                  bsr->VolParams[i].EndFile);
237          fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
238                  bsr->VolParams[i].EndBlock);
239
240 //       Dmsg2(000, "bsr VolParam FI=%u LI=%u\n",
241 //          bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
242          write_findex(ua, bsr->fi, bsr->VolParams[i].FirstIndex,
243             bsr->VolParams[i].LastIndex, fd);
244       }
245       write_bsr(ua, bsr->next, fd);
246    }
247 }
248
249 void print_bsr(UAContext *ua, RBSR *bsr)
250 {
251    if (bsr) {
252       for (int i=0; i < bsr->VolCount; i++) {
253          bsendmsg(ua, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
254          bsendmsg(ua, "VolSessionId=%u\n", bsr->VolSessionId);
255          bsendmsg(ua, "VolSessionTime=%u\n", bsr->VolSessionTime);
256          bsendmsg(ua, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile, 
257                   bsr->VolParams[i].EndFile);
258          bsendmsg(ua, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
259                   bsr->VolParams[i].EndBlock);
260          print_findex(ua, bsr->fi);
261       }
262       print_bsr(ua, bsr->next);
263    }
264 }
265
266
267 /*
268  * Add a FileIndex to the list of BootStrap records.
269  *  Here we are only dealing with JobId's and the FileIndexes
270  *  associated with those JobIds.
271  */
272 void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
273 {
274    RBSR *nbsr;
275    RBSR_FINDEX *fi, *lfi;
276
277    if (findex == 0) {
278       return;                         /* probably a dummy directory */
279    }
280    
281    if (bsr->fi == NULL) {             /* if no FI add one */
282       /* This is the first FileIndex item in the chain */
283       bsr->fi = new_findex();
284       bsr->JobId = JobId;
285       bsr->fi->findex = findex;
286       bsr->fi->findex2 = findex;
287       return;
288    }
289    /* Walk down list of bsrs until we find the JobId */
290    if (bsr->JobId != JobId) {
291       for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
292          if (nbsr->JobId == JobId) {
293             bsr = nbsr;
294             break;
295          }
296       }
297
298       if (!nbsr) {                    /* Must add new JobId */
299          /* Add new JobId at end of chain */
300          for (nbsr=bsr; nbsr->next; nbsr=nbsr->next) 
301             {  }
302          nbsr->next = new_bsr();
303          nbsr->next->JobId = JobId;
304          nbsr->next->fi = new_findex();
305          nbsr->next->fi->findex = findex;
306          nbsr->next->fi->findex2 = findex;
307          return;
308       }
309    }
310
311    /* 
312     * At this point, bsr points to bsr containing this JobId,
313     *  and we are sure that there is at least one fi record.
314     */
315    lfi = fi = bsr->fi;
316    /* Check if this findex is smaller than first item */
317    if (findex < fi->findex) {
318       if ((findex+1) == fi->findex) {
319          fi->findex = findex;         /* extend down */
320          return;
321       }
322       fi = new_findex();              /* yes, insert before first item */
323       fi->findex = findex;
324       fi->findex2 = findex;
325       fi->next = lfi;
326       bsr->fi = fi;
327       return;
328    }
329    /* Walk down fi chain and find where to insert insert new FileIndex */
330    for ( ; fi; fi=fi->next) {
331       if (findex == (fi->findex2 + 1)) {  /* extend up */
332          RBSR_FINDEX *nfi;     
333          fi->findex2 = findex;
334          /*
335           * If the following record contains one higher, merge its
336           *   file index by extending it up.
337           */
338          if (fi->next && ((findex+1) == fi->next->findex)) { 
339             nfi = fi->next;
340             fi->findex2 = nfi->findex2;
341             fi->next = nfi->next;
342             free(nfi);
343          }
344          return;
345       }
346       if (findex < fi->findex) {      /* add before */
347          if ((findex+1) == fi->findex) {
348             fi->findex = findex;
349             return;
350          }
351          break;
352       }
353       lfi = fi;
354    }
355    /* Add to last place found */
356    fi = new_findex();
357    fi->findex = findex;
358    fi->findex2 = findex;
359    fi->next = lfi->next;
360    lfi->next = fi;
361    return;
362 }