]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/parse_conf.c
Fail when multipl mailcommand and other strings are specified in .conf. Fixes bug...
[bacula/bacula] / bacula / src / lib / parse_conf.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2016 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *   Master Configuration routines.
21  *
22  *   This file contains the common parts of the Bacula
23  *   configuration routines.
24  *
25  *   Note, the configuration file parser consists of three parts
26  *
27  *   1. The generic lexical scanner in lib/lex.c and lib/lex.h
28  *
29  *   2. The generic config  scanner in lib/parse_conf.c and
30  *      lib/parse_conf.h.
31  *      These files contain the parser code, some utility
32  *      routines, and the common store routines (name, int,
33  *      string, time, int64, size, ...).
34  *
35  *   3. The daemon specific file, which contains the Resource
36  *      definitions as well as any specific store routines
37  *      for the resource records.
38  *
39  *    N.B. This is a two pass parser, so if you malloc() a string
40  *         in a "store" routine, you must ensure to do it during
41  *         only one of the two passes, or to free it between.
42  *         Also, note that the resource record is malloced and
43  *         saved in save_resource() during pass 1.  Anything that
44  *         you want saved after pass two (e.g. resource pointers)
45  *         must explicitly be done in save_resource. Take a look
46  *         at the Job resource in src/dird/dird_conf.c to see how
47  *         it is done.
48  *
49  *     Kern Sibbald, January MM
50  *
51  */
52
53
54 #include "bacula.h"
55
56 #if defined(HAVE_WIN32)
57 #include "shlobj.h"
58 #else
59 #define MAX_PATH  1024
60 #endif
61
62 /*
63  * Define the Union of all the common resource structure definitions.
64  */
65 union URES {
66    MSGS  res_msgs;
67    RES hdr;
68 };
69
70 #if defined(_MSC_VER)
71 // work around visual studio name mangling preventing external linkage since res_all
72 // is declared as a different type when instantiated.
73 extern "C" URES res_all;
74 #else
75 extern  URES res_all;
76 #endif
77
78 extern brwlock_t res_lock;            /* resource lock */
79
80
81 /* Forward referenced subroutines */
82 static void scan_types(LEX *lc, MSGS *msg, int dest, char *where, char *cmd);
83 static const char *get_default_configdir();
84 static bool find_config_file(const char *config_file, char *full_path, int max_path);
85
86 /* Common Resource definitions */
87
88 /* Message resource directives
89  *  name         handler      value       code   flags  default_value
90  */
91 RES_ITEM msgs_items[] = {
92    {"Name",        store_name,    ITEM(res_msgs.hdr.name),  0, 0, 0},
93    {"Description", store_str,     ITEM(res_msgs.hdr.desc),  0, 0, 0},
94    {"MailCommand", store_str,     ITEM(res_msgs.mail_cmd),  0, 0, 0},
95    {"OperatorCommand", store_str, ITEM(res_msgs.operator_cmd), 0, 0, 0},
96    {"Syslog",      store_msgs, ITEM(res_msgs), MD_SYSLOG,   0, 0},
97    {"Mail",        store_msgs, ITEM(res_msgs), MD_MAIL,     0, 0},
98    {"MailOnError", store_msgs, ITEM(res_msgs), MD_MAIL_ON_ERROR, 0, 0},
99    {"MailOnSuccess", store_msgs, ITEM(res_msgs), MD_MAIL_ON_SUCCESS, 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    {"Catalog",     store_msgs, ITEM(res_msgs), MD_CATALOG,  ITEM_LAST, 0},
108    {NULL,          NULL,       {0},       0, 0, 0}
109 };
110
111 struct s_mtypes {
112    const char *name;
113    int token;
114 };
115 /* Various message types */
116 static struct s_mtypes msg_types[] = {
117    {"Debug",         M_DEBUG},
118    {"Abort",         M_ABORT},
119    {"Fatal",         M_FATAL},
120    {"Error",         M_ERROR},
121    {"Warning",       M_WARNING},
122    {"Info",          M_INFO},
123    {"Saved",         M_SAVED},
124    {"NotSaved",      M_NOTSAVED},
125    {"Skipped",       M_SKIPPED},
126    {"Mount",         M_MOUNT},
127    {"Terminate",     M_TERM},
128    {"Restored",      M_RESTORED},
129    {"Security",      M_SECURITY},
130    {"Alert",         M_ALERT},
131    {"VolMgmt",       M_VOLMGMT},
132    {"ErrorTerm",     M_ERROR_TERM},
133    {"All",           M_MAX+1},
134    {NULL,            0}
135 };
136
137 /*
138  * Tape Label types permitted in Pool records
139  *
140  *   tape label      label code = token
141  */
142 s_kw tapelabels[] = {
143    {"Bacula",        B_BACULA_LABEL},
144    {"ANSI",          B_ANSI_LABEL},
145    {"IBM",           B_IBM_LABEL},
146    {NULL,            0}
147 };
148
149
150 /* Simply print a message */
151 static void prtmsg(void *sock, const char *fmt, ...)
152 {
153    va_list arg_ptr;
154
155    va_start(arg_ptr, fmt);
156    vfprintf(stdout, fmt, arg_ptr);
157    va_end(arg_ptr);
158 }
159
160 const char *res_to_str(int rcode)
161 {
162    if (rcode < r_first || rcode > r_last) {
163       return _("***UNKNOWN***");
164    } else {
165       return resources[rcode-r_first].name;
166    }
167 }
168
169
170 /*
171  * Initialize the static structure to zeros, then
172  *  apply all the default values.
173  */
174 static void init_resource(CONFIG *config, int type, RES_ITEM *items, int pass)
175 {
176    int i;
177    int rindex = type - r_first;
178
179    memset(config->m_res_all, 0, config->m_res_all_size);
180    res_all.hdr.rcode = type;
181    res_all.hdr.refcnt = 1;
182
183    /* Set defaults in each item */
184    for (i=0; items[i].name; i++) {
185       Dmsg3(900, "Item=%s def=%s defval=%d\n", items[i].name,
186             (items[i].flags & ITEM_DEFAULT) ? "yes" : "no",
187             items[i].default_value);
188       if (items[i].flags & ITEM_DEFAULT && items[i].default_value != 0) {
189          if (items[i].handler == store_bit) {
190             *(uint32_t *)(items[i].value) |= items[i].code;
191          } else if (items[i].handler == store_bool) {
192             *(bool *)(items[i].value) = items[i].default_value != 0;
193          } else if (items[i].handler == store_pint32 ||
194                     items[i].handler == store_int32 ||
195                     items[i].handler == store_size32) {
196             *(uint32_t *)(items[i].value) = items[i].default_value;
197          } else if (items[i].handler == store_int64) {
198             *(int64_t *)(items[i].value) = items[i].default_value;
199          } else if (items[i].handler == store_size64) {
200             *(uint64_t *)(items[i].value) = (uint64_t)items[i].default_value;
201          } else if (items[i].handler == store_speed) {
202             *(uint64_t *)(items[i].value) = (uint64_t)items[i].default_value;
203          } else if (items[i].handler == store_time) {
204             *(utime_t *)(items[i].value) = (utime_t)items[i].default_value;
205          } else if (pass == 1 && items[i].handler == store_addresses) {
206             init_default_addresses((dlist**)items[i].value, items[i].default_value);
207          }
208       }
209       /* If this triggers, take a look at lib/parse_conf.h */
210       if (i >= MAX_RES_ITEMS) {
211          Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
212       }
213    }
214 }
215
216
217 /* Store Messages Destination information */
218 void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass)
219 {
220    int token;
221    char *cmd;
222    POOLMEM *dest;
223    int dest_len;
224
225    Dmsg2(900, "store_msgs pass=%d code=%d\n", pass, item->code);
226    if (pass == 1) {
227       switch (item->code) {
228       case MD_STDOUT:
229       case MD_STDERR:
230       case MD_SYSLOG:              /* syslog */
231       case MD_CONSOLE:
232       case MD_CATALOG:
233          scan_types(lc, (MSGS *)(item->value), item->code, NULL, NULL);
234          break;
235       case MD_OPERATOR:            /* send to operator */
236       case MD_DIRECTOR:            /* send to Director */
237       case MD_MAIL:                /* mail */
238       case MD_MAIL_ON_ERROR:       /* mail if Job errors */
239       case MD_MAIL_ON_SUCCESS:     /* mail if Job succeeds */
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                return;
266             }
267             break;
268          }
269          Dmsg1(900, "mail_cmd=%s\n", NPRT(cmd));
270          scan_types(lc, (MSGS *)(item->value), item->code, dest, cmd);
271          free_pool_memory(dest);
272          Dmsg0(900, "done with dest codes\n");
273          break;
274
275       case MD_FILE:                /* file */
276       case MD_APPEND:              /* append */
277          dest = get_pool_memory(PM_MESSAGE);
278          /* Pick up a single destination */
279          token = lex_get_token(lc, T_NAME);   /* scan destination */
280          pm_strcpy(dest, lc->str);
281          dest_len = lc->str_len;
282          token = lex_get_token(lc, T_SKIP_EOL);
283          Dmsg1(900, "store_msgs dest=%s:\n", NPRT(dest));
284          if (token != T_EQUALS) {
285             scan_err1(lc, _("expected an =, got: %s"), lc->str);
286             return;
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          return;
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;
312    bool found, is_not;
313    int msg_type = 0;
314    char *str;
315
316    for ( ;; ) {
317       lex_get_token(lc, T_NAME);            /* expect at least one type */
318       found = false;
319       if (lc->str[0] == '!') {
320          is_not = true;
321          str = &lc->str[1];
322       } else {
323          is_not = false;
324          str = &lc->str[0];
325       }
326       for (i=0; msg_types[i].name; i++) {
327          if (strcasecmp(str, msg_types[i].name) == 0) {
328             msg_type = msg_types[i].token;
329             found = true;
330             break;
331          }
332       }
333       if (!found) {
334          scan_err1(lc, _("message type: %s not found"), str);
335          return;
336       }
337
338       if (msg_type == M_MAX+1) {         /* all? */
339          for (i=1; i<=M_MAX; i++) {      /* yes set all types */
340             add_msg_dest(msg, dest_code, i, where, cmd);
341          }
342       } else 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       if (lc->ch != ',') {
348          break;
349       }
350       Dmsg0(900, "call lex_get_token() to eat comma\n");
351       lex_get_token(lc, T_ALL);          /* eat comma */
352    }
353    Dmsg0(900, "Done scan_types()\n");
354 }
355
356
357 /*
358  * This routine is ONLY for resource names
359  *  Store a name at specified address.
360  */
361 void store_name(LEX *lc, RES_ITEM *item, int index, int pass)
362 {
363    POOLMEM *msg = get_pool_memory(PM_EMSG);
364    lex_get_token(lc, T_NAME);
365    if (!is_name_valid(lc->str, &msg)) {
366       scan_err1(lc, "%s\n", msg);
367       return;
368    }
369    free_pool_memory(msg);
370    /* Store the name both pass 1 and pass 2 */
371    if (*(item->value)) {
372       scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
373          item->name, *(item->value), lc->str, lc->line_no, lc->line);
374       return;
375    }
376    *(item->value) = bstrdup(lc->str);
377    scan_to_eol(lc);
378    set_bit(index, res_all.hdr.item_present);
379 }
380
381
382 /*
383  * Store a name string at specified address
384  * A name string is limited to MAX_RES_NAME_LENGTH
385  */
386 void store_strname(LEX *lc, RES_ITEM *item, int index, int pass)
387 {
388    lex_get_token(lc, T_NAME);
389    /* Store the name */
390    if (pass == 1) {
391       if (*(item->value)) {
392          scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
393             item->name, *(item->value), lc->str, lc->line_no, lc->line);
394          return;
395       }
396       *(item->value) = bstrdup(lc->str);
397    }
398    scan_to_eol(lc);
399    set_bit(index, res_all.hdr.item_present);
400 }
401
402 /* Store a string at specified address */
403 void store_str(LEX *lc, RES_ITEM *item, int index, int pass)
404 {
405    lex_get_token(lc, T_STRING);
406    if (pass == 1) {
407       if (*(item->value)) {
408          scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
409             item->name, *(item->value), lc->str, lc->line_no, lc->line);
410          return;
411       }
412       *(item->value) = bstrdup(lc->str);
413    }
414    scan_to_eol(lc);
415    set_bit(index, res_all.hdr.item_present);
416 }
417
418 /*
419  * Store a directory name at specified address. Note, we do
420  *   shell expansion except if the string begins with a vertical
421  *   bar (i.e. it will likely be passed to the shell later).
422  */
423 void store_dir(LEX *lc, RES_ITEM *item, int index, int pass)
424 {
425    lex_get_token(lc, T_STRING);
426    if (pass == 1) {
427       if (lc->str[0] != '|') {
428          do_shell_expansion(lc->str, sizeof_pool_memory(lc->str));
429       }
430       if (*(item->value)) {
431          scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
432             item->name, *(item->value), lc->str, lc->line_no, lc->line);
433          return;
434       }
435       *(item->value) = bstrdup(lc->str);
436    }
437    scan_to_eol(lc);
438    set_bit(index, res_all.hdr.item_present);
439 }
440
441
442 /* Store a password specified address in MD5 coding */
443 void store_password(LEX *lc, RES_ITEM *item, int index, int pass)
444 {
445    unsigned int i, j;
446    struct MD5Context md5c;
447    unsigned char digest[CRYPTO_DIGEST_MD5_SIZE];
448    char sig[100];
449
450
451    lex_get_token(lc, T_STRING);
452    if (pass == 1) {
453       MD5Init(&md5c);
454       MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
455       MD5Final(digest, &md5c);
456       for (i = j = 0; i < sizeof(digest); i++) {
457          sprintf(&sig[j], "%02x", digest[i]);
458          j += 2;
459       }
460       if (*(item->value)) {
461          scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
462             item->name, *(item->value), lc->str, lc->line_no, lc->line);
463          return;
464       }
465       *(item->value) = bstrdup(sig);
466    }
467    scan_to_eol(lc);
468    set_bit(index, res_all.hdr.item_present);
469 }
470
471
472 /* Store a resource at specified address.
473  * If we are in pass 2, do a lookup of the
474  * resource.
475  */
476 void store_res(LEX *lc, RES_ITEM *item, int index, int pass)
477 {
478    RES *res;
479
480    lex_get_token(lc, T_NAME);
481    if (pass == 2) {
482       res = GetResWithName(item->code, lc->str);
483       if (res == NULL) {
484          scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
485             lc->str, lc->line_no, lc->line);
486          return;
487       }
488       if (*(item->value)) {
489          scan_err3(lc, _("Attempt to redefine resource \"%s\" referenced on line %d : %s\n"),
490             item->name, lc->line_no, lc->line);
491          return;
492       }
493       *(item->value) = (char *)res;
494    }
495    scan_to_eol(lc);
496    set_bit(index, res_all.hdr.item_present);
497 }
498
499 /*
500  * Store a resource pointer in an alist. default_value indicates how many
501  *   times this routine can be called -- i.e. how many alists
502  *   there are.
503  * If we are in pass 2, do a lookup of the
504  *   resource.
505  */
506 void store_alist_res(LEX *lc, RES_ITEM *item, int index, int pass)
507 {
508    RES *res;
509    int count = item->default_value;
510    int i = 0;
511    alist *list;
512
513    if (pass == 2) {
514       if (count == 0) {               /* always store in item->value */
515          i = 0;
516          if ((item->value)[i] == NULL) {
517             list = New(alist(10, not_owned_by_alist));
518          } else {
519             list = (alist *)(item->value)[i];
520          }
521       } else {
522          /* Find empty place to store this directive */
523          while ((item->value)[i] != NULL && i++ < count) { }
524          if (i >= count) {
525             scan_err4(lc, _("Too many %s directives. Max. is %d. line %d: %s\n"),
526                lc->str, count, lc->line_no, lc->line);
527             return;
528          }
529          list = New(alist(10, not_owned_by_alist));
530       }
531
532       for (;;) {
533          lex_get_token(lc, T_NAME);   /* scan next item */
534          res = GetResWithName(item->code, lc->str);
535          if (res == NULL) {
536             scan_err3(lc, _("Could not find config Resource \"%s\" referenced on line %d : %s\n"),
537                item->name, lc->line_no, lc->line);
538             return;
539          }
540          Dmsg5(900, "Append %p to alist %p size=%d i=%d %s\n",
541                res, list, list->size(), i, item->name);
542          list->append(res);
543          (item->value)[i] = (char *)list;
544          if (lc->ch != ',') {         /* if no other item follows */
545             break;                    /* get out */
546          }
547          lex_get_token(lc, T_ALL);    /* eat comma */
548       }
549    }
550    scan_to_eol(lc);
551    set_bit(index, res_all.hdr.item_present);
552 }
553
554
555 /*
556  * Store a string in an alist.
557  */
558 void store_alist_str(LEX *lc, RES_ITEM *item, int index, int pass)
559 {
560    alist *list;
561
562    if (pass == 2) {
563       if (*(item->value) == NULL) {
564          list = New(alist(10, owned_by_alist));
565          *(item->value) = (char *)list;
566       } else {
567          list = (alist *)(*(item->value));
568       }
569       for (;;) {
570          lex_get_token(lc, T_STRING);   /* scan next item */
571          Dmsg4(900, "Append %s to alist 0x%p size=%d %s\n",
572             lc->str, list, list->size(), item->name);
573          list->append(bstrdup(lc->str));
574          if (lc->ch != ',') {         /* if no other item follows */
575             break;                    /* get out */
576          }
577          lex_get_token(lc, T_ALL);    /* eat comma */
578       }
579    }
580    scan_to_eol(lc);
581    set_bit(index, res_all.hdr.item_present);
582 }
583
584
585
586 /*
587  * Store default values for Resource from xxxDefs
588  * If we are in pass 2, do a lookup of the
589  * resource and store everything not explicitly set
590  * in main resource.
591  *
592  * Note, here item points to the main resource (e.g. Job, not
593  *  the jobdefs, which we look up).
594  */
595 void store_defs(LEX *lc, RES_ITEM *item, int index, int pass)
596 {
597    RES *res;
598
599    lex_get_token(lc, T_NAME);
600    if (pass == 2) {
601      Dmsg2(900, "Code=%d name=%s\n", item->code, lc->str);
602      res = GetResWithName(item->code, lc->str);
603      if (res == NULL) {
604         scan_err3(lc, _("Missing config Resource \"%s\" referenced on line %d : %s\n"),
605            lc->str, lc->line_no, lc->line);
606         return;
607      }
608    }
609    scan_to_eol(lc);
610 }
611
612
613
614 /* Store an integer at specified address */
615 void store_int32(LEX *lc, RES_ITEM *item, int index, int pass)
616 {
617    lex_get_token(lc, T_INT32);
618    *(uint32_t *)(item->value) = lc->int32_val;
619    scan_to_eol(lc);
620    set_bit(index, res_all.hdr.item_present);
621 }
622
623 /* Store a positive integer at specified address */
624 void store_pint32(LEX *lc, RES_ITEM *item, int index, int pass)
625 {
626    lex_get_token(lc, T_PINT32);
627    *(uint32_t *)(item->value) = lc->pint32_val;
628    scan_to_eol(lc);
629    set_bit(index, res_all.hdr.item_present);
630 }
631
632
633 /* Store an 64 bit integer at specified address */
634 void store_int64(LEX *lc, RES_ITEM *item, int index, int pass)
635 {
636    lex_get_token(lc, T_INT64);
637    *(int64_t *)(item->value) = lc->int64_val;
638    scan_to_eol(lc);
639    set_bit(index, res_all.hdr.item_present);
640 }
641
642 enum store_unit_type {
643    STORE_SIZE,
644    STORE_SPEED
645 } ;
646
647 /* Store a size in bytes */
648 static void store_int_unit(LEX *lc, RES_ITEM *item, int index, int pass,
649                            bool size32, enum store_unit_type type)
650 {
651    int token;
652    uint64_t uvalue;
653    char bsize[500];
654
655    Dmsg0(900, "Enter store_unit\n");
656    token = lex_get_token(lc, T_SKIP_EOL);
657    errno = 0;
658    switch (token) {
659    case T_NUMBER:
660    case T_IDENTIFIER:
661    case T_UNQUOTED_STRING:
662       bstrncpy(bsize, lc->str, sizeof(bsize));  /* save first part */
663       /* if terminated by space, scan and get modifier */
664       while (lc->ch == ' ') {
665          token = lex_get_token(lc, T_ALL);
666          switch (token) {
667          case T_NUMBER:
668          case T_IDENTIFIER:
669          case T_UNQUOTED_STRING:
670             bstrncat(bsize, lc->str, sizeof(bsize));
671             break;
672          }
673       }
674       if (type == STORE_SIZE) {
675          if (!size_to_uint64(bsize, strlen(bsize), &uvalue)) {
676             scan_err1(lc, _("expected a size number, got: %s"), lc->str);
677             return;
678          }
679       } else {
680          if (!speed_to_uint64(bsize, strlen(bsize), &uvalue)) {
681             scan_err1(lc, _("expected a speed number, got: %s"), lc->str);
682             return;
683          }
684       }
685       if (size32) {
686          *(uint32_t *)(item->value) = (uint32_t)uvalue;
687       } else {
688          *(uint64_t *)(item->value) = uvalue;
689       }
690       break;
691    default:
692       scan_err2(lc, _("expected a %s, got: %s"),
693                 (type == STORE_SIZE)?_("size"):_("speed"), lc->str);
694       return;
695    }
696    if (token != T_EOL) {
697       scan_to_eol(lc);
698    }
699    set_bit(index, res_all.hdr.item_present);
700    Dmsg0(900, "Leave store_unit\n");
701 }
702
703 /* Store a size in bytes */
704 void store_size32(LEX *lc, RES_ITEM *item, int index, int pass)
705 {
706    store_int_unit(lc, item, index, pass, true /* 32 bit */, STORE_SIZE);
707 }
708
709 /* Store a size in bytes */
710 void store_size64(LEX *lc, RES_ITEM *item, int index, int pass)
711 {
712    store_int_unit(lc, item, index, pass, false /* not 32 bit */, STORE_SIZE);
713 }
714
715 /* Store a speed in bytes/s */
716 void store_speed(LEX *lc, RES_ITEM *item, int index, int pass)
717 {
718    store_int_unit(lc, item, index, pass, false /* 64 bit */, STORE_SPEED);
719 }
720
721 /* Store a time period in seconds */
722 void store_time(LEX *lc, RES_ITEM *item, int index, int pass)
723 {
724    int token;
725    utime_t utime;
726    char period[500];
727
728    token = lex_get_token(lc, T_SKIP_EOL);
729    errno = 0;
730    switch (token) {
731    case T_NUMBER:
732    case T_IDENTIFIER:
733    case T_UNQUOTED_STRING:
734       bstrncpy(period, lc->str, sizeof(period));  /* get first part */
735       /* if terminated by space, scan and get modifier */
736       while (lc->ch == ' ') {
737          token = lex_get_token(lc, T_ALL);
738          switch (token) {
739          case T_NUMBER:
740          case T_IDENTIFIER:
741          case T_UNQUOTED_STRING:
742             bstrncat(period, lc->str, sizeof(period));
743             break;
744          }
745       }
746       if (!duration_to_utime(period, &utime)) {
747          scan_err1(lc, _("expected a time period, got: %s"), period);
748          return;
749       }
750       *(utime_t *)(item->value) = utime;
751       break;
752    default:
753       scan_err1(lc, _("expected a time period, got: %s"), lc->str);
754       return;
755    }
756    if (token != T_EOL) {
757       scan_to_eol(lc);
758    }
759    set_bit(index, res_all.hdr.item_present);
760 }
761
762
763 /* Store a yes/no in a bit field */
764 void store_bit(LEX *lc, RES_ITEM *item, int index, int pass)
765 {
766    lex_get_token(lc, T_NAME);
767    if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
768       *(uint32_t *)(item->value) |= item->code;
769    } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
770       *(uint32_t *)(item->value) &= ~(item->code);
771    } else {
772       scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
773       return;
774    }
775    scan_to_eol(lc);
776    set_bit(index, res_all.hdr.item_present);
777 }
778
779 /* Store a bool in a bit field */
780 void store_bool(LEX *lc, RES_ITEM *item, int index, int pass)
781 {
782    lex_get_token(lc, T_NAME);
783    if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
784       *(bool *)(item->value) = true;
785    } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
786       *(bool *)(item->value) = false;
787    } else {
788       scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
789       return;
790    }
791    scan_to_eol(lc);
792    set_bit(index, res_all.hdr.item_present);
793 }
794
795
796 /*
797  * Store Tape Label Type (Bacula, ANSI, IBM)
798  *
799  */
800 void store_label(LEX *lc, RES_ITEM *item, int index, int pass)
801 {
802    int i;
803
804    lex_get_token(lc, T_NAME);
805    /* Store the label pass 2 so that type is defined */
806    for (i=0; tapelabels[i].name; i++) {
807       if (strcasecmp(lc->str, tapelabels[i].name) == 0) {
808          *(uint32_t *)(item->value) = tapelabels[i].token;
809          i = 0;
810          break;
811       }
812    }
813    if (i != 0) {
814       scan_err1(lc, _("Expected a Tape Label keyword, got: %s"), lc->str);
815       return;
816    }
817    scan_to_eol(lc);
818    set_bit(index, res_all.hdr.item_present);
819 }
820
821
822 /* Parser state */
823 enum parse_state {
824    p_none,
825    p_resource
826 };
827
828 CONFIG *new_config_parser()
829 {
830    CONFIG *config;
831    config = (CONFIG *)malloc(sizeof(CONFIG));
832    memset(config, 0, sizeof(CONFIG));
833    return config;
834 }
835
836 void CONFIG::init(
837    const char *cf,
838    LEX_ERROR_HANDLER *scan_error,
839    int32_t err_type,
840    void *vres_all,
841    int32_t res_all_size,
842    int32_t r_first,
843    int32_t r_last,
844    RES_TABLE *resources,
845    RES **res_head)
846 {
847    m_cf = cf;
848    m_scan_error = scan_error;
849    m_err_type = err_type;
850    m_res_all = vres_all;
851    m_res_all_size = res_all_size;
852    m_r_first = r_first;
853    m_r_last = r_last;
854    m_resources = resources;
855    m_res_head = res_head;
856 }
857
858 /*********************************************************************
859  *
860  * Parse configuration file
861  *
862  * Return 0 if reading failed, 1 otherwise
863  *  Note, the default behavior unless you have set an alternate
864  *  scan_error handler is to die on an error.
865  */
866 bool CONFIG::parse_config()
867 {
868    LEX *lc = NULL;
869    int token, i, pass;
870    int res_type = 0;
871    enum parse_state state = p_none;
872    RES_ITEM *items = NULL;
873    int level = 0;
874    static bool first = true;
875    int errstat;
876    const char *cf = m_cf;
877    LEX_ERROR_HANDLER *scan_error = m_scan_error;
878    int err_type = m_err_type;
879
880    if (first && (errstat=rwl_init(&res_lock)) != 0) {
881       berrno be;
882       Jmsg1(NULL, M_ABORT, 0, _("Unable to initialize resource lock. ERR=%s\n"),
883             be.bstrerror(errstat));
884    }
885    first = false;
886
887    char *full_path = (char *)alloca(MAX_PATH + 1);
888
889    if (!find_config_file(cf, full_path, MAX_PATH +1)) {
890       Jmsg0(NULL, M_ABORT, 0, _("Config filename too long.\n"));
891    }
892    cf = full_path;
893
894    /* Make two passes. The first builds the name symbol table,
895     * and the second picks up the items.
896     */
897    Dmsg0(900, "Enter parse_config()\n");
898    for (pass=1; pass <= 2; pass++) {
899       Dmsg1(900, "parse_config pass %d\n", pass);
900       if ((lc = lex_open_file(lc, cf, scan_error)) == NULL) {
901          berrno be;
902          /* We must create a lex packet to print the error */
903          lc = (LEX *)malloc(sizeof(LEX));
904          memset(lc, 0, sizeof(LEX));
905          lc->str = get_memory(5000);
906          if (scan_error) {
907             lc->scan_error = scan_error;
908          } else {
909             lex_set_default_error_handler(lc);
910          }
911          lex_set_error_handler_error_type(lc, err_type) ;
912          pm_strcpy(lc->str, cf);
913          lc->fname = lc->str;
914          scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
915             lc->str, be.bstrerror());
916          free_pool_memory(lc->str);
917          free(lc);
918          return 0;
919       }
920       lex_set_error_handler_error_type(lc, err_type) ;
921       while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
922          Dmsg3(900, "parse state=%d pass=%d got token=%s\n", state, pass,
923               lex_tok_to_str(token));
924          switch (state) {
925          case p_none:
926             if (token == T_EOL) {
927                break;
928             } else if (token == T_UTF8_BOM) {
929                /* We can assume the file is UTF-8 as we have seen a UTF-8 BOM */
930                break;
931             } else if (token == T_UTF16_BOM) {
932                scan_err0(lc, _("Currently we cannot handle UTF-16 source files. "
933                    "Please convert the conf file to UTF-8\n"));
934                goto bail_out;
935             } else if (token != T_IDENTIFIER) {
936                scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
937                goto bail_out;
938             }
939             for (i=0; resources[i].name; i++) {
940                if (strcasecmp(resources[i].name, lc->str) == 0) {
941                   items = resources[i].items;
942                   if (!items) {
943                      break;
944                   }
945                   state = p_resource;
946                   res_type = resources[i].rcode;
947                   init_resource(this, res_type, items, pass);
948                   break;
949                }
950             }
951             if (state == p_none) {
952                scan_err1(lc, _("expected resource name, got: %s"), lc->str);
953                goto bail_out;
954             }
955             break;
956          case p_resource:
957             switch (token) {
958             case T_BOB:
959                level++;
960                break;
961             case T_IDENTIFIER:
962                if (level != 1) {
963                   scan_err1(lc, _("not in resource definition: %s"), lc->str);
964                   goto bail_out;
965                }
966                for (i=0; items[i].name; i++) {
967                   if (strcasecmp(items[i].name, lc->str) == 0) {
968                      /* If the ITEM_NO_EQUALS flag is set we do NOT
969                       *   scan for = after the keyword  */
970                      if (!(items[i].flags & ITEM_NO_EQUALS)) {
971                         token = lex_get_token(lc, T_SKIP_EOL);
972                         Dmsg1 (900, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
973                         if (token != T_EQUALS) {
974                            scan_err1(lc, _("expected an equals, got: %s"), lc->str);
975                            goto bail_out;
976                         }
977                      }
978                      Dmsg1(800, "calling handler for %s\n", items[i].name);
979                      /* Call item handler */
980                      items[i].handler(lc, &items[i], i, pass);
981                      i = -1;
982                      break;
983                   }
984                }
985                if (i >= 0) {
986                   Dmsg2(900, "level=%d id=%s\n", level, lc->str);
987                   Dmsg1(900, "Keyword = %s\n", lc->str);
988                   scan_err1(lc, _("Keyword \"%s\" not permitted in this resource.\n"
989                      "Perhaps you left the trailing brace off of the previous resource."), lc->str);
990                   goto bail_out;
991                }
992                break;
993
994             case T_EOB:
995                level--;
996                state = p_none;
997                Dmsg0(900, "T_EOB => define new resource\n");
998                if (res_all.hdr.name == NULL) {
999                   scan_err0(lc, _("Name not specified for resource"));
1000                   goto bail_out;
1001                }
1002                save_resource(res_type, items, pass);  /* save resource */
1003                break;
1004
1005             case T_EOL:
1006                break;
1007
1008             default:
1009                scan_err2(lc, _("unexpected token %d %s in resource definition"),
1010                   token, lex_tok_to_str(token));
1011                goto bail_out;
1012             }
1013             break;
1014          default:
1015             scan_err1(lc, _("Unknown parser state %d\n"), state);
1016             goto bail_out;
1017          }
1018       }
1019       if (state != p_none) {
1020          scan_err0(lc, _("End of conf file reached with unclosed resource."));
1021          goto bail_out;
1022       }
1023       if (debug_level >= 900 && pass == 2) {
1024          int i;
1025          for (i=m_r_first; i<=m_r_last; i++) {
1026             dump_resource(i, m_res_head[i-m_r_first], prtmsg, NULL);
1027          }
1028       }
1029       lc = lex_close_file(lc);
1030    }
1031    Dmsg0(900, "Leave parse_config()\n");
1032    return 1;
1033 bail_out:
1034    if (lc) {
1035       lc = lex_close_file(lc);
1036    }
1037    return 0;
1038 }
1039
1040 const char *get_default_configdir()
1041 {
1042    return SYSCONFDIR;
1043 }
1044
1045 /*
1046  * Returns false on error
1047  *         true  on OK, with full_path set to where config file should be
1048  */
1049 static bool
1050 find_config_file(const char *config_file, char *full_path, int max_path)
1051 {
1052    int file_length = strlen(config_file) + 1;
1053
1054    /* If a full path specified, use it */
1055    if (first_path_separator(config_file) != NULL) {
1056       if (file_length > max_path) {
1057          return false;
1058       }
1059       bstrncpy(full_path, config_file, file_length);
1060       return true;
1061    }
1062
1063    /* config_file is default file name, now find default dir */
1064    const char *config_dir = get_default_configdir();
1065    int dir_length = strlen(config_dir);
1066
1067    if ((dir_length + 1 + file_length) > max_path) {
1068       return false;
1069    }
1070
1071    memcpy(full_path, config_dir, dir_length + 1);
1072
1073    if (!IsPathSeparator(full_path[dir_length - 1])) {
1074       full_path[dir_length++] = '/';
1075    }
1076
1077    memcpy(&full_path[dir_length], config_file, file_length);
1078
1079    return true;
1080 }
1081
1082 /*********************************************************************
1083  *
1084  *      Free configuration resources
1085  *
1086  */
1087 void CONFIG::free_resources()
1088 {
1089    for (int i=m_r_first; i<=m_r_last; i++) {
1090       free_resource(m_res_head[i-m_r_first], i);
1091       m_res_head[i-m_r_first] = NULL;
1092    }
1093 }
1094
1095 RES **CONFIG::save_resources()
1096 {
1097    int num = m_r_last - m_r_first + 1;
1098    RES **res = (RES **)malloc(num*sizeof(RES *));
1099    for (int i=0; i<num; i++) {
1100       res[i] = m_res_head[i];
1101       m_res_head[i] = NULL;
1102    }
1103    return res;
1104 }
1105
1106 RES **CONFIG::new_res_head()
1107 {
1108    int size = (m_r_last - m_r_first + 1) * sizeof(RES *);
1109    RES **res = (RES **)malloc(size);
1110    memset(res, 0, size);
1111    return res;
1112 }
1113
1114
1115 #ifdef xxx
1116 void free_config_resources()
1117 {
1118    for (int i=r_first; i<=r_last; i++) {
1119       free_resource(res_head[i-r_first], i);
1120       res_head[i-r_first] = NULL;
1121    }
1122 }
1123
1124 RES **save_config_resources()
1125 {
1126    int num = r_last - r_first + 1;
1127    RES **res = (RES **)malloc(num*sizeof(RES *));
1128    for (int i=0; i<num; i++) {
1129       res[i] = res_head[i];
1130       res_head[i] = NULL;
1131    }
1132    return res;
1133 }
1134
1135 RES **new_res_head()
1136 {
1137    int size = (r_last - r_first + 1) * sizeof(RES *);
1138    RES **res = (RES **)malloc(size);
1139    memset(res, 0, size);
1140    return res;
1141 }
1142 #endif