1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2002-2012 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2012 Planets Communications B.V.
6    Copyright (C) 2013-2020 Bareos GmbH & Co. KG
7 
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    Affero General Public License for more details.
17 
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22 */
23 /*
24  * Parse Bootstrap Records (used for restores)
25  *
26  * Kern Sibbald, June MMII
27  */
28 
29 #include "include/bareos.h"
30 #include "jcr.h"
31 #include "stored/bsr.h"
32 #include "lib/berrno.h"
33 #include "lib/parse_bsr.h"
34 
35 namespace libbareos {
36 
37 typedef storagedaemon::BootStrapRecord*(
38     ITEM_HANDLER)(LEX* lc, storagedaemon::BootStrapRecord* bsr);
39 
40 static storagedaemon::BootStrapRecord* store_vol(
41     LEX* lc,
42     storagedaemon::BootStrapRecord* bsr);
43 static storagedaemon::BootStrapRecord* store_mediatype(
44     LEX* lc,
45     storagedaemon::BootStrapRecord* bsr);
46 static storagedaemon::BootStrapRecord* StoreDevice(
47     LEX* lc,
48     storagedaemon::BootStrapRecord* bsr);
49 static storagedaemon::BootStrapRecord* store_client(
50     LEX* lc,
51     storagedaemon::BootStrapRecord* bsr);
52 static storagedaemon::BootStrapRecord* store_job(
53     LEX* lc,
54     storagedaemon::BootStrapRecord* bsr);
55 static storagedaemon::BootStrapRecord* store_jobid(
56     LEX* lc,
57     storagedaemon::BootStrapRecord* bsr);
58 static storagedaemon::BootStrapRecord* store_count(
59     LEX* lc,
60     storagedaemon::BootStrapRecord* bsr);
61 static storagedaemon::BootStrapRecord* StoreJobtype(
62     LEX* lc,
63     storagedaemon::BootStrapRecord* bsr);
64 static storagedaemon::BootStrapRecord* store_joblevel(
65     LEX* lc,
66     storagedaemon::BootStrapRecord* bsr);
67 static storagedaemon::BootStrapRecord* store_findex(
68     LEX* lc,
69     storagedaemon::BootStrapRecord* bsr);
70 static storagedaemon::BootStrapRecord* store_sessid(
71     LEX* lc,
72     storagedaemon::BootStrapRecord* bsr);
73 static storagedaemon::BootStrapRecord* store_volfile(
74     LEX* lc,
75     storagedaemon::BootStrapRecord* bsr);
76 static storagedaemon::BootStrapRecord* store_volblock(
77     LEX* lc,
78     storagedaemon::BootStrapRecord* bsr);
79 static storagedaemon::BootStrapRecord* store_voladdr(
80     LEX* lc,
81     storagedaemon::BootStrapRecord* bsr);
82 static storagedaemon::BootStrapRecord* store_sesstime(
83     LEX* lc,
84     storagedaemon::BootStrapRecord* bsr);
85 static storagedaemon::BootStrapRecord* store_include(
86     LEX* lc,
87     storagedaemon::BootStrapRecord* bsr);
88 static storagedaemon::BootStrapRecord* store_exclude(
89     LEX* lc,
90     storagedaemon::BootStrapRecord* bsr);
91 static storagedaemon::BootStrapRecord* store_stream(
92     LEX* lc,
93     storagedaemon::BootStrapRecord* bsr);
94 static storagedaemon::BootStrapRecord* store_slot(
95     LEX* lc,
96     storagedaemon::BootStrapRecord* bsr);
97 static storagedaemon::BootStrapRecord* store_fileregex(
98     LEX* lc,
99     storagedaemon::BootStrapRecord* bsr);
100 static storagedaemon::BootStrapRecord* store_nothing(
101     LEX* lc,
102     storagedaemon::BootStrapRecord* bsr);
103 
104 struct kw_items {
105   const char* name;
106   ITEM_HANDLER* handler;
107 };
108 
109 /*
110  * List of all keywords permitted in bsr files and their handlers
111  */
112 struct kw_items items[] = {{"volume", store_vol},
113                            {"mediatype", store_mediatype},
114                            {"client", store_client},
115                            {"job", store_job},
116                            {"jobid", store_jobid},
117                            {"count", store_count},
118                            {"fileindex", store_findex},
119                            {"jobtype", StoreJobtype},
120                            {"joblevel", store_joblevel},
121                            {"volsessionid", store_sessid},
122                            {"volsessiontime", store_sesstime},
123                            {"include", store_include},
124                            {"exclude", store_exclude},
125                            {"volfile", store_volfile},
126                            {"volblock", store_volblock},
127                            {"voladdr", store_voladdr},
128                            {"stream", store_stream},
129                            {"slot", store_slot},
130                            {"device", StoreDevice},
131                            {"fileregex", store_fileregex},
132                            {"storage", store_nothing},
133                            {NULL, NULL}};
134 
135 /*
136  * Create a storagedaemon::BootStrapRecord record
137  */
new_bsr()138 static storagedaemon::BootStrapRecord* new_bsr()
139 {
140   storagedaemon::BootStrapRecord* bsr = (storagedaemon::BootStrapRecord*)malloc(
141       sizeof(storagedaemon::BootStrapRecord));
142   memset(bsr, 0, sizeof(storagedaemon::BootStrapRecord));
143   return bsr;
144 }
145 
146 /*
147  * Format a scanner error message
148  */
s_err(const char * file,int line,LEX * lc,const char * msg,...)149 static void s_err(const char* file, int line, LEX* lc, const char* msg, ...)
150 {
151   va_list ap;
152   int len, maxlen;
153   PoolMem buf(PM_NAME);
154   JobControlRecord* jcr = (JobControlRecord*)(lc->caller_ctx);
155 
156   while (1) {
157     maxlen = buf.size() - 1;
158     va_start(ap, msg);
159     len = Bvsnprintf(buf.c_str(), maxlen, msg, ap);
160     va_end(ap);
161 
162     if (len < 0 || len >= (maxlen - 5)) {
163       buf.ReallocPm(maxlen + maxlen / 2);
164       continue;
165     }
166 
167     break;
168   }
169 
170   if (jcr) {
171     Jmsg(jcr, M_FATAL, 0,
172          _("Bootstrap file error: %s\n"
173            "            : Line %d, col %d of file %s\n%s\n"),
174          buf.c_str(), lc->line_no, lc->col_no, lc->fname, lc->line);
175   } else {
176     e_msg(file, line, M_FATAL, 0,
177           _("Bootstrap file error: %s\n"
178             "            : Line %d, col %d of file %s\n%s\n"),
179           buf.c_str(), lc->line_no, lc->col_no, lc->fname, lc->line);
180   }
181 }
182 
183 /*
184  * Format a scanner warning message
185  */
s_warn(const char * file,int line,LEX * lc,const char * msg,...)186 static void s_warn(const char* file, int line, LEX* lc, const char* msg, ...)
187 {
188   va_list ap;
189   int len, maxlen;
190   PoolMem buf(PM_NAME);
191   JobControlRecord* jcr = (JobControlRecord*)(lc->caller_ctx);
192 
193   while (1) {
194     maxlen = buf.size() - 1;
195     va_start(ap, msg);
196     len = Bvsnprintf(buf.c_str(), maxlen, msg, ap);
197     va_end(ap);
198 
199     if (len < 0 || len >= (maxlen - 5)) {
200       buf.ReallocPm(maxlen + maxlen / 2);
201       continue;
202     }
203 
204     break;
205   }
206 
207   if (jcr) {
208     Jmsg(jcr, M_WARNING, 0,
209          _("Bootstrap file warning: %s\n"
210            "            : Line %d, col %d of file %s\n%s\n"),
211          buf.c_str(), lc->line_no, lc->col_no, lc->fname, lc->line);
212   } else {
213     p_msg(file, line, 0,
214           _("Bootstrap file warning: %s\n"
215             "            : Line %d, col %d of file %s\n%s\n"),
216           buf.c_str(), lc->line_no, lc->col_no, lc->fname, lc->line);
217   }
218 }
219 
IsFastRejectionOk(storagedaemon::BootStrapRecord * bsr)220 static inline bool IsFastRejectionOk(storagedaemon::BootStrapRecord* bsr)
221 {
222   /*
223    * Although, this can be optimized, for the moment, require
224    *  all bsrs to have both sesstime and sessid set before
225    *  we do fast rejection.
226    */
227   for (; bsr; bsr = bsr->next) {
228     if (!(bsr->sesstime && bsr->sessid)) { return false; }
229   }
230   return true;
231 }
232 
IsPositioningOk(storagedaemon::BootStrapRecord * bsr)233 static inline bool IsPositioningOk(storagedaemon::BootStrapRecord* bsr)
234 {
235   /*
236    * Every bsr should have a volfile entry and a volblock entry
237    * or a VolAddr
238    *   if we are going to use positioning
239    */
240   for (; bsr; bsr = bsr->next) {
241     if (!((bsr->volfile && bsr->volblock) || bsr->voladdr)) { return false; }
242   }
243   return true;
244 }
245 
246 /*
247  * Parse Bootstrap file
248  */
parse_bsr(JobControlRecord * jcr,char * fname)249 storagedaemon::BootStrapRecord* parse_bsr(JobControlRecord* jcr, char* fname)
250 {
251   LEX* lc = NULL;
252   int token, i;
253   storagedaemon::BootStrapRecord* root_bsr = new_bsr();
254   storagedaemon::BootStrapRecord* bsr = root_bsr;
255 
256   Dmsg1(300, "Enter parse_bsf %s\n", fname);
257   if ((lc = lex_open_file(lc, fname, s_err, s_warn)) == NULL) {
258     BErrNo be;
259     Emsg2(M_ERROR_TERM, 0, _("Cannot open bootstrap file %s: %s\n"), fname,
260           be.bstrerror());
261   }
262   lc->caller_ctx = (void*)jcr;
263   while ((token = LexGetToken(lc, BCT_ALL)) != BCT_EOF) {
264     Dmsg1(300, "parse got token=%s\n", lex_tok_to_str(token));
265     if (token == BCT_EOL) { continue; }
266     for (i = 0; items[i].name; i++) {
267       if (Bstrcasecmp(items[i].name, lc->str)) {
268         token = LexGetToken(lc, BCT_ALL);
269         Dmsg1(300, "in BCT_IDENT got token=%s\n", lex_tok_to_str(token));
270         if (token != BCT_EQUALS) {
271           scan_err1(lc, "expected an equals, got: %s", lc->str);
272           bsr = NULL;
273           break;
274         }
275         Dmsg1(300, "calling handler for %s\n", items[i].name);
276         /*
277          * Call item handler
278          */
279         bsr = items[i].handler(lc, bsr);
280         i = -1;
281         break;
282       }
283     }
284     if (i >= 0) {
285       Dmsg1(300, "Keyword = %s\n", lc->str);
286       scan_err1(lc, "Keyword %s not found", lc->str);
287       bsr = NULL;
288       break;
289     }
290     if (!bsr) { break; }
291   }
292   lc = LexCloseFile(lc);
293   Dmsg0(300, "Leave parse_bsf()\n");
294   if (!bsr) {
295     FreeBsr(root_bsr);
296     root_bsr = NULL;
297   }
298   if (root_bsr) {
299     root_bsr->use_fast_rejection = IsFastRejectionOk(root_bsr);
300     root_bsr->use_positioning = IsPositioningOk(root_bsr);
301   }
302   for (bsr = root_bsr; bsr; bsr = bsr->next) { bsr->root = root_bsr; }
303   return root_bsr;
304 }
305 
store_vol(LEX * lc,storagedaemon::BootStrapRecord * bsr)306 static storagedaemon::BootStrapRecord* store_vol(
307     LEX* lc,
308     storagedaemon::BootStrapRecord* bsr)
309 {
310   int token;
311   storagedaemon::BsrVolume* volume;
312   char *p, *n;
313 
314   token = LexGetToken(lc, BCT_STRING);
315   if (token == BCT_ERROR) { return NULL; }
316   if (bsr->volume) {
317     bsr->next = new_bsr();
318     bsr->next->prev = bsr;
319     bsr = bsr->next;
320   }
321   /* This may actually be more than one volume separated by a |
322    * If so, separate them.
323    */
324   for (p = lc->str; p && *p;) {
325     n = strchr(p, '|');
326     if (n) { *n++ = 0; }
327     volume
328         = (storagedaemon::BsrVolume*)malloc(sizeof(storagedaemon::BsrVolume));
329     memset(volume, 0, sizeof(storagedaemon::BsrVolume));
330     bstrncpy(volume->VolumeName, p, sizeof(volume->VolumeName));
331 
332     /*
333      * Add it to the end of the volume chain
334      */
335     if (!bsr->volume) {
336       bsr->volume = volume;
337     } else {
338       storagedaemon::BsrVolume* bc = bsr->volume;
339       for (; bc->next; bc = bc->next) {}
340       bc->next = volume;
341     }
342     p = n;
343   }
344   return bsr;
345 }
346 
347 /*
348  * Shove the MediaType in each Volume in the current bsr\
349  */
store_mediatype(LEX * lc,storagedaemon::BootStrapRecord * bsr)350 static storagedaemon::BootStrapRecord* store_mediatype(
351     LEX* lc,
352     storagedaemon::BootStrapRecord* bsr)
353 {
354   int token;
355 
356   token = LexGetToken(lc, BCT_STRING);
357   if (token == BCT_ERROR) { return NULL; }
358   if (!bsr->volume) {
359     Emsg1(M_ERROR, 0, _("MediaType %s in bsr at inappropriate place.\n"),
360           lc->str);
361     return bsr;
362   }
363   storagedaemon::BsrVolume* bv;
364   for (bv = bsr->volume; bv; bv = bv->next) {
365     bstrncpy(bv->MediaType, lc->str, sizeof(bv->MediaType));
366   }
367   return bsr;
368 }
369 
store_nothing(LEX * lc,storagedaemon::BootStrapRecord * bsr)370 static storagedaemon::BootStrapRecord* store_nothing(
371     LEX* lc,
372     storagedaemon::BootStrapRecord* bsr)
373 {
374   int token;
375 
376   token = LexGetToken(lc, BCT_STRING);
377   if (token == BCT_ERROR) { return NULL; }
378   return bsr;
379 }
380 
381 /*
382  * Shove the Device name in each Volume in the current bsr
383  */
StoreDevice(LEX * lc,storagedaemon::BootStrapRecord * bsr)384 static storagedaemon::BootStrapRecord* StoreDevice(
385     LEX* lc,
386     storagedaemon::BootStrapRecord* bsr)
387 {
388   int token;
389 
390   token = LexGetToken(lc, BCT_STRING);
391   if (token == BCT_ERROR) { return NULL; }
392   if (!bsr->volume) {
393     Emsg1(M_ERROR, 0, _("Device \"%s\" in bsr at inappropriate place.\n"),
394           lc->str);
395     return bsr;
396   }
397   storagedaemon::BsrVolume* bv;
398   for (bv = bsr->volume; bv; bv = bv->next) {
399     bstrncpy(bv->device, lc->str, sizeof(bv->device));
400   }
401   return bsr;
402 }
403 
store_client(LEX * lc,storagedaemon::BootStrapRecord * bsr)404 static storagedaemon::BootStrapRecord* store_client(
405     LEX* lc,
406     storagedaemon::BootStrapRecord* bsr)
407 {
408   int token;
409   storagedaemon::BsrClient* client;
410 
411   for (;;) {
412     token = LexGetToken(lc, BCT_NAME);
413     if (token == BCT_ERROR) { return NULL; }
414     client
415         = (storagedaemon::BsrClient*)malloc(sizeof(storagedaemon::BsrClient));
416     memset(client, 0, sizeof(storagedaemon::BsrClient));
417     bstrncpy(client->ClientName, lc->str, sizeof(client->ClientName));
418 
419     /*
420      * Add it to the end of the client chain
421      */
422     if (!bsr->client) {
423       bsr->client = client;
424     } else {
425       storagedaemon::BsrClient* bc = bsr->client;
426       for (; bc->next; bc = bc->next) {}
427       bc->next = client;
428     }
429     token = LexGetToken(lc, BCT_ALL);
430     if (token != BCT_COMMA) { break; }
431   }
432   return bsr;
433 }
434 
store_job(LEX * lc,storagedaemon::BootStrapRecord * bsr)435 static storagedaemon::BootStrapRecord* store_job(
436     LEX* lc,
437     storagedaemon::BootStrapRecord* bsr)
438 {
439   int token;
440   storagedaemon::BsrJob* job;
441 
442   for (;;) {
443     token = LexGetToken(lc, BCT_NAME);
444     if (token == BCT_ERROR) { return NULL; }
445     job = (storagedaemon::BsrJob*)malloc(sizeof(storagedaemon::BsrJob));
446     memset(job, 0, sizeof(storagedaemon::BsrJob));
447     bstrncpy(job->Job, lc->str, sizeof(job->Job));
448 
449     /*
450      * Add it to the end of the client chain
451      */
452     if (!bsr->job) {
453       bsr->job = job;
454     } else {
455       /*
456        * Add to end of chain
457        */
458       storagedaemon::BsrJob* bc = bsr->job;
459       for (; bc->next; bc = bc->next) {}
460       bc->next = job;
461     }
462     token = LexGetToken(lc, BCT_ALL);
463     if (token != BCT_COMMA) { break; }
464   }
465   return bsr;
466 }
467 
store_findex(LEX * lc,storagedaemon::BootStrapRecord * bsr)468 static storagedaemon::BootStrapRecord* store_findex(
469     LEX* lc,
470     storagedaemon::BootStrapRecord* bsr)
471 {
472   int token;
473   storagedaemon::BsrFileIndex* findex;
474 
475   for (;;) {
476     token = LexGetToken(lc, BCT_PINT32_RANGE);
477     if (token == BCT_ERROR) { return NULL; }
478     findex = (storagedaemon::BsrFileIndex*)malloc(
479         sizeof(storagedaemon::BsrFileIndex));
480     memset(findex, 0, sizeof(storagedaemon::BsrFileIndex));
481     findex->findex = lc->u.pint32_val;
482     findex->findex2 = lc->u2.pint32_val;
483 
484     /*
485      * Add it to the end of the chain
486      */
487     if (!bsr->FileIndex) {
488       bsr->FileIndex = findex;
489     } else {
490       /*
491        * Add to end of chain
492        */
493       storagedaemon::BsrFileIndex* bs = bsr->FileIndex;
494       for (; bs->next; bs = bs->next) {}
495       bs->next = findex;
496     }
497     token = LexGetToken(lc, BCT_ALL);
498     if (token != BCT_COMMA) { break; }
499   }
500   return bsr;
501 }
502 
store_jobid(LEX * lc,storagedaemon::BootStrapRecord * bsr)503 static storagedaemon::BootStrapRecord* store_jobid(
504     LEX* lc,
505     storagedaemon::BootStrapRecord* bsr)
506 {
507   int token;
508   storagedaemon::BsrJobid* jobid;
509 
510   for (;;) {
511     token = LexGetToken(lc, BCT_PINT32_RANGE);
512     if (token == BCT_ERROR) { return NULL; }
513     jobid = (storagedaemon::BsrJobid*)malloc(sizeof(storagedaemon::BsrJobid));
514     memset(jobid, 0, sizeof(storagedaemon::BsrJobid));
515     jobid->JobId = lc->u.pint32_val;
516     jobid->JobId2 = lc->u2.pint32_val;
517 
518     /*
519      * Add it to the end of the chain
520      */
521     if (!bsr->JobId) {
522       bsr->JobId = jobid;
523     } else {
524       /*
525        * Add to end of chain
526        */
527       storagedaemon::BsrJobid* bs = bsr->JobId;
528       for (; bs->next; bs = bs->next) {}
529       bs->next = jobid;
530     }
531     token = LexGetToken(lc, BCT_ALL);
532     if (token != BCT_COMMA) { break; }
533   }
534   return bsr;
535 }
536 
store_count(LEX * lc,storagedaemon::BootStrapRecord * bsr)537 static storagedaemon::BootStrapRecord* store_count(
538     LEX* lc,
539     storagedaemon::BootStrapRecord* bsr)
540 {
541   int token;
542 
543   token = LexGetToken(lc, BCT_PINT32);
544   if (token == BCT_ERROR) { return NULL; }
545   bsr->count = lc->u.pint32_val;
546   ScanToEol(lc);
547   return bsr;
548 }
549 
store_fileregex(LEX * lc,storagedaemon::BootStrapRecord * bsr)550 static storagedaemon::BootStrapRecord* store_fileregex(
551     LEX* lc,
552     storagedaemon::BootStrapRecord* bsr)
553 {
554   int token;
555   int rc;
556 
557   token = LexGetToken(lc, BCT_STRING);
558   if (token == BCT_ERROR) { return NULL; }
559 
560   if (bsr->fileregex) free(bsr->fileregex);
561   bsr->fileregex = strdup(lc->str);
562 
563   if (bsr->fileregex_re == NULL) {
564     bsr->fileregex_re = (regex_t*)malloc(sizeof(regex_t));
565   }
566 
567   rc = regcomp(bsr->fileregex_re, bsr->fileregex, REG_EXTENDED | REG_NOSUB);
568   if (rc != 0) {
569     char prbuf[500];
570     regerror(rc, bsr->fileregex_re, prbuf, sizeof(prbuf));
571     Emsg2(M_ERROR, 0, _("REGEX '%s' compile error. ERR=%s\n"), bsr->fileregex,
572           prbuf);
573     return NULL;
574   }
575   return bsr;
576 }
577 
StoreJobtype(LEX * lc,storagedaemon::BootStrapRecord * bsr)578 static storagedaemon::BootStrapRecord* StoreJobtype(
579     LEX* lc,
580     storagedaemon::BootStrapRecord* bsr)
581 {
582   /* *****FIXME****** */
583   Pmsg0(-1, _("JobType not yet implemented\n"));
584   return bsr;
585 }
586 
store_joblevel(LEX * lc,storagedaemon::BootStrapRecord * bsr)587 static storagedaemon::BootStrapRecord* store_joblevel(
588     LEX* lc,
589     storagedaemon::BootStrapRecord* bsr)
590 {
591   /* *****FIXME****** */
592   Pmsg0(-1, _("JobLevel not yet implemented\n"));
593   return bsr;
594 }
595 
596 /*
597  * Routine to handle Volume start/end file
598  */
store_volfile(LEX * lc,storagedaemon::BootStrapRecord * bsr)599 static storagedaemon::BootStrapRecord* store_volfile(
600     LEX* lc,
601     storagedaemon::BootStrapRecord* bsr)
602 {
603   int token;
604   storagedaemon::BsrVolumeFile* volfile;
605 
606   for (;;) {
607     token = LexGetToken(lc, BCT_PINT32_RANGE);
608     if (token == BCT_ERROR) { return NULL; }
609     volfile = (storagedaemon::BsrVolumeFile*)malloc(
610         sizeof(storagedaemon::BsrVolumeFile));
611     memset(volfile, 0, sizeof(storagedaemon::BsrVolumeFile));
612     volfile->sfile = lc->u.pint32_val;
613     volfile->efile = lc->u2.pint32_val;
614 
615     /*
616      * Add it to the end of the chain
617      */
618     if (!bsr->volfile) {
619       bsr->volfile = volfile;
620     } else {
621       /*
622        * Add to end of chain
623        */
624       storagedaemon::BsrVolumeFile* bs = bsr->volfile;
625       for (; bs->next; bs = bs->next) {}
626       bs->next = volfile;
627     }
628     token = LexGetToken(lc, BCT_ALL);
629     if (token != BCT_COMMA) { break; }
630   }
631   return bsr;
632 }
633 
634 /*
635  * Routine to handle Volume start/end Block
636  */
store_volblock(LEX * lc,storagedaemon::BootStrapRecord * bsr)637 static storagedaemon::BootStrapRecord* store_volblock(
638     LEX* lc,
639     storagedaemon::BootStrapRecord* bsr)
640 {
641   int token;
642   storagedaemon::BsrVolumeBlock* volblock;
643 
644   for (;;) {
645     token = LexGetToken(lc, BCT_PINT32_RANGE);
646     if (token == BCT_ERROR) { return NULL; }
647     volblock = (storagedaemon::BsrVolumeBlock*)malloc(
648         sizeof(storagedaemon::BsrVolumeBlock));
649     memset(volblock, 0, sizeof(storagedaemon::BsrVolumeBlock));
650     volblock->sblock = lc->u.pint32_val;
651     volblock->eblock = lc->u2.pint32_val;
652 
653     /*
654      * Add it to the end of the chain
655      */
656     if (!bsr->volblock) {
657       bsr->volblock = volblock;
658     } else {
659       /*
660        * Add to end of chain
661        */
662       storagedaemon::BsrVolumeBlock* bs = bsr->volblock;
663       for (; bs->next; bs = bs->next) {}
664       bs->next = volblock;
665     }
666     token = LexGetToken(lc, BCT_ALL);
667     if (token != BCT_COMMA) { break; }
668   }
669   return bsr;
670 }
671 
672 /*
673  * Routine to handle Volume start/end address
674  */
store_voladdr(LEX * lc,storagedaemon::BootStrapRecord * bsr)675 static storagedaemon::BootStrapRecord* store_voladdr(
676     LEX* lc,
677     storagedaemon::BootStrapRecord* bsr)
678 {
679   int token;
680   storagedaemon::BsrVolumeAddress* voladdr;
681 
682   for (;;) {
683     token = LexGetToken(lc, BCT_PINT64_RANGE);
684     if (token == BCT_ERROR) { return NULL; }
685     voladdr = (storagedaemon::BsrVolumeAddress*)malloc(
686         sizeof(storagedaemon::BsrVolumeAddress));
687     memset(voladdr, 0, sizeof(storagedaemon::BsrVolumeAddress));
688     voladdr->saddr = lc->u.pint64_val;
689     voladdr->eaddr = lc->u2.pint64_val;
690 
691     /*
692      * Add it to the end of the chain
693      */
694     if (!bsr->voladdr) {
695       bsr->voladdr = voladdr;
696     } else {
697       /*
698        * Add to end of chain
699        */
700       storagedaemon::BsrVolumeAddress* bs = bsr->voladdr;
701       for (; bs->next; bs = bs->next) {}
702       bs->next = voladdr;
703     }
704     token = LexGetToken(lc, BCT_ALL);
705     if (token != BCT_COMMA) { break; }
706   }
707   return bsr;
708 }
709 
store_sessid(LEX * lc,storagedaemon::BootStrapRecord * bsr)710 static storagedaemon::BootStrapRecord* store_sessid(
711     LEX* lc,
712     storagedaemon::BootStrapRecord* bsr)
713 {
714   int token;
715   storagedaemon::BsrSessionId* sid;
716 
717   for (;;) {
718     token = LexGetToken(lc, BCT_PINT32_RANGE);
719     if (token == BCT_ERROR) { return NULL; }
720     sid = (storagedaemon::BsrSessionId*)malloc(
721         sizeof(storagedaemon::BsrSessionId));
722     memset(sid, 0, sizeof(storagedaemon::BsrSessionId));
723     sid->sessid = lc->u.pint32_val;
724     sid->sessid2 = lc->u2.pint32_val;
725 
726     /*
727      * Add it to the end of the chain
728      */
729     if (!bsr->sessid) {
730       bsr->sessid = sid;
731     } else {
732       /*
733        * Add to end of chain
734        */
735       storagedaemon::BsrSessionId* bs = bsr->sessid;
736       for (; bs->next; bs = bs->next) {}
737       bs->next = sid;
738     }
739     token = LexGetToken(lc, BCT_ALL);
740     if (token != BCT_COMMA) { break; }
741   }
742   return bsr;
743 }
744 
store_sesstime(LEX * lc,storagedaemon::BootStrapRecord * bsr)745 static storagedaemon::BootStrapRecord* store_sesstime(
746     LEX* lc,
747     storagedaemon::BootStrapRecord* bsr)
748 {
749   int token;
750   storagedaemon::BsrSessionTime* stime;
751 
752   for (;;) {
753     token = LexGetToken(lc, BCT_PINT32);
754     if (token == BCT_ERROR) { return NULL; }
755     stime = (storagedaemon::BsrSessionTime*)malloc(
756         sizeof(storagedaemon::BsrSessionTime));
757     memset(stime, 0, sizeof(storagedaemon::BsrSessionTime));
758     stime->sesstime = lc->u.pint32_val;
759 
760     /*
761      * Add it to the end of the chain
762      */
763     if (!bsr->sesstime) {
764       bsr->sesstime = stime;
765     } else {
766       /*
767        * Add to end of chain
768        */
769       storagedaemon::BsrSessionTime* bs = bsr->sesstime;
770       for (; bs->next; bs = bs->next) {}
771       bs->next = stime;
772     }
773     token = LexGetToken(lc, BCT_ALL);
774     if (token != BCT_COMMA) { break; }
775   }
776   return bsr;
777 }
778 
store_stream(LEX * lc,storagedaemon::BootStrapRecord * bsr)779 static storagedaemon::BootStrapRecord* store_stream(
780     LEX* lc,
781     storagedaemon::BootStrapRecord* bsr)
782 {
783   int token;
784   storagedaemon::BsrStream* stream;
785 
786   for (;;) {
787     token = LexGetToken(lc, BCT_INT32);
788     if (token == BCT_ERROR) { return NULL; }
789     stream
790         = (storagedaemon::BsrStream*)malloc(sizeof(storagedaemon::BsrStream));
791     memset(stream, 0, sizeof(storagedaemon::BsrStream));
792     stream->stream = lc->u.int32_val;
793 
794     /*
795      * Add it to the end of the chain
796      */
797     if (!bsr->stream) {
798       bsr->stream = stream;
799     } else {
800       /*
801        * Add to end of chain
802        */
803       storagedaemon::BsrStream* bs = bsr->stream;
804       for (; bs->next; bs = bs->next) {}
805       bs->next = stream;
806     }
807     token = LexGetToken(lc, BCT_ALL);
808     if (token != BCT_COMMA) { break; }
809   }
810   return bsr;
811 }
812 
store_slot(LEX * lc,storagedaemon::BootStrapRecord * bsr)813 static storagedaemon::BootStrapRecord* store_slot(
814     LEX* lc,
815     storagedaemon::BootStrapRecord* bsr)
816 {
817   int token;
818 
819   token = LexGetToken(lc, BCT_PINT32);
820   if (token == BCT_ERROR) { return NULL; }
821   if (!bsr->volume) {
822     Emsg1(M_ERROR, 0, _("Slot %d in bsr at inappropriate place.\n"),
823           lc->u.pint32_val);
824     return bsr;
825   }
826   bsr->volume->Slot = lc->u.pint32_val;
827   ScanToEol(lc);
828   return bsr;
829 }
830 
store_include(LEX * lc,storagedaemon::BootStrapRecord * bsr)831 static storagedaemon::BootStrapRecord* store_include(
832     LEX* lc,
833     storagedaemon::BootStrapRecord* bsr)
834 {
835   ScanToEol(lc);
836   return bsr;
837 }
838 
store_exclude(LEX * lc,storagedaemon::BootStrapRecord * bsr)839 static storagedaemon::BootStrapRecord* store_exclude(
840     LEX* lc,
841     storagedaemon::BootStrapRecord* bsr)
842 {
843   ScanToEol(lc);
844   return bsr;
845 }
846 
DumpVolfile(storagedaemon::BsrVolumeFile * volfile)847 static inline void DumpVolfile(storagedaemon::BsrVolumeFile* volfile)
848 {
849   if (volfile) {
850     Pmsg2(-1, _("VolFile     : %u-%u\n"), volfile->sfile, volfile->efile);
851     DumpVolfile(volfile->next);
852   }
853 }
854 
DumpVolblock(storagedaemon::BsrVolumeBlock * volblock)855 static inline void DumpVolblock(storagedaemon::BsrVolumeBlock* volblock)
856 {
857   if (volblock) {
858     Pmsg2(-1, _("VolBlock    : %u-%u\n"), volblock->sblock, volblock->eblock);
859     DumpVolblock(volblock->next);
860   }
861 }
862 
DumpVoladdr(storagedaemon::BsrVolumeAddress * voladdr)863 static inline void DumpVoladdr(storagedaemon::BsrVolumeAddress* voladdr)
864 {
865   if (voladdr) {
866     Pmsg2(-1, _("VolAddr    : %llu-%llu\n"), voladdr->saddr, voladdr->eaddr);
867     DumpVoladdr(voladdr->next);
868   }
869 }
870 
DumpFindex(storagedaemon::BsrFileIndex * FileIndex)871 static inline void DumpFindex(storagedaemon::BsrFileIndex* FileIndex)
872 {
873   if (FileIndex) {
874     if (FileIndex->findex == FileIndex->findex2) {
875       Pmsg1(-1, _("FileIndex   : %u\n"), FileIndex->findex);
876     } else {
877       Pmsg2(-1, _("FileIndex   : %u-%u\n"), FileIndex->findex,
878             FileIndex->findex2);
879     }
880     DumpFindex(FileIndex->next);
881   }
882 }
883 
DumpJobid(storagedaemon::BsrJobid * jobid)884 static inline void DumpJobid(storagedaemon::BsrJobid* jobid)
885 {
886   if (jobid) {
887     if (jobid->JobId == jobid->JobId2) {
888       Pmsg1(-1, _("JobId       : %u\n"), jobid->JobId);
889     } else {
890       Pmsg2(-1, _("JobId       : %u-%u\n"), jobid->JobId, jobid->JobId2);
891     }
892     DumpJobid(jobid->next);
893   }
894 }
895 
DumpSessid(storagedaemon::BsrSessionId * sessid)896 static inline void DumpSessid(storagedaemon::BsrSessionId* sessid)
897 {
898   if (sessid) {
899     if (sessid->sessid == sessid->sessid2) {
900       Pmsg1(-1, _("SessId      : %u\n"), sessid->sessid);
901     } else {
902       Pmsg2(-1, _("SessId      : %u-%u\n"), sessid->sessid, sessid->sessid2);
903     }
904     DumpSessid(sessid->next);
905   }
906 }
907 
DumpVolume(storagedaemon::BsrVolume * volume)908 static inline void DumpVolume(storagedaemon::BsrVolume* volume)
909 {
910   if (volume) {
911     Pmsg1(-1, _("VolumeName  : %s\n"), volume->VolumeName);
912     Pmsg1(-1, _("  MediaType : %s\n"), volume->MediaType);
913     Pmsg1(-1, _("  Device    : %s\n"), volume->device);
914     Pmsg1(-1, _("  Slot      : %d\n"), volume->Slot);
915     DumpVolume(volume->next);
916   }
917 }
918 
DumpClient(storagedaemon::BsrClient * client)919 static inline void DumpClient(storagedaemon::BsrClient* client)
920 {
921   if (client) {
922     Pmsg1(-1, _("Client      : %s\n"), client->ClientName);
923     DumpClient(client->next);
924   }
925 }
926 
dump_job(storagedaemon::BsrJob * job)927 static inline void dump_job(storagedaemon::BsrJob* job)
928 {
929   if (job) {
930     Pmsg1(-1, _("Job          : %s\n"), job->Job);
931     dump_job(job->next);
932   }
933 }
934 
DumpSesstime(storagedaemon::BsrSessionTime * sesstime)935 static inline void DumpSesstime(storagedaemon::BsrSessionTime* sesstime)
936 {
937   if (sesstime) {
938     Pmsg1(-1, _("SessTime    : %u\n"), sesstime->sesstime);
939     DumpSesstime(sesstime->next);
940   }
941 }
942 
DumpBsr(storagedaemon::BootStrapRecord * bsr,bool recurse)943 void DumpBsr(storagedaemon::BootStrapRecord* bsr, bool recurse)
944 {
945   int save_debug = debug_level;
946   debug_level = 1;
947   if (!bsr) {
948     Pmsg0(-1, _("storagedaemon::BootStrapRecord is NULL\n"));
949     debug_level = save_debug;
950     return;
951   }
952   Pmsg1(-1, _("Next        : 0x%x\n"), bsr->next);
953   Pmsg1(-1, _("Root bsr    : 0x%x\n"), bsr->root);
954   DumpVolume(bsr->volume);
955   DumpSessid(bsr->sessid);
956   DumpSesstime(bsr->sesstime);
957   DumpVolfile(bsr->volfile);
958   DumpVolblock(bsr->volblock);
959   DumpVoladdr(bsr->voladdr);
960   DumpClient(bsr->client);
961   DumpJobid(bsr->JobId);
962   dump_job(bsr->job);
963   DumpFindex(bsr->FileIndex);
964   if (bsr->count) {
965     Pmsg1(-1, _("count       : %u\n"), bsr->count);
966     Pmsg1(-1, _("found       : %u\n"), bsr->found);
967   }
968 
969   Pmsg1(-1, _("done        : %s\n"), bsr->done ? _("yes") : _("no"));
970   Pmsg1(-1, _("positioning : %d\n"), bsr->use_positioning);
971   Pmsg1(-1, _("fast_reject : %d\n"), bsr->use_fast_rejection);
972   if (recurse && bsr->next) {
973     Pmsg0(-1, "\n");
974     DumpBsr(bsr->next, true);
975   }
976   debug_level = save_debug;
977 }
978 
979 /*
980  * Free bsr resources
981  */
FreeBsrItem(storagedaemon::BootStrapRecord * bsr)982 static inline void FreeBsrItem(storagedaemon::BootStrapRecord* bsr)
983 {
984   if (bsr) {
985     FreeBsrItem(bsr->next);
986     free(bsr);
987   }
988 }
989 
990 /*
991  * Remove a single item from the bsr tree
992  */
RemoveBsr(storagedaemon::BootStrapRecord * bsr)993 static inline void RemoveBsr(storagedaemon::BootStrapRecord* bsr)
994 {
995   FreeBsrItem((storagedaemon::BootStrapRecord*)bsr->volume);
996   FreeBsrItem((storagedaemon::BootStrapRecord*)bsr->client);
997   FreeBsrItem((storagedaemon::BootStrapRecord*)bsr->sessid);
998   FreeBsrItem((storagedaemon::BootStrapRecord*)bsr->sesstime);
999   FreeBsrItem((storagedaemon::BootStrapRecord*)bsr->volfile);
1000   FreeBsrItem((storagedaemon::BootStrapRecord*)bsr->volblock);
1001   FreeBsrItem((storagedaemon::BootStrapRecord*)bsr->voladdr);
1002   FreeBsrItem((storagedaemon::BootStrapRecord*)bsr->JobId);
1003   FreeBsrItem((storagedaemon::BootStrapRecord*)bsr->job);
1004   FreeBsrItem((storagedaemon::BootStrapRecord*)bsr->FileIndex);
1005   FreeBsrItem((storagedaemon::BootStrapRecord*)bsr->JobType);
1006   FreeBsrItem((storagedaemon::BootStrapRecord*)bsr->JobLevel);
1007   if (bsr->fileregex) { free(bsr->fileregex); }
1008   if (bsr->fileregex_re) {
1009     regfree(bsr->fileregex_re);
1010     free(bsr->fileregex_re);
1011   }
1012   if (bsr->attr) { FreeAttr(bsr->attr); }
1013   if (bsr->next) { bsr->next->prev = bsr->prev; }
1014   if (bsr->prev) { bsr->prev->next = bsr->next; }
1015   free(bsr);
1016 }
1017 
1018 /*
1019  * Free all bsrs in chain
1020  */
FreeBsr(storagedaemon::BootStrapRecord * bsr)1021 void FreeBsr(storagedaemon::BootStrapRecord* bsr)
1022 {
1023   storagedaemon::BootStrapRecord* next_bsr;
1024 
1025   if (!bsr) { return; }
1026   next_bsr = bsr->next;
1027 
1028   /*
1029    * Remove (free) current bsr
1030    */
1031   RemoveBsr(bsr);
1032 
1033   /*
1034    * Now get the next one
1035    */
1036   FreeBsr(next_bsr);
1037 }
1038 
1039 } /* namespace libbareos */
1040