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