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