]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/parse_conf.c
1e8b2be9edbbb60b64fa8928971c4756b1b5bacc
[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-2006 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 amended 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 static 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    /* Set defaults in each item */
189    for (i=0; items[i].name; i++) {
190       Dmsg3(900, "Item=%s def=%s defval=%d\n", items[i].name,
191             (items[i].flags & ITEM_DEFAULT) ? "yes" : "no",
192             items[i].default_value);
193       if (items[i].flags & ITEM_DEFAULT && items[i].default_value != 0) {
194          if (items[i].handler == store_bit) {
195             *(int *)(items[i].value) |= items[i].code;
196          } else if (items[i].handler == store_bool) {
197             *(bool *)(items[i].value) = items[i].default_value;
198          } else if (items[i].handler == store_pint ||
199                     items[i].handler == store_int) {
200             *(int *)(items[i].value) = items[i].default_value;
201          } else if (items[i].handler == store_int64) {
202             *(int64_t *)(items[i].value) = items[i].default_value;
203          } else if (items[i].handler == store_size) {
204             *(uint64_t *)(items[i].value) = (uint64_t)items[i].default_value;
205          } else if (items[i].handler == store_time) {
206             *(utime_t *)(items[i].value) = (utime_t)items[i].default_value;
207          } else if (pass == 1 && items[i].handler == store_addresses) {
208             init_default_addresses((dlist**)items[i].value, items[i].default_value);
209          }
210       }
211       /* If this triggers, take a look at lib/parse_conf.h */
212       if (i >= MAX_RES_ITEMS) {
213          Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
214       }
215    }
216 }
217
218
219 /* Store Messages Destination information */
220 void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass)
221 {
222    int token;
223    char *cmd;
224    POOLMEM *dest;
225    int dest_len;
226
227    Dmsg2(900, "store_msgs pass=%d code=%d\n", pass, item->code);
228    if (pass == 1) {
229       switch (item->code) {
230       case MD_STDOUT:
231       case MD_STDERR:
232       case MD_SYSLOG:              /* syslog */
233       case MD_CONSOLE:
234          scan_types(lc, (MSGS *)(item->value), item->code, NULL, NULL);
235          break;
236       case MD_OPERATOR:            /* send to operator */
237       case MD_DIRECTOR:            /* send to Director */
238       case MD_MAIL:                /* mail */
239       case MD_MAIL_ON_ERROR:       /* mail if Job errors */
240          if (item->code == MD_OPERATOR) {
241             cmd = res_all.res_msgs.operator_cmd;
242          } else {
243             cmd = res_all.res_msgs.mail_cmd;
244          }
245          dest = get_pool_memory(PM_MESSAGE);
246          dest[0] = 0;
247          dest_len = 0;
248          /* Pick up comma separated list of destinations */
249          for ( ;; ) {
250             token = lex_get_token(lc, T_NAME);   /* scan destination */
251             dest = check_pool_memory_size(dest, dest_len + lc->str_len + 2);
252             if (dest[0] != 0) {
253                pm_strcat(dest, " ");  /* separate multiple destinations with space */
254                dest_len++;
255             }
256             pm_strcat(dest, lc->str);
257             dest_len += lc->str_len;
258             Dmsg2(900, "store_msgs newdest=%s: dest=%s:\n", lc->str, NPRT(dest));
259             token = lex_get_token(lc, T_SKIP_EOL);
260             if (token == T_COMMA) {
261                continue;           /* get another destination */
262             }
263             if (token != T_EQUALS) {
264                scan_err1(lc, _("expected an =, got: %s"), lc->str);
265             }
266             break;
267          }
268          Dmsg1(900, "mail_cmd=%s\n", NPRT(cmd));
269          scan_types(lc, (MSGS *)(item->value), item->code, dest, cmd);
270          free_pool_memory(dest);
271          Dmsg0(900, "done with dest codes\n");
272          break;
273       case MD_FILE:                /* file */
274       case MD_APPEND:              /* append */
275          dest = get_pool_memory(PM_MESSAGE);
276          /* Pick up a single destination */
277          token = lex_get_token(lc, T_NAME);   /* scan destination */
278          pm_strcpy(dest, lc->str);
279          dest_len = lc->str_len;
280          token = lex_get_token(lc, T_SKIP_EOL);
281          Dmsg1(900, "store_msgs dest=%s:\n", NPRT(dest));
282          if (token != T_EQUALS) {
283             scan_err1(lc, _("expected an =, got: %s"), lc->str);
284          }
285          scan_types(lc, (MSGS *)(item->value), item->code, dest, NULL);
286          free_pool_memory(dest);
287          Dmsg0(900, "done with dest codes\n");
288          break;
289
290       default:
291          scan_err1(lc, _("Unknown item code: %d\n"), item->code);
292          break;
293       }
294    }
295    scan_to_eol(lc);
296    set_bit(index, res_all.hdr.item_present);
297    Dmsg0(900, "Done store_msgs\n");
298 }
299
300 /*
301  * Scan for message types and add them to the message
302  * destination. The basic job here is to connect message types
303  *  (WARNING, ERROR, FATAL, INFO, ...) with an appropriate
304  *  destination (MAIL, FILE, OPERATOR, ...)
305  */
306 static void scan_types(LEX *lc, MSGS *msg, int dest_code, char *where, char *cmd)
307 {
308    int i, found, quit, is_not;
309    int msg_type = 0;
310    char *str;
311
312    for (quit=0; !quit;) {
313       lex_get_token(lc, T_NAME);            /* expect at least one type */
314       found = FALSE;
315       if (lc->str[0] == '!') {
316          is_not = TRUE;
317          str = &lc->str[1];
318       } else {
319          is_not = FALSE;
320          str = &lc->str[0];
321       }
322       for (i=0; msg_types[i].name; i++) {
323          if (strcasecmp(str, msg_types[i].name) == 0) {
324             msg_type = msg_types[i].token;
325             found = TRUE;
326             break;
327          }
328       }
329       if (!found) {
330          scan_err1(lc, _("message type: %s not found"), str);
331          /* NOT REACHED */
332       }
333
334       if (msg_type == M_MAX+1) {         /* all? */
335          for (i=1; i<=M_MAX; i++) {      /* yes set all types */
336             add_msg_dest(msg, dest_code, i, where, cmd);
337          }
338       } else {
339          if (is_not) {
340             rem_msg_dest(msg, dest_code, msg_type, where);
341          } else {
342             add_msg_dest(msg, dest_code, msg_type, where, cmd);
343          }
344       }
345       if (lc->ch != ',') {
346          break;
347       }
348       Dmsg0(900, "call lex_get_token() to eat comma\n");
349       lex_get_token(lc, T_ALL);          /* eat comma */
350    }
351    Dmsg0(900, "Done scan_types()\n");
352 }
353
354
355 /*
356  * This routine is ONLY for resource names
357  *  Store a name at specified address.
358  */
359 void store_name(LEX *lc, RES_ITEM *item, int index, int pass)
360 {
361    POOLMEM *msg = get_pool_memory(PM_EMSG);
362    lex_get_token(lc, T_NAME);
363    if (!is_name_valid(lc->str, &msg)) {
364       scan_err1(lc, "%s\n", msg);
365    }
366    free_pool_memory(msg);
367    /* Store the name both pass 1 and pass 2 */
368    if (*(item->value)) {
369       scan_err2(lc, _("Attempt to redefine name \"%s\" to \"%s\"."),
370          *(item->value), lc->str);
371    }
372    *(item->value) = bstrdup(lc->str);
373    scan_to_eol(lc);
374    set_bit(index, res_all.hdr.item_present);
375 }
376
377
378 /*
379  * Store a name string at specified address
380  * A name string is limited to MAX_RES_NAME_LENGTH
381  */
382 void store_strname(LEX *lc, RES_ITEM *item, int index, int pass)
383 {
384    lex_get_token(lc, T_NAME);
385    /* Store the name */
386    if (pass == 1) {
387       *(item->value) = bstrdup(lc->str);
388    }
389    scan_to_eol(lc);
390    set_bit(index, res_all.hdr.item_present);
391 }
392
393 /* Store a string at specified address */
394 void store_str(LEX *lc, RES_ITEM *item, int index, int pass)
395 {
396    lex_get_token(lc, T_STRING);
397    if (pass == 1) {
398       *(item->value) = bstrdup(lc->str);
399    }
400    scan_to_eol(lc);
401    set_bit(index, res_all.hdr.item_present);
402 }
403
404 /*
405  * Store a directory name at specified address. Note, we do
406  *   shell expansion except if the string begins with a vertical
407  *   bar (i.e. it will likely be passed to the shell later).
408  */
409 void store_dir(LEX *lc, RES_ITEM *item, int index, int pass)
410 {
411    lex_get_token(lc, T_STRING);
412    if (pass == 1) {
413       if (lc->str[0] != '|') {
414          do_shell_expansion(lc->str, sizeof(lc->str));
415       }
416       *(item->value) = bstrdup(lc->str);
417    }
418    scan_to_eol(lc);
419    set_bit(index, res_all.hdr.item_present);
420 }
421
422
423 /* Store a password specified address in MD5 coding */
424 void store_password(LEX *lc, RES_ITEM *item, int index, int pass)
425 {
426    unsigned int i, j;
427    struct MD5Context md5c;
428    unsigned char digest[CRYPTO_DIGEST_MD5_SIZE];
429    char sig[100];
430
431
432    lex_get_token(lc, T_STRING);
433    if (pass == 1) {
434       MD5Init(&md5c);
435       MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
436       MD5Final(digest, &md5c);
437       for (i = j = 0; i < sizeof(digest); i++) {
438          sprintf(&sig[j], "%02x", digest[i]);
439          j += 2;
440       }
441       *(item->value) = bstrdup(sig);
442    }
443    scan_to_eol(lc);
444    set_bit(index, res_all.hdr.item_present);
445 }
446
447
448 /* Store a resource at specified address.
449  * If we are in pass 2, do a lookup of the
450  * resource.
451  */
452 void store_res(LEX *lc, RES_ITEM *item, int index, int pass)
453 {
454    RES *res;
455
456    lex_get_token(lc, T_NAME);
457    if (pass == 2) {
458       res = GetResWithName(item->code, lc->str);
459       if (res == NULL) {
460          scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
461             lc->str, lc->line_no, lc->line);
462       }
463       if (*(item->value)) {
464          scan_err3(lc, _("Attempt to redefine resource \"%s\" referenced on line %d : %s\n"),
465             item->name, lc->line_no, lc->line);
466       }
467       *(item->value) = (char *)res;
468    }
469    scan_to_eol(lc);
470    set_bit(index, res_all.hdr.item_present);
471 }
472
473 /*
474  * Store a resource pointer in an alist. default_value indicates how many
475  *   times this routine can be called -- i.e. how many alists
476  *   there are.
477  * If we are in pass 2, do a lookup of the
478  *   resource.
479  */
480 void store_alist_res(LEX *lc, RES_ITEM *item, int index, int pass)
481 {
482    RES *res;
483    int count = item->default_value;
484    int i = 0;
485    alist *list;
486
487    if (pass == 2) {
488       if (count == 0) {               /* always store in item->value */
489          i = 0;
490          if ((item->value)[i] == NULL) {
491             list = New(alist(10, not_owned_by_alist));
492          } else {
493             list = (alist *)(item->value)[i];
494          }
495       } else {
496          /* Find empty place to store this directive */
497          while ((item->value)[i] != NULL && i++ < count) { }
498          if (i >= count) {
499             scan_err4(lc, _("Too many %s directives. Max. is %d. line %d: %s\n"),
500                lc->str, count, lc->line_no, lc->line);
501          }
502          list = New(alist(10, not_owned_by_alist));
503       }
504
505       for (;;) {
506          lex_get_token(lc, T_NAME);   /* scan next item */
507          res = GetResWithName(item->code, lc->str);
508          if (res == NULL) {
509             scan_err3(lc, _("Could not find config Resource \"%s\" referenced on line %d : %s\n"),
510                item->name, lc->line_no, lc->line);
511          }
512          Dmsg5(900, "Append %p to alist %p size=%d i=%d %s\n", 
513                res, list, list->size(), i, item->name);
514          list->append(res);
515          (item->value)[i] = (char *)list;
516          if (lc->ch != ',') {         /* if no other item follows */
517             break;                    /* get out */
518          }
519          lex_get_token(lc, T_ALL);    /* eat comma */
520       }
521    }
522    scan_to_eol(lc);
523    set_bit(index, res_all.hdr.item_present);
524 }
525
526
527 /*
528  * Store a string in an alist.
529  */
530 void store_alist_str(LEX *lc, RES_ITEM *item, int index, int pass)
531 {
532    alist *list;
533
534    if (pass == 2) {
535       if (*(item->value) == NULL) {
536          list = New(alist(10, owned_by_alist));
537       } else {
538          list = (alist *)(*(item->value));    
539       }
540
541       lex_get_token(lc, T_STRING);   /* scan next item */
542       Dmsg4(900, "Append %s to alist %p size=%d %s\n", 
543          lc->str, list, list->size(), item->name);
544       list->append(bstrdup(lc->str));
545       *(item->value) = (char *)list;
546    }
547    scan_to_eol(lc);
548    set_bit(index, res_all.hdr.item_present);
549 }
550
551
552
553 /*
554  * Store default values for Resource from xxxDefs
555  * If we are in pass 2, do a lookup of the
556  * resource and store everything not explicitly set
557  * in main resource.
558  *
559  * Note, here item points to the main resource (e.g. Job, not
560  *  the jobdefs, which we look up).
561  */
562 void store_defs(LEX *lc, RES_ITEM *item, int index, int pass)
563 {
564    RES *res;
565
566    lex_get_token(lc, T_NAME);
567    if (pass == 2) {
568      Dmsg2(900, "Code=%d name=%s\n", item->code, lc->str);
569      res = GetResWithName(item->code, lc->str);
570      if (res == NULL) {
571         scan_err3(lc, _("Missing config Resource \"%s\" referenced on line %d : %s\n"),
572            lc->str, lc->line_no, lc->line);
573      }
574    }
575    scan_to_eol(lc);
576 }
577
578
579
580 /* Store an integer at specified address */
581 void store_int(LEX *lc, RES_ITEM *item, int index, int pass)
582 {
583    lex_get_token(lc, T_INT32);
584    *(int *)(item->value) = lc->int32_val;
585    scan_to_eol(lc);
586    set_bit(index, res_all.hdr.item_present);
587 }
588
589 /* Store a positive integer at specified address */
590 void store_pint(LEX *lc, RES_ITEM *item, int index, int pass)
591 {
592    lex_get_token(lc, T_PINT32);
593    *(int *)(item->value) = lc->pint32_val;
594    scan_to_eol(lc);
595    set_bit(index, res_all.hdr.item_present);
596 }
597
598
599 /* Store an 64 bit integer at specified address */
600 void store_int64(LEX *lc, RES_ITEM *item, int index, int pass)
601 {
602    lex_get_token(lc, T_INT64);
603    *(int64_t *)(item->value) = lc->int64_val;
604    scan_to_eol(lc);
605    set_bit(index, res_all.hdr.item_present);
606 }
607
608 /* Store a size in bytes */
609 void store_size(LEX *lc, RES_ITEM *item, int index, int pass)
610 {
611    int token;
612    uint64_t uvalue;
613    char bsize[500];
614
615    Dmsg0(900, "Enter store_size\n");
616    token = lex_get_token(lc, T_SKIP_EOL);
617    errno = 0;
618    switch (token) {
619    case T_NUMBER:
620    case T_IDENTIFIER:
621    case T_UNQUOTED_STRING:
622       bstrncpy(bsize, lc->str, sizeof(bsize));  /* save first part */
623       /* if terminated by space, scan and get modifier */
624       while (lc->ch == ' ') {
625          token = lex_get_token(lc, T_ALL);
626          switch (token) {
627          case T_NUMBER:
628          case T_IDENTIFIER:
629          case T_UNQUOTED_STRING:
630             bstrncat(bsize, lc->str, sizeof(bsize));
631             break;
632          }
633       }
634       if (!size_to_uint64(bsize, strlen(bsize), &uvalue)) {
635          scan_err1(lc, _("expected a size number, got: %s"), lc->str);
636       }
637       *(uint64_t *)(item->value) = uvalue;
638       break;
639    default:
640       scan_err1(lc, _("expected a size, got: %s"), lc->str);
641       break;
642    }
643    if (token != T_EOL) {
644       scan_to_eol(lc);
645    }
646    set_bit(index, res_all.hdr.item_present);
647    Dmsg0(900, "Leave store_size\n");
648 }
649
650
651 /* Store a time period in seconds */
652 void store_time(LEX *lc, RES_ITEM *item, int index, int pass)
653 {
654    int token;
655    utime_t utime;
656    char period[500];
657
658    token = lex_get_token(lc, T_SKIP_EOL);
659    errno = 0;
660    switch (token) {
661    case T_NUMBER:
662    case T_IDENTIFIER:
663    case T_UNQUOTED_STRING:
664       bstrncpy(period, lc->str, sizeof(period));  /* get first part */
665       /* if terminated by space, scan and get modifier */
666       while (lc->ch == ' ') {
667          token = lex_get_token(lc, T_ALL);
668          switch (token) {
669          case T_NUMBER:
670          case T_IDENTIFIER:
671          case T_UNQUOTED_STRING:
672             bstrncat(period, lc->str, sizeof(period));
673             break;
674          }
675       }
676       if (!duration_to_utime(period, &utime)) {
677          scan_err1(lc, _("expected a time period, got: %s"), period);
678       }
679       *(utime_t *)(item->value) = utime;
680       break;
681    default:
682       scan_err1(lc, _("expected a time period, got: %s"), lc->str);
683       break;
684    }
685    if (token != T_EOL) {
686       scan_to_eol(lc);
687    }
688    set_bit(index, res_all.hdr.item_present);
689 }
690
691
692 /* Store a yes/no in a bit field */
693 void store_bit(LEX *lc, RES_ITEM *item, int index, int pass)
694 {
695    lex_get_token(lc, T_NAME);
696    if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
697       *(int *)(item->value) |= item->code;
698    } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
699       *(int *)(item->value) &= ~(item->code);
700    } else {
701       scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
702    }
703    scan_to_eol(lc);
704    set_bit(index, res_all.hdr.item_present);
705 }
706
707 /* Store a bool in a bit field */
708 void store_bool(LEX *lc, RES_ITEM *item, int index, int pass)
709 {
710    lex_get_token(lc, T_NAME);
711    if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
712       *(bool *)(item->value) = true;
713    } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
714       *(bool *)(item->value) = false;
715    } else {
716       scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
717    }
718    scan_to_eol(lc);
719    set_bit(index, res_all.hdr.item_present);
720 }
721
722
723 /*
724  * Store Tape Label Type (Bacula, ANSI, IBM)
725  *
726  */
727 void store_label(LEX *lc, RES_ITEM *item, int index, int pass)
728 {
729    int token, i;
730
731    token = lex_get_token(lc, T_NAME);
732    /* Store the label pass 2 so that type is defined */
733    for (i=0; tapelabels[i].name; i++) {
734       if (strcasecmp(lc->str, tapelabels[i].name) == 0) {
735          *(int *)(item->value) = tapelabels[i].token;
736          i = 0;
737          break;
738       }
739    }
740    if (i != 0) {
741       scan_err1(lc, _("Expected a Tape Label keyword, got: %s"), lc->str);
742    }
743    scan_to_eol(lc);
744    set_bit(index, res_all.hdr.item_present);
745 }
746
747
748 /* Parser state */
749 enum parse_state {
750    p_none,
751    p_resource
752 };
753
754 /*********************************************************************
755  *
756  * Parse configuration file
757  *
758  * Return 0 if reading failed, 1 otherwise
759  *  Note, the default behavior unless you have set an alternate
760  *  scan_error handler is to die on an error.
761  */
762 int
763 parse_config(const char *cf, LEX_ERROR_HANDLER *scan_error)
764 {
765    LEX *lc = NULL;
766    int token, i, pass;
767    int res_type = 0;
768    enum parse_state state = p_none;
769    RES_ITEM *items = NULL;
770    int level = 0;
771
772    /* Make two passes. The first builds the name symbol table,
773     * and the second picks up the items.
774     */
775    Dmsg0(900, "Enter parse_config()\n");
776    for (pass=1; pass <= 2; pass++) {
777       Dmsg1(900, "parse_config pass %d\n", pass);
778       if ((lc = lex_open_file(lc, cf, scan_error)) == NULL) {
779          berrno be;
780          /* We must create a lex packet to print the error */
781          lc = (LEX *)malloc(sizeof(LEX));
782          memset(lc, 0, sizeof(LEX));
783          if (scan_error) {
784             lc->scan_error = scan_error;
785          } else {
786             lex_set_default_error_handler(lc);
787          }
788          bstrncpy(lc->str, cf, sizeof(lc->str));
789          lc->fname = lc->str;
790          scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
791             lc->str, be.strerror());
792          free(lc);
793          return 0;
794       }
795       while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
796          Dmsg1(900, "parse got token=%s\n", lex_tok_to_str(token));
797          switch (state) {
798          case p_none:
799             if (token == T_EOL) {
800                break;
801             }
802             if (token != T_IDENTIFIER) {
803                scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
804                return 0;
805             }
806             for (i=0; resources[i].name; i++)
807                if (strcasecmp(resources[i].name, lc->str) == 0) {
808                   state = p_resource;
809                   items = resources[i].items;
810                   res_type = resources[i].rcode;
811                   init_resource(res_type, items, pass);
812                   break;
813                }
814             if (state == p_none) {
815                scan_err1(lc, _("expected resource name, got: %s"), lc->str);
816           return 0;
817             }
818             break;
819          case p_resource:
820             switch (token) {
821             case T_BOB:
822                level++;
823                break;
824             case T_IDENTIFIER:
825                if (level != 1) {
826                   scan_err1(lc, _("not in resource definition: %s"), lc->str);
827                   return 0;
828                }
829                for (i=0; items[i].name; i++) {
830                   if (strcasecmp(items[i].name, lc->str) == 0) {
831                      /* If the ITEM_NO_EQUALS flag is set we do NOT
832                       *   scan for = after the keyword  */
833                      if (!(items[i].flags & ITEM_NO_EQUALS)) {
834                         token = lex_get_token(lc, T_SKIP_EOL);
835                         Dmsg1 (900, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
836                         if (token != T_EQUALS) {
837                            scan_err1(lc, _("expected an equals, got: %s"), lc->str);
838                            return 0;
839                         }
840                      }
841                      Dmsg1(800, "calling handler for %s\n", items[i].name);
842                      /* Call item handler */
843                      items[i].handler(lc, &items[i], i, pass);
844                      i = -1;
845                      break;
846                   }
847                }
848                if (i >= 0) {
849                   Dmsg2(900, "level=%d id=%s\n", level, lc->str);
850                   Dmsg1(900, "Keyword = %s\n", lc->str);
851                   scan_err1(lc, _("Keyword \"%s\" not permitted in this resource.\n"
852                      "Perhaps you left the trailing brace off of the previous resource."), lc->str);
853                   return 0;
854                }
855                break;
856
857             case T_EOB:
858                level--;
859                state = p_none;
860                Dmsg0(900, "T_EOB => define new resource\n");
861                save_resource(res_type, items, pass);  /* save resource */
862                break;
863
864             case T_EOL:
865                break;
866
867             default:
868                scan_err2(lc, _("unexpected token %d %s in resource definition"),
869                   token, lex_tok_to_str(token));
870                return 0;
871             }
872             break;
873          default:
874             scan_err1(lc, _("Unknown parser state %d\n"), state);
875             return 0;
876          }
877       }
878       if (state != p_none) {
879          scan_err0(lc, _("End of conf file reached with unclosed resource."));
880          return 0;
881       }
882       if (debug_level >= 900 && pass == 2) {
883          int i;
884          for (i=r_first; i<=r_last; i++) {
885             dump_resource(i, res_head[i-r_first], prtmsg, NULL);
886          }
887       }
888       lc = lex_close_file(lc);
889    }
890    Dmsg0(900, "Leave parse_config()\n");
891    return 1;
892 }
893
894 /*********************************************************************
895  *
896  *      Free configuration resources
897  *
898  */
899 void free_config_resources()
900 {
901    for (int i=r_first; i<=r_last; i++) {
902       free_resource(res_head[i-r_first], i);
903       res_head[i-r_first] = NULL;
904    }
905 }
906
907 RES **save_config_resources()
908 {
909    int num = r_last - r_first + 1;
910    RES **res = (RES **)malloc(num*sizeof(RES *));
911    for (int i=0; i<num; i++) {
912       res[i] = res_head[i];
913       res_head[i] = NULL;
914    }
915    return res;
916 }
917
918 RES **new_res_head()
919 {
920    int size = (r_last - r_first + 1) * sizeof(RES *);
921    RES **res = (RES **)malloc(size);
922    memset(res, 0, size);
923    return res;
924 }