]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/parse_conf.c
41177e10479a36d0b293e535e1089f74386a477c
[bacula/bacula] / bacula / src / lib / parse_conf.c
1 /*
2  *   Master Configuration routines.
3  *
4  *   This file contains the common parts of the Bacula
5  *   configuration routines.
6  *
7  *   Note, the configuration file parser consists of three parts
8  *
9  *   1. The generic lexical scanner in lib/lex.c and lib/lex.h
10  *
11  *   2. The generic config  scanner in lib/parse_conf.c and
12  *      lib/parse_conf.h.
13  *      These files contain the parser code, some utility
14  *      routines, and the common store routines (name, int,
15  *      string, time, int64, size, ...).
16  *
17  *   3. The daemon specific file, which contains the Resource
18  *      definitions as well as any specific store routines
19  *      for the resource records.
20  *
21  *    N.B. This is a two pass parser, so if you malloc() a string
22  *         in a "store" routine, you must ensure to do it during
23  *         only one of the two passes, or to free it between.
24  *         Also, note that the resource record is malloced and
25  *         saved in save_resource() during pass 1.  Anything that
26  *         you want saved after pass two (e.g. resource pointers)
27  *         must explicitly be done in save_resource. Take a look
28  *         at the Job resource in src/dird/dird_conf.c to see how
29  *         it is done.
30  *
31  *     Kern Sibbald, January MM
32  *
33  *   Version $Id$
34  */
35 /*
36    Copyright (C) 2000-2005 Kern Sibbald
37
38    This program is free software; you can redistribute it and/or
39    modify it under the terms of the GNU General Public License
40    version 2 as ammended with additional clauses defined in the
41    file LICENSE in the main source directory.
42
43    This program is distributed in the hope that it will be useful,
44    but WITHOUT ANY WARRANTY; without even the implied warranty of
45    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
46    the file LICENSE for additional details.
47
48  */
49
50
51 #include "bacula.h"
52
53 extern int debug_level;
54
55 /* Each daemon has a slightly different set of
56  * resources, so it will define the following
57  * global values.
58  */
59 extern int r_first;
60 extern int r_last;
61 extern RES_TABLE resources[];
62 extern RES **res_head;
63
64 #ifdef HAVE_WIN32
65 // work around visual studio name manling preventing external linkage since res_all
66 // is declared as a different type when instantiated.
67 extern "C" CURES res_all;
68 extern "C" int res_all_size;
69 #else
70 extern  CURES res_all;
71 extern int res_all_size;
72 #endif
73
74 extern brwlock_t res_lock;            /* resource lock */
75
76
77 /* Forward referenced subroutines */
78 static void scan_types(LEX *lc, MSGS *msg, int dest, char *where, char *cmd);
79
80
81 /* Common Resource definitions */
82
83 /* Message resource directives
84  *  name         handler      value       code   flags  default_value
85  */
86 RES_ITEM msgs_items[] = {
87    {"name",        store_name,    ITEM(res_msgs.hdr.name),  0, 0, 0},
88    {"description", store_str,     ITEM(res_msgs.hdr.desc),  0, 0, 0},
89    {"mailcommand", store_str,     ITEM(res_msgs.mail_cmd),  0, 0, 0},
90    {"operatorcommand", store_str, ITEM(res_msgs.operator_cmd), 0, 0, 0},
91    {"syslog",      store_msgs, ITEM(res_msgs), MD_SYSLOG,   0, 0},
92    {"mail",        store_msgs, ITEM(res_msgs), MD_MAIL,     0, 0},
93    {"mailonerror", store_msgs, ITEM(res_msgs), MD_MAIL_ON_ERROR, 0, 0},
94    {"file",        store_msgs, ITEM(res_msgs), MD_FILE,     0, 0},
95    {"append",      store_msgs, ITEM(res_msgs), MD_APPEND,   0, 0},
96    {"stdout",      store_msgs, ITEM(res_msgs), MD_STDOUT,   0, 0},
97    {"stderr",      store_msgs, ITEM(res_msgs), MD_STDERR,   0, 0},
98    {"director",    store_msgs, ITEM(res_msgs), MD_DIRECTOR, 0, 0},
99    {"console",     store_msgs, ITEM(res_msgs), MD_CONSOLE,  0, 0},
100    {"operator",    store_msgs, ITEM(res_msgs), MD_OPERATOR, 0, 0},
101    {NULL, NULL,    NULL,       0,              0}
102 };
103
104 struct s_mtypes {
105    const char *name;
106    int token;
107 };
108 /* Various message types */
109 static struct s_mtypes msg_types[] = {
110    {"debug",         M_DEBUG},
111    {"abort",         M_ABORT},
112    {"fatal",         M_FATAL},
113    {"error",         M_ERROR},
114    {"warning",       M_WARNING},
115    {"info",          M_INFO},
116    {"saved",         M_SAVED},
117    {"notsaved",      M_NOTSAVED},
118    {"skipped",       M_SKIPPED},
119    {"mount",         M_MOUNT},
120    {"terminate",     M_TERM},
121    {"restored",      M_RESTORED},
122    {"security",      M_SECURITY},
123    {"alert",         M_ALERT},
124    {"all",           M_MAX+1},
125    {NULL,            0}
126 };
127
128 /* Used for certain KeyWord tables */
129 struct s_kw {
130    const char *name;
131    int token;
132 };
133
134 /*
135  * Tape Label types permitted in Pool records 
136  *
137  *   tape label      label code = token
138  */
139 struct s_kw tapelabels[] = {
140    {"bacula",        B_BACULA_LABEL},
141    {"ansi",          B_ANSI_LABEL},
142    {"ibm",           B_IBM_LABEL},
143    {NULL,            0}
144 };
145
146
147 /* Simply print a message */
148 static void prtmsg(void *sock, const char *fmt, ...)
149 {
150    va_list arg_ptr;
151
152    va_start(arg_ptr, fmt);
153    vfprintf(stdout, fmt, arg_ptr);
154    va_end(arg_ptr);
155 }
156
157 const char *res_to_str(int rcode)
158 {
159    if (rcode < r_first || rcode > r_last) {
160       return _("***UNKNOWN***");
161    } else {
162       return resources[rcode-r_first].name;
163    }
164 }
165
166
167 /*
168  * Initialize the static structure to zeros, then
169  *  apply all the default values.
170  */
171 void init_resource(int type, RES_ITEM *items, int pass)
172 {
173    int i;
174    int rindex = type - r_first;
175    static bool first = true;
176    int errstat;
177
178    if (first && (errstat=rwl_init(&res_lock)) != 0) {
179       Emsg1(M_ABORT, 0, _("Unable to initialize resource lock. ERR=%s\n"),
180             strerror(errstat));
181    }
182    first = false;
183
184    memset(&res_all, 0, res_all_size);
185    res_all.hdr.rcode = type;
186    res_all.hdr.refcnt = 1;
187
188    for (i=0; items[i].name; i++) {
189       Dmsg3(900, "Item=%s def=%s defval=%d\n", items[i].name,
190             (items[i].flags & ITEM_DEFAULT) ? "yes" : "no",
191             items[i].default_value);
192       if (items[i].flags & ITEM_DEFAULT && items[i].default_value != 0) {
193          if (items[i].handler == store_yesno) {
194             *(int *)(items[i].value) |= items[i].code;
195          } else if (items[i].handler == store_pint ||
196                     items[i].handler == store_int) {
197             *(int *)(items[i].value) = items[i].default_value;
198          } else if (items[i].handler == store_int64) {
199             *(int64_t *)(items[i].value) = items[i].default_value;
200          } else if (items[i].handler == store_size) {
201             *(uint64_t *)(items[i].value) = (uint64_t)items[i].default_value;
202          } else if (items[i].handler == store_time) {
203             *(utime_t *)(items[i].value) = (utime_t)items[i].default_value;
204          } else if (pass == 1 && items[i].handler == store_addresses) {
205             init_default_addresses((dlist**)items[i].value, items[i].default_value);
206          }
207       }
208       /* If this triggers, take a look at lib/parse_conf.h */
209       if (i >= MAX_RES_ITEMS) {
210          Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
211       }
212    }
213 }
214
215
216 /* Store Messages Destination information */
217 void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass)
218 {
219    int token;
220    char *cmd;
221    POOLMEM *dest;
222    int dest_len;
223
224    Dmsg2(900, "store_msgs pass=%d code=%d\n", pass, item->code);
225    if (pass == 1) {
226       switch (item->code) {
227       case MD_STDOUT:
228       case MD_STDERR:
229       case MD_SYSLOG:              /* syslog */
230       case MD_CONSOLE:
231          scan_types(lc, (MSGS *)(item->value), item->code, NULL, NULL);
232          break;
233       case MD_OPERATOR:            /* send to operator */
234       case MD_DIRECTOR:            /* send to Director */
235       case MD_MAIL:                /* mail */
236       case MD_MAIL_ON_ERROR:       /* mail if Job errors */
237          if (item->code == MD_OPERATOR) {
238             cmd = res_all.res_msgs.operator_cmd;
239          } else {
240             cmd = res_all.res_msgs.mail_cmd;
241          }
242          dest = get_pool_memory(PM_MESSAGE);
243          dest[0] = 0;
244          dest_len = 0;
245          /* Pick up comma separated list of destinations */
246          for ( ;; ) {
247             token = lex_get_token(lc, T_NAME);   /* scan destination */
248             dest = check_pool_memory_size(dest, dest_len + lc->str_len + 2);
249             if (dest[0] != 0) {
250                pm_strcat(dest, " ");  /* separate multiple destinations with space */
251                dest_len++;
252             }
253             pm_strcat(dest, lc->str);
254             dest_len += lc->str_len;
255             Dmsg2(900, "store_msgs newdest=%s: dest=%s:\n", lc->str, NPRT(dest));
256             token = lex_get_token(lc, T_SKIP_EOL);
257             if (token == T_COMMA) {
258                continue;           /* get another destination */
259             }
260             if (token != T_EQUALS) {
261                scan_err1(lc, _("expected an =, got: %s"), lc->str);
262             }
263             break;
264          }
265          Dmsg1(900, "mail_cmd=%s\n", NPRT(cmd));
266          scan_types(lc, (MSGS *)(item->value), item->code, dest, cmd);
267          free_pool_memory(dest);
268          Dmsg0(900, "done with dest codes\n");
269          break;
270       case MD_FILE:                /* file */
271       case MD_APPEND:              /* append */
272          dest = get_pool_memory(PM_MESSAGE);
273          /* Pick up a single destination */
274          token = lex_get_token(lc, T_NAME);   /* scan destination */
275          pm_strcpy(dest, lc->str);
276          dest_len = lc->str_len;
277          token = lex_get_token(lc, T_SKIP_EOL);
278          Dmsg1(900, "store_msgs dest=%s:\n", NPRT(dest));
279          if (token != T_EQUALS) {
280             scan_err1(lc, _("expected an =, got: %s"), lc->str);
281          }
282          scan_types(lc, (MSGS *)(item->value), item->code, dest, NULL);
283          free_pool_memory(dest);
284          Dmsg0(900, "done with dest codes\n");
285          break;
286
287       default:
288          scan_err1(lc, _("Unknown item code: %d\n"), item->code);
289          break;
290       }
291    }
292    scan_to_eol(lc);
293    set_bit(index, res_all.hdr.item_present);
294    Dmsg0(900, "Done store_msgs\n");
295 }
296
297 /*
298  * Scan for message types and add them to the message
299  * destination. The basic job here is to connect message types
300  *  (WARNING, ERROR, FATAL, INFO, ...) with an appropriate
301  *  destination (MAIL, FILE, OPERATOR, ...)
302  */
303 static void scan_types(LEX *lc, MSGS *msg, int dest_code, char *where, char *cmd)
304 {
305    int i, found, quit, is_not;
306    int msg_type = 0;
307    char *str;
308
309    for (quit=0; !quit;) {
310       lex_get_token(lc, T_NAME);            /* expect at least one type */
311       found = FALSE;
312       if (lc->str[0] == '!') {
313          is_not = TRUE;
314          str = &lc->str[1];
315       } else {
316          is_not = FALSE;
317          str = &lc->str[0];
318       }
319       for (i=0; msg_types[i].name; i++) {
320          if (strcasecmp(str, msg_types[i].name) == 0) {
321             msg_type = msg_types[i].token;
322             found = TRUE;
323             break;
324          }
325       }
326       if (!found) {
327          scan_err1(lc, _("message type: %s not found"), str);
328          /* NOT REACHED */
329       }
330
331       if (msg_type == M_MAX+1) {         /* all? */
332          for (i=1; i<=M_MAX; i++) {      /* yes set all types */
333             add_msg_dest(msg, dest_code, i, where, cmd);
334          }
335       } else {
336          if (is_not) {
337             rem_msg_dest(msg, dest_code, msg_type, where);
338          } else {
339             add_msg_dest(msg, dest_code, msg_type, where, cmd);
340          }
341       }
342       if (lc->ch != ',') {
343          break;
344       }
345       Dmsg0(900, "call lex_get_token() to eat comma\n");
346       lex_get_token(lc, T_ALL);          /* eat comma */
347    }
348    Dmsg0(900, "Done scan_types()\n");
349 }
350
351
352 /*
353  * This routine is ONLY for resource names
354  *  Store a name at specified address.
355  */
356 void store_name(LEX *lc, RES_ITEM *item, int index, int pass)
357 {
358    POOLMEM *msg = get_pool_memory(PM_EMSG);
359    lex_get_token(lc, T_NAME);
360    if (!is_name_valid(lc->str, &msg)) {
361       scan_err1(lc, "%s\n", msg);
362    }
363    free_pool_memory(msg);
364    /* Store the name both pass 1 and pass 2 */
365    if (*(item->value)) {
366       scan_err2(lc, _("Attempt to redefine name \"%s\" to \"%s\"."),
367          *(item->value), lc->str);
368    }
369    *(item->value) = bstrdup(lc->str);
370    scan_to_eol(lc);
371    set_bit(index, res_all.hdr.item_present);
372 }
373
374
375 /*
376  * Store a name string at specified address
377  * A name string is limited to MAX_RES_NAME_LENGTH
378  */
379 void store_strname(LEX *lc, RES_ITEM *item, int index, int pass)
380 {
381    lex_get_token(lc, T_NAME);
382    /* Store the name */
383    if (pass == 1) {
384       *(item->value) = bstrdup(lc->str);
385    }
386    scan_to_eol(lc);
387    set_bit(index, res_all.hdr.item_present);
388 }
389
390 /* Store a string at specified address */
391 void store_str(LEX *lc, RES_ITEM *item, int index, int pass)
392 {
393    lex_get_token(lc, T_STRING);
394    if (pass == 1) {
395       *(item->value) = bstrdup(lc->str);
396    }
397    scan_to_eol(lc);
398    set_bit(index, res_all.hdr.item_present);
399 }
400
401 /*
402  * Store a directory name at specified address. Note, we do
403  *   shell expansion except if the string begins with a vertical
404  *   bar (i.e. it will likely be passed to the shell later).
405  */
406 void store_dir(LEX *lc, RES_ITEM *item, int index, int pass)
407 {
408    lex_get_token(lc, T_STRING);
409    if (pass == 1) {
410       if (lc->str[0] != '|') {
411          do_shell_expansion(lc->str, sizeof(lc->str));
412       }
413       *(item->value) = bstrdup(lc->str);
414    }
415    scan_to_eol(lc);
416    set_bit(index, res_all.hdr.item_present);
417 }
418
419
420 /* Store a password specified address in MD5 coding */
421 void store_password(LEX *lc, RES_ITEM *item, int index, int pass)
422 {
423    unsigned int i, j;
424    struct MD5Context md5c;
425    unsigned char signature[16];
426    char sig[100];
427
428
429    lex_get_token(lc, T_STRING);
430    if (pass == 1) {
431       MD5Init(&md5c);
432       MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
433       MD5Final(signature, &md5c);
434       for (i = j = 0; i < sizeof(signature); i++) {
435          sprintf(&sig[j], "%02x", signature[i]);
436          j += 2;
437       }
438       *(item->value) = bstrdup(sig);
439    }
440    scan_to_eol(lc);
441    set_bit(index, res_all.hdr.item_present);
442 }
443
444
445 /* Store a resource at specified address.
446  * If we are in pass 2, do a lookup of the
447  * resource.
448  */
449 void store_res(LEX *lc, RES_ITEM *item, int index, int pass)
450 {
451    RES *res;
452
453    lex_get_token(lc, T_NAME);
454    if (pass == 2) {
455       res = GetResWithName(item->code, lc->str);
456       if (res == NULL) {
457          scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
458             lc->str, lc->line_no, lc->line);
459       }
460       if (*(item->value)) {
461          scan_err3(lc, _("Attempt to redefine resource \"%s\" referenced on line %d : %s\n"),
462             item->name, lc->line_no, lc->line);
463       }
464       *(item->value) = (char *)res;
465    }
466    scan_to_eol(lc);
467    set_bit(index, res_all.hdr.item_present);
468 }
469
470 /*
471  * Store a resource pointer in an alist. default_value indicates how many
472  *   times this routine can be called -- i.e. how many alists
473  *   there are.
474  * If we are in pass 2, do a lookup of the
475  *   resource.
476  */
477 void store_alist_res(LEX *lc, RES_ITEM *item, int index, int pass)
478 {
479    RES *res;
480    int count = item->default_value;
481    int i = 0;
482    alist *list;
483
484    if (pass == 2) {
485       if (count == 0) {               /* always store in item->value */
486          i = 0;
487          if ((item->value)[i] == NULL) {
488             list = New(alist(10, not_owned_by_alist));
489          } else {
490             list = (alist *)(item->value)[i];
491          }
492       } else {
493          /* Find empty place to store this directive */
494          while ((item->value)[i] != NULL && i++ < count) { }
495          if (i >= count) {
496             scan_err4(lc, _("Too many %s directives. Max. is %d. line %d: %s\n"),
497                lc->str, count, lc->line_no, lc->line);
498          }
499          list = New(alist(10, not_owned_by_alist));
500       }
501
502       for (;;) {
503          lex_get_token(lc, T_NAME);   /* scan next item */
504          res = GetResWithName(item->code, lc->str);
505          if (res == NULL) {
506             scan_err3(lc, _("Could not find config Resource \"%s\" referenced on line %d : %s\n"),
507                item->name, lc->line_no, lc->line);
508          }
509          Dmsg5(900, "Append %p to alist %p size=%d i=%d %s\n", 
510                res, list, list->size(), i, item->name);
511          list->append(res);
512          (item->value)[i] = (char *)list;
513          if (lc->ch != ',') {         /* if no other item follows */
514             break;                    /* get out */
515          }
516          lex_get_token(lc, T_ALL);    /* eat comma */
517       }
518    }
519    scan_to_eol(lc);
520    set_bit(index, res_all.hdr.item_present);
521 }
522
523
524 /*
525  * Store a string in an alist.
526  */
527 void store_alist_str(LEX *lc, RES_ITEM *item, int index, int pass)
528 {
529    alist *list;
530
531    if (pass == 2) {
532       if (*(item->value) == NULL) {
533          list = New(alist(10, owned_by_alist));
534       } else {
535          list = (alist *)(*(item->value));    
536       }
537
538       lex_get_token(lc, T_STRING);   /* scan next item */
539       Dmsg4(900, "Append %s to alist %p size=%d %s\n", 
540          lc->str, list, list->size(), item->name);
541       list->append(bstrdup(lc->str));
542       *(item->value) = (char *)list;
543    }
544    scan_to_eol(lc);
545    set_bit(index, res_all.hdr.item_present);
546 }
547
548
549
550 /*
551  * Store default values for Resource from xxxDefs
552  * If we are in pass 2, do a lookup of the
553  * resource and store everything not explicitly set
554  * in main resource.
555  *
556  * Note, here item points to the main resource (e.g. Job, not
557  *  the jobdefs, which we look up).
558  */
559 void store_defs(LEX *lc, RES_ITEM *item, int index, int pass)
560 {
561    RES *res;
562
563    lex_get_token(lc, T_NAME);
564    if (pass == 2) {
565      Dmsg2(900, "Code=%d name=%s\n", item->code, lc->str);
566      res = GetResWithName(item->code, lc->str);
567      if (res == NULL) {
568         scan_err3(lc, _("Missing config Resource \"%s\" referenced on line %d : %s\n"),
569            lc->str, lc->line_no, lc->line);
570      }
571      /* for each item not set, we copy the field from res */
572 #ifdef xxx
573      for (int i=0; item->name;; i++, item++) {
574         if (bit_is_set(i, res->item_present)) {
575            Dmsg2(900, "Item %d is present in %s\n", i, res->name);
576         } else {
577            Dmsg2(900, "Item %d is not present in %s\n", i, res->name);
578         }
579      }
580      /* ***FIXME **** add code */
581 #endif
582    }
583    scan_to_eol(lc);
584 }
585
586
587
588 /* Store an integer at specified address */
589 void store_int(LEX *lc, RES_ITEM *item, int index, int pass)
590 {
591    lex_get_token(lc, T_INT32);
592    *(int *)(item->value) = lc->int32_val;
593    scan_to_eol(lc);
594    set_bit(index, res_all.hdr.item_present);
595 }
596
597 /* Store a positive integer at specified address */
598 void store_pint(LEX *lc, RES_ITEM *item, int index, int pass)
599 {
600    lex_get_token(lc, T_PINT32);
601    *(int *)(item->value) = lc->pint32_val;
602    scan_to_eol(lc);
603    set_bit(index, res_all.hdr.item_present);
604 }
605
606
607 /* Store an 64 bit integer at specified address */
608 void store_int64(LEX *lc, RES_ITEM *item, int index, int pass)
609 {
610    lex_get_token(lc, T_INT64);
611    *(int64_t *)(item->value) = lc->int64_val;
612    scan_to_eol(lc);
613    set_bit(index, res_all.hdr.item_present);
614 }
615
616 /* Store a size in bytes */
617 void store_size(LEX *lc, RES_ITEM *item, int index, int pass)
618 {
619    int token;
620    uint64_t uvalue;
621    char bsize[500];
622
623    Dmsg0(900, "Enter store_size\n");
624    token = lex_get_token(lc, T_SKIP_EOL);
625    errno = 0;
626    switch (token) {
627    case T_NUMBER:
628    case T_IDENTIFIER:
629    case T_UNQUOTED_STRING:
630       bstrncpy(bsize, lc->str, sizeof(bsize));  /* save first part */
631       /* if terminated by space, scan and get modifier */
632       if (lc->ch == ' ') {
633          token = lex_get_token(lc, T_ALL);
634          switch (token) {
635          case T_IDENTIFIER:
636          case T_UNQUOTED_STRING:
637             bstrncat(bsize, lc->str, sizeof(bsize));
638             break;
639          }
640       }
641       if (!size_to_uint64(bsize, strlen(bsize), &uvalue)) {
642          scan_err1(lc, _("expected a size number, got: %s"), lc->str);
643       }
644       *(uint64_t *)(item->value) = uvalue;
645       break;
646    default:
647       scan_err1(lc, _("expected a size, got: %s"), lc->str);
648       break;
649    }
650    scan_to_eol(lc);
651    set_bit(index, res_all.hdr.item_present);
652    Dmsg0(900, "Leave store_size\n");
653 }
654
655
656 /* Store a time period in seconds */
657 void store_time(LEX *lc, RES_ITEM *item, int index, int pass)
658 {
659    int token;
660    utime_t utime;
661    char period[500];
662
663    token = lex_get_token(lc, T_SKIP_EOL);
664    errno = 0;
665    switch (token) {
666    case T_NUMBER:
667    case T_IDENTIFIER:
668    case T_UNQUOTED_STRING:
669       bstrncpy(period, lc->str, sizeof(period));  /* get first part */
670       /* if terminated by space, scan and get modifier */
671       if (lc->ch == ' ') {
672          token = lex_get_token(lc, T_ALL);
673          switch (token) {
674          case T_IDENTIFIER:
675          case T_UNQUOTED_STRING:
676             bstrncat(period, lc->str, sizeof(period));
677             break;
678          }
679       }
680       if (!duration_to_utime(period, &utime)) {
681          scan_err1(lc, _("expected a time period, got: %s"), period);
682       }
683       *(utime_t *)(item->value) = utime;
684       break;
685    default:
686       scan_err1(lc, _("expected a time period, got: %s"), lc->str);
687       break;
688    }
689    if (token != T_EOL) {
690       scan_to_eol(lc);
691    }
692    set_bit(index, res_all.hdr.item_present);
693 }
694
695
696 /* Store a yes/no in a bit field */
697 void store_yesno(LEX *lc, RES_ITEM *item, int index, int pass)
698 {
699    lex_get_token(lc, T_NAME);
700    if (strcasecmp(lc->str, "yes") == 0) {
701       *(int *)(item->value) |= item->code;
702    } else if (strcasecmp(lc->str, "no") == 0) {
703       *(int *)(item->value) &= ~(item->code);
704    } else {
705       scan_err1(lc, _("Expect a YES or NO, got: %s"), lc->str);
706    }
707    scan_to_eol(lc);
708    set_bit(index, res_all.hdr.item_present);
709 }
710
711 /*
712  * Store Tape Label Type (Bacula, ANSI, IBM)
713  *
714  */
715 void store_label(LEX *lc, RES_ITEM *item, int index, int pass)
716 {
717    int token, i;
718
719    token = lex_get_token(lc, T_NAME);
720    /* Store the label pass 2 so that type is defined */
721    for (i=0; tapelabels[i].name; i++) {
722       if (strcasecmp(lc->str, tapelabels[i].name) == 0) {
723          *(int *)(item->value) = tapelabels[i].token;
724          i = 0;
725          break;
726       }
727    }
728    if (i != 0) {
729       scan_err1(lc, "Expected a Tape Label keyword, got: %s", lc->str);
730    }
731    scan_to_eol(lc);
732    set_bit(index, res_all.hdr.item_present);
733 }
734
735
736 /* Parser state */
737 enum parse_state {
738    p_none,
739    p_resource
740 };
741
742 /*********************************************************************
743  *
744  * Parse configuration file
745  *
746  * Return 0 if reading failed, 1 otherwise
747  *  Note, the default behavior unless you have set an alternate
748  *  scan_error handler is to die on an error.
749  */
750 int
751 parse_config(const char *cf, LEX_ERROR_HANDLER *scan_error)
752 {
753    LEX *lc = NULL;
754    int token, i, pass;
755    int res_type = 0;
756    enum parse_state state = p_none;
757    RES_ITEM *items = NULL;
758    int level = 0;
759
760    /* Make two passes. The first builds the name symbol table,
761     * and the second picks up the items.
762     */
763    Dmsg0(900, "Enter parse_config()\n");
764    for (pass=1; pass <= 2; pass++) {
765       Dmsg1(900, "parse_config pass %d\n", pass);
766       if ((lc = lex_open_file(lc, cf, scan_error)) == NULL) {
767          berrno be;
768          /* We must create a lex packet to print the error */
769          lc = (LEX *)malloc(sizeof(LEX));
770          memset(lc, 0, sizeof(LEX));
771          if (scan_error) {
772             lc->scan_error = scan_error;
773          } else {
774             lex_set_default_error_handler(lc);
775          }
776          bstrncpy(lc->str, cf, sizeof(lc->str));
777          lc->fname = lc->str;
778          scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
779             lc->str, be.strerror());
780          free(lc);
781          return 0;
782       }
783       while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
784          Dmsg1(900, "parse got token=%s\n", lex_tok_to_str(token));
785          switch (state) {
786          case p_none:
787             if (token == T_EOL) {
788                break;
789             }
790             if (token != T_IDENTIFIER) {
791                scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
792                return 0;
793             }
794             for (i=0; resources[i].name; i++)
795                if (strcasecmp(resources[i].name, lc->str) == 0) {
796                   state = p_resource;
797                   items = resources[i].items;
798                   res_type = resources[i].rcode;
799                   init_resource(res_type, items, pass);
800                   break;
801                }
802             if (state == p_none) {
803                scan_err1(lc, _("expected resource name, got: %s"), lc->str);
804           return 0;
805             }
806             break;
807          case p_resource:
808             switch (token) {
809             case T_BOB:
810                level++;
811                break;
812             case T_IDENTIFIER:
813                if (level != 1) {
814                   scan_err1(lc, _("not in resource definition: %s"), lc->str);
815                   return 0;
816                }
817                for (i=0; items[i].name; i++) {
818                   if (strcasecmp(items[i].name, lc->str) == 0) {
819                      /* If the ITEM_NO_EQUALS flag is set we do NOT
820                       *   scan for = after the keyword  */
821                      if (!(items[i].flags & ITEM_NO_EQUALS)) {
822                         token = lex_get_token(lc, T_SKIP_EOL);
823                         Dmsg1 (900, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
824                         if (token != T_EQUALS) {
825                            scan_err1(lc, _("expected an equals, got: %s"), lc->str);
826                            return 0;
827                         }
828                      }
829                      Dmsg1(900, "calling handler for %s\n", items[i].name);
830                      /* Call item handler */
831                      items[i].handler(lc, &items[i], i, pass);
832                      i = -1;
833                      break;
834                   }
835                }
836                if (i >= 0) {
837                   Dmsg2(900, "level=%d id=%s\n", level, lc->str);
838                   Dmsg1(900, "Keyword = %s\n", lc->str);
839                   scan_err1(lc, _("Keyword \"%s\" not permitted in this resource.\n"
840                      "Perhaps you left the trailing brace off of the previous resource."), lc->str);
841                   return 0;
842                }
843                break;
844
845             case T_EOB:
846                level--;
847                state = p_none;
848                Dmsg0(900, "T_EOB => define new resource\n");
849                save_resource(res_type, items, pass);  /* save resource */
850                break;
851
852             case T_EOL:
853                break;
854
855             default:
856                scan_err2(lc, _("unexpected token %d %s in resource definition"),
857                   token, lex_tok_to_str(token));
858                return 0;
859             }
860             break;
861          default:
862             scan_err1(lc, _("Unknown parser state %d\n"), state);
863             return 0;
864          }
865       }
866       if (state != p_none) {
867          scan_err0(lc, _("End of conf file reached with unclosed resource."));
868          return 0;
869       }
870       if (debug_level >= 900 && pass == 2) {
871          int i;
872          for (i=r_first; i<=r_last; i++) {
873             dump_resource(i, res_head[i-r_first], prtmsg, NULL);
874          }
875       }
876       lc = lex_close_file(lc);
877    }
878    Dmsg0(900, "Leave parse_config()\n");
879    return 1;
880 }
881
882 /*********************************************************************
883  *
884  *      Free configuration resources
885  *
886  */
887 void free_config_resources()
888 {
889    for (int i=r_first; i<=r_last; i++) {
890       free_resource(res_head[i-r_first], i);
891       res_head[i-r_first] = NULL;
892    }
893 }
894
895 RES **save_config_resources()
896 {
897    int num = r_last - r_first + 1;
898    RES **res = (RES **)malloc(num*sizeof(RES *));
899    for (int i=0; i<num; i++) {
900       res[i] = res_head[i];
901       res_head[i] = NULL;
902    }
903    return res;
904 }
905
906 RES **new_res_head()
907 {
908    int size = (r_last - r_first + 1) * sizeof(RES *);
909    RES **res = (RES **)malloc(size);
910    memset(res, 0, size);
911    return res;
912 }