]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/parse_conf.c
Tweak leave SQL library links in rpm
[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, ITEM_ALLOW_DUPS, 0},
95    {"OperatorCommand", store_str, ITEM(res_msgs.operator_cmd), 0, ITEM_ALLOW_DUPS, 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 directives in \"%s\" resource\n"), resources[rindex].name);
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) && (item->flags & ITEM_ALLOW_DUPS)) {
408          free(*(item->value));
409          *(item->value) = NULL;
410       }
411       if (*(item->value)) {
412          scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
413             item->name, *(item->value), lc->str, lc->line_no, lc->line);
414          return;
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 directory name at specified address. Note, we do
424  *   shell expansion except if the string begins with a vertical
425  *   bar (i.e. it will likely be passed to the shell later).
426  */
427 void store_dir(LEX *lc, RES_ITEM *item, int index, int pass)
428 {
429    lex_get_token(lc, T_STRING);
430    if (pass == 1) {
431       if (lc->str[0] != '|') {
432          do_shell_expansion(lc->str, sizeof_pool_memory(lc->str));
433       }
434       if (*(item->value)) {
435          scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
436             item->name, *(item->value), lc->str, lc->line_no, lc->line);
437          return;
438       }
439       *(item->value) = bstrdup(lc->str);
440    }
441    scan_to_eol(lc);
442    set_bit(index, res_all.hdr.item_present);
443 }
444
445
446 /* Store a password specified address in MD5 coding */
447 void store_password(LEX *lc, RES_ITEM *item, int index, int pass)
448 {
449    unsigned int i, j;
450    struct MD5Context md5c;
451    unsigned char digest[CRYPTO_DIGEST_MD5_SIZE];
452    char sig[100];
453
454
455    lex_get_token(lc, T_STRING);
456    if (pass == 1) {
457       MD5Init(&md5c);
458       MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
459       MD5Final(digest, &md5c);
460       for (i = j = 0; i < sizeof(digest); i++) {
461          sprintf(&sig[j], "%02x", digest[i]);
462          j += 2;
463       }
464       if (*(item->value)) {
465          scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
466             item->name, *(item->value), lc->str, lc->line_no, lc->line);
467          return;
468       }
469       *(item->value) = bstrdup(sig);
470    }
471    scan_to_eol(lc);
472    set_bit(index, res_all.hdr.item_present);
473 }
474
475
476 /* Store a resource at specified address.
477  * If we are in pass 2, do a lookup of the
478  * resource.
479  */
480 void store_res(LEX *lc, RES_ITEM *item, int index, int pass)
481 {
482    RES *res;
483
484    lex_get_token(lc, T_NAME);
485    if (pass == 2) {
486       res = GetResWithName(item->code, lc->str);
487       if (res == NULL) {
488          scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
489             lc->str, lc->line_no, lc->line);
490          return;
491       }
492       if (*(item->value)) {
493          scan_err3(lc, _("Attempt to redefine resource \"%s\" referenced on line %d : %s\n"),
494             item->name, lc->line_no, lc->line);
495          return;
496       }
497       *(item->value) = (char *)res;
498    }
499    scan_to_eol(lc);
500    set_bit(index, res_all.hdr.item_present);
501 }
502
503 /*
504  * Store a resource pointer in an alist. default_value indicates how many
505  *   times this routine can be called -- i.e. how many alists
506  *   there are.
507  * If we are in pass 2, do a lookup of the
508  *   resource.
509  */
510 void store_alist_res(LEX *lc, RES_ITEM *item, int index, int pass)
511 {
512    RES *res;
513    int count = item->default_value;
514    int i = 0;
515    alist *list;
516
517    if (pass == 2) {
518       if (count == 0) {               /* always store in item->value */
519          i = 0;
520          if ((item->value)[i] == NULL) {
521             list = New(alist(10, not_owned_by_alist));
522          } else {
523             list = (alist *)(item->value)[i];
524          }
525       } else {
526          /* Find empty place to store this directive */
527          while ((item->value)[i] != NULL && i++ < count) { }
528          if (i >= count) {
529             scan_err4(lc, _("Too many %s directives. Max. is %d. line %d: %s\n"),
530                lc->str, count, lc->line_no, lc->line);
531             return;
532          }
533          list = New(alist(10, not_owned_by_alist));
534       }
535
536       for (;;) {
537          lex_get_token(lc, T_NAME);   /* scan next item */
538          res = GetResWithName(item->code, lc->str);
539          if (res == NULL) {
540             scan_err3(lc, _("Could not find config Resource \"%s\" referenced on line %d : %s\n"),
541                item->name, lc->line_no, lc->line);
542             return;
543          }
544          Dmsg5(900, "Append %p to alist %p size=%d i=%d %s\n",
545                res, list, list->size(), i, item->name);
546          list->append(res);
547          (item->value)[i] = (char *)list;
548          if (lc->ch != ',') {         /* if no other item follows */
549             break;                    /* get out */
550          }
551          lex_get_token(lc, T_ALL);    /* eat comma */
552       }
553    }
554    scan_to_eol(lc);
555    set_bit(index, res_all.hdr.item_present);
556 }
557
558
559 /*
560  * Store a string in an alist.
561  */
562 void store_alist_str(LEX *lc, RES_ITEM *item, int index, int pass)
563 {
564    alist *list;
565
566    if (pass == 2) {
567       if (*(item->value) == NULL) {
568          list = New(alist(10, owned_by_alist));
569          *(item->value) = (char *)list;
570       } else {
571          list = (alist *)(*(item->value));
572       }
573       for (;;) {
574          lex_get_token(lc, T_STRING);   /* scan next item */
575          Dmsg4(900, "Append %s to alist 0x%p size=%d %s\n",
576             lc->str, list, list->size(), item->name);
577          list->append(bstrdup(lc->str));
578          if (lc->ch != ',') {         /* if no other item follows */
579             break;                    /* get out */
580          }
581          lex_get_token(lc, T_ALL);    /* eat comma */
582       }
583    }
584    scan_to_eol(lc);
585    set_bit(index, res_all.hdr.item_present);
586 }
587
588
589
590 /*
591  * Store default values for Resource from xxxDefs
592  * If we are in pass 2, do a lookup of the
593  * resource and store everything not explicitly set
594  * in main resource.
595  *
596  * Note, here item points to the main resource (e.g. Job, not
597  *  the jobdefs, which we look up).
598  */
599 void store_defs(LEX *lc, RES_ITEM *item, int index, int pass)
600 {
601    RES *res;
602
603    lex_get_token(lc, T_NAME);
604    if (pass == 2) {
605      Dmsg2(900, "Code=%d name=%s\n", item->code, lc->str);
606      res = GetResWithName(item->code, lc->str);
607      if (res == NULL) {
608         scan_err3(lc, _("Missing config Resource \"%s\" referenced on line %d : %s\n"),
609            lc->str, lc->line_no, lc->line);
610         return;
611      }
612    }
613    scan_to_eol(lc);
614 }
615
616
617
618 /* Store an integer at specified address */
619 void store_int32(LEX *lc, RES_ITEM *item, int index, int pass)
620 {
621    lex_get_token(lc, T_INT32);
622    *(uint32_t *)(item->value) = lc->int32_val;
623    scan_to_eol(lc);
624    set_bit(index, res_all.hdr.item_present);
625 }
626
627 /* Store a positive integer at specified address */
628 void store_pint32(LEX *lc, RES_ITEM *item, int index, int pass)
629 {
630    lex_get_token(lc, T_PINT32);
631    *(uint32_t *)(item->value) = lc->pint32_val;
632    scan_to_eol(lc);
633    set_bit(index, res_all.hdr.item_present);
634 }
635
636
637 /* Store an 64 bit integer at specified address */
638 void store_int64(LEX *lc, RES_ITEM *item, int index, int pass)
639 {
640    lex_get_token(lc, T_INT64);
641    *(int64_t *)(item->value) = lc->int64_val;
642    scan_to_eol(lc);
643    set_bit(index, res_all.hdr.item_present);
644 }
645
646 enum store_unit_type {
647    STORE_SIZE,
648    STORE_SPEED
649 } ;
650
651 /* Store a size in bytes */
652 static void store_int_unit(LEX *lc, RES_ITEM *item, int index, int pass,
653                            bool size32, enum store_unit_type type)
654 {
655    int token;
656    uint64_t uvalue;
657    char bsize[500];
658
659    Dmsg0(900, "Enter store_unit\n");
660    token = lex_get_token(lc, T_SKIP_EOL);
661    errno = 0;
662    switch (token) {
663    case T_NUMBER:
664    case T_IDENTIFIER:
665    case T_UNQUOTED_STRING:
666       bstrncpy(bsize, lc->str, sizeof(bsize));  /* save first part */
667       /* if terminated by space, scan and get modifier */
668       while (lc->ch == ' ') {
669          token = lex_get_token(lc, T_ALL);
670          switch (token) {
671          case T_NUMBER:
672          case T_IDENTIFIER:
673          case T_UNQUOTED_STRING:
674             bstrncat(bsize, lc->str, sizeof(bsize));
675             break;
676          }
677       }
678       if (type == STORE_SIZE) {
679          if (!size_to_uint64(bsize, strlen(bsize), &uvalue)) {
680             scan_err1(lc, _("expected a size number, got: %s"), lc->str);
681             return;
682          }
683       } else {
684          if (!speed_to_uint64(bsize, strlen(bsize), &uvalue)) {
685             scan_err1(lc, _("expected a speed number, got: %s"), lc->str);
686             return;
687          }
688       }
689       if (size32) {
690          *(uint32_t *)(item->value) = (uint32_t)uvalue;
691       } else {
692          *(uint64_t *)(item->value) = uvalue;
693       }
694       break;
695    default:
696       scan_err2(lc, _("expected a %s, got: %s"),
697                 (type == STORE_SIZE)?_("size"):_("speed"), lc->str);
698       return;
699    }
700    if (token != T_EOL) {
701       scan_to_eol(lc);
702    }
703    set_bit(index, res_all.hdr.item_present);
704    Dmsg0(900, "Leave store_unit\n");
705 }
706
707 /* Store a size in bytes */
708 void store_size32(LEX *lc, RES_ITEM *item, int index, int pass)
709 {
710    store_int_unit(lc, item, index, pass, true /* 32 bit */, STORE_SIZE);
711 }
712
713 /* Store a size in bytes */
714 void store_size64(LEX *lc, RES_ITEM *item, int index, int pass)
715 {
716    store_int_unit(lc, item, index, pass, false /* not 32 bit */, STORE_SIZE);
717 }
718
719 /* Store a speed in bytes/s */
720 void store_speed(LEX *lc, RES_ITEM *item, int index, int pass)
721 {
722    store_int_unit(lc, item, index, pass, false /* 64 bit */, STORE_SPEED);
723 }
724
725 /* Store a time period in seconds */
726 void store_time(LEX *lc, RES_ITEM *item, int index, int pass)
727 {
728    int token;
729    utime_t utime;
730    char period[500];
731
732    token = lex_get_token(lc, T_SKIP_EOL);
733    errno = 0;
734    switch (token) {
735    case T_NUMBER:
736    case T_IDENTIFIER:
737    case T_UNQUOTED_STRING:
738       bstrncpy(period, lc->str, sizeof(period));  /* get first part */
739       /* if terminated by space, scan and get modifier */
740       while (lc->ch == ' ') {
741          token = lex_get_token(lc, T_ALL);
742          switch (token) {
743          case T_NUMBER:
744          case T_IDENTIFIER:
745          case T_UNQUOTED_STRING:
746             bstrncat(period, lc->str, sizeof(period));
747             break;
748          }
749       }
750       if (!duration_to_utime(period, &utime)) {
751          scan_err1(lc, _("expected a time period, got: %s"), period);
752          return;
753       }
754       *(utime_t *)(item->value) = utime;
755       break;
756    default:
757       scan_err1(lc, _("expected a time period, got: %s"), lc->str);
758       return;
759    }
760    if (token != T_EOL) {
761       scan_to_eol(lc);
762    }
763    set_bit(index, res_all.hdr.item_present);
764 }
765
766
767 /* Store a yes/no in a bit field */
768 void store_bit(LEX *lc, RES_ITEM *item, int index, int pass)
769 {
770    lex_get_token(lc, T_NAME);
771    if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
772       *(uint32_t *)(item->value) |= item->code;
773    } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
774       *(uint32_t *)(item->value) &= ~(item->code);
775    } else {
776       scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
777       return;
778    }
779    scan_to_eol(lc);
780    set_bit(index, res_all.hdr.item_present);
781 }
782
783 /* Store a bool in a bit field */
784 void store_bool(LEX *lc, RES_ITEM *item, int index, int pass)
785 {
786    lex_get_token(lc, T_NAME);
787    if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
788       *(bool *)(item->value) = true;
789    } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
790       *(bool *)(item->value) = false;
791    } else {
792       scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
793       return;
794    }
795    scan_to_eol(lc);
796    set_bit(index, res_all.hdr.item_present);
797 }
798
799
800 /*
801  * Store Tape Label Type (Bacula, ANSI, IBM)
802  *
803  */
804 void store_label(LEX *lc, RES_ITEM *item, int index, int pass)
805 {
806    int i;
807
808    lex_get_token(lc, T_NAME);
809    /* Store the label pass 2 so that type is defined */
810    for (i=0; tapelabels[i].name; i++) {
811       if (strcasecmp(lc->str, tapelabels[i].name) == 0) {
812          *(uint32_t *)(item->value) = tapelabels[i].token;
813          i = 0;
814          break;
815       }
816    }
817    if (i != 0) {
818       scan_err1(lc, _("Expected a Tape Label keyword, got: %s"), lc->str);
819       return;
820    }
821    scan_to_eol(lc);
822    set_bit(index, res_all.hdr.item_present);
823 }
824
825
826 /* Parser state */
827 enum parse_state {
828    p_none,
829    p_resource
830 };
831
832 CONFIG *new_config_parser()
833 {
834    CONFIG *config;
835    config = (CONFIG *)malloc(sizeof(CONFIG));
836    memset(config, 0, sizeof(CONFIG));
837    return config;
838 }
839
840 void CONFIG::init(
841    const char *cf,
842    LEX_ERROR_HANDLER *scan_error,
843    int32_t err_type,
844    void *vres_all,
845    int32_t res_all_size,
846    int32_t r_first,
847    int32_t r_last,
848    RES_TABLE *resources,
849    RES **res_head)
850 {
851    m_cf = cf;
852    m_scan_error = scan_error;
853    m_err_type = err_type;
854    m_res_all = vres_all;
855    m_res_all_size = res_all_size;
856    m_r_first = r_first;
857    m_r_last = r_last;
858    m_resources = resources;
859    m_res_head = res_head;
860 }
861
862 /*********************************************************************
863  *
864  * Parse configuration file
865  *
866  * Return 0 if reading failed, 1 otherwise
867  *  Note, the default behavior unless you have set an alternate
868  *  scan_error handler is to die on an error.
869  */
870 bool CONFIG::parse_config()
871 {
872    LEX *lc = NULL;
873    int token, i, pass;
874    int res_type = 0;
875    enum parse_state state = p_none;
876    RES_ITEM *items = NULL;
877    int level = 0;
878    static bool first = true;
879    int errstat;
880    const char *cf = m_cf;
881    LEX_ERROR_HANDLER *scan_error = m_scan_error;
882    int err_type = m_err_type;
883
884    if (first && (errstat=rwl_init(&res_lock)) != 0) {
885       berrno be;
886       Jmsg1(NULL, M_ABORT, 0, _("Unable to initialize resource lock. ERR=%s\n"),
887             be.bstrerror(errstat));
888    }
889    first = false;
890
891    char *full_path = (char *)alloca(MAX_PATH + 1);
892
893    if (!find_config_file(cf, full_path, MAX_PATH +1)) {
894       Jmsg0(NULL, M_ABORT, 0, _("Config filename too long.\n"));
895    }
896    cf = full_path;
897
898    /* Make two passes. The first builds the name symbol table,
899     * and the second picks up the items.
900     */
901    Dmsg0(900, "Enter parse_config()\n");
902    for (pass=1; pass <= 2; pass++) {
903       Dmsg1(900, "parse_config pass %d\n", pass);
904       if ((lc = lex_open_file(lc, cf, scan_error)) == NULL) {
905          berrno be;
906          /* We must create a lex packet to print the error */
907          lc = (LEX *)malloc(sizeof(LEX));
908          memset(lc, 0, sizeof(LEX));
909          lc->str = get_memory(5000);
910          if (scan_error) {
911             lc->scan_error = scan_error;
912          } else {
913             lex_set_default_error_handler(lc);
914          }
915          lex_set_error_handler_error_type(lc, err_type) ;
916          pm_strcpy(lc->str, cf);
917          lc->fname = lc->str;
918          scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
919             lc->str, be.bstrerror());
920          free_pool_memory(lc->str);
921          free(lc);
922          return 0;
923       }
924       lex_set_error_handler_error_type(lc, err_type) ;
925       while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
926          Dmsg3(900, "parse state=%d pass=%d got token=%s\n", state, pass,
927               lex_tok_to_str(token));
928          switch (state) {
929          case p_none:
930             if (token == T_EOL) {
931                break;
932             } else if (token == T_UTF8_BOM) {
933                /* We can assume the file is UTF-8 as we have seen a UTF-8 BOM */
934                break;
935             } else if (token == T_UTF16_BOM) {
936                scan_err0(lc, _("Currently we cannot handle UTF-16 source files. "
937                    "Please convert the conf file to UTF-8\n"));
938                goto bail_out;
939             } else if (token != T_IDENTIFIER) {
940                scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
941                goto bail_out;
942             }
943             for (i=0; resources[i].name; i++) {
944                if (strcasecmp(resources[i].name, lc->str) == 0) {
945                   items = resources[i].items;
946                   if (!items) {
947                      break;
948                   }
949                   state = p_resource;
950                   res_type = resources[i].rcode;
951                   init_resource(this, res_type, items, pass);
952                   break;
953                }
954             }
955             if (state == p_none) {
956                scan_err1(lc, _("expected resource name, got: %s"), lc->str);
957                goto bail_out;
958             }
959             break;
960          case p_resource:
961             switch (token) {
962             case T_BOB:
963                level++;
964                break;
965             case T_IDENTIFIER:
966                if (level != 1) {
967                   scan_err1(lc, _("not in resource definition: %s"), lc->str);
968                   goto bail_out;
969                }
970                for (i=0; items[i].name; i++) {
971                   if (strcasecmp(items[i].name, lc->str) == 0) {
972                      /* If the ITEM_NO_EQUALS flag is set we do NOT
973                       *   scan for = after the keyword  */
974                      if (!(items[i].flags & ITEM_NO_EQUALS)) {
975                         token = lex_get_token(lc, T_SKIP_EOL);
976                         Dmsg1 (900, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
977                         if (token != T_EQUALS) {
978                            scan_err1(lc, _("expected an equals, got: %s"), lc->str);
979                            goto bail_out;
980                         }
981                      }
982                      Dmsg1(800, "calling handler for %s\n", items[i].name);
983                      /* Call item handler */
984                      items[i].handler(lc, &items[i], i, pass);
985                      i = -1;
986                      break;
987                   }
988                }
989                if (i >= 0) {
990                   Dmsg2(900, "level=%d id=%s\n", level, lc->str);
991                   Dmsg1(900, "Keyword = %s\n", lc->str);
992                   scan_err1(lc, _("Keyword \"%s\" not permitted in this resource.\n"
993                      "Perhaps you left the trailing brace off of the previous resource."), lc->str);
994                   goto bail_out;
995                }
996                break;
997
998             case T_EOB:
999                level--;
1000                state = p_none;
1001                Dmsg0(900, "T_EOB => define new resource\n");
1002                if (res_all.hdr.name == NULL) {
1003                   scan_err0(lc, _("Name not specified for resource"));
1004                   goto bail_out;
1005                }
1006                save_resource(res_type, items, pass);  /* save resource */
1007                break;
1008
1009             case T_EOL:
1010                break;
1011
1012             default:
1013                scan_err2(lc, _("unexpected token %d %s in resource definition"),
1014                   token, lex_tok_to_str(token));
1015                goto bail_out;
1016             }
1017             break;
1018          default:
1019             scan_err1(lc, _("Unknown parser state %d\n"), state);
1020             goto bail_out;
1021          }
1022       }
1023       if (state != p_none) {
1024          scan_err0(lc, _("End of conf file reached with unclosed resource."));
1025          goto bail_out;
1026       }
1027       if (debug_level >= 900 && pass == 2) {
1028          int i;
1029          for (i=m_r_first; i<=m_r_last; i++) {
1030             dump_resource(i, m_res_head[i-m_r_first], prtmsg, NULL);
1031          }
1032       }
1033       lc = lex_close_file(lc);
1034    }
1035    Dmsg0(900, "Leave parse_config()\n");
1036    return 1;
1037 bail_out:
1038    if (lc) {
1039       lc = lex_close_file(lc);
1040    }
1041    return 0;
1042 }
1043
1044 const char *get_default_configdir()
1045 {
1046    return SYSCONFDIR;
1047 }
1048
1049 /*
1050  * Returns false on error
1051  *         true  on OK, with full_path set to where config file should be
1052  */
1053 static bool
1054 find_config_file(const char *config_file, char *full_path, int max_path)
1055 {
1056    int file_length = strlen(config_file) + 1;
1057
1058    /* If a full path specified, use it */
1059    if (first_path_separator(config_file) != NULL) {
1060       if (file_length > max_path) {
1061          return false;
1062       }
1063       bstrncpy(full_path, config_file, file_length);
1064       return true;
1065    }
1066
1067    /* config_file is default file name, now find default dir */
1068    const char *config_dir = get_default_configdir();
1069    int dir_length = strlen(config_dir);
1070
1071    if ((dir_length + 1 + file_length) > max_path) {
1072       return false;
1073    }
1074
1075    memcpy(full_path, config_dir, dir_length + 1);
1076
1077    if (!IsPathSeparator(full_path[dir_length - 1])) {
1078       full_path[dir_length++] = '/';
1079    }
1080
1081    memcpy(&full_path[dir_length], config_file, file_length);
1082
1083    return true;
1084 }
1085
1086 /*********************************************************************
1087  *
1088  *      Free configuration resources
1089  *
1090  */
1091 void CONFIG::free_resources()
1092 {
1093    for (int i=m_r_first; i<=m_r_last; i++) {
1094       free_resource(m_res_head[i-m_r_first], i);
1095       m_res_head[i-m_r_first] = NULL;
1096    }
1097 }
1098
1099 RES **CONFIG::save_resources()
1100 {
1101    int num = m_r_last - m_r_first + 1;
1102    RES **res = (RES **)malloc(num*sizeof(RES *));
1103    for (int i=0; i<num; i++) {
1104       res[i] = m_res_head[i];
1105       m_res_head[i] = NULL;
1106    }
1107    return res;
1108 }
1109
1110 RES **CONFIG::new_res_head()
1111 {
1112    int size = (m_r_last - m_r_first + 1) * sizeof(RES *);
1113    RES **res = (RES **)malloc(size);
1114    memset(res, 0, size);
1115    return res;
1116 }
1117
1118
1119 #ifdef xxx
1120 void free_config_resources()
1121 {
1122    for (int i=r_first; i<=r_last; i++) {
1123       free_resource(res_head[i-r_first], i);
1124       res_head[i-r_first] = NULL;
1125    }
1126 }
1127
1128 RES **save_config_resources()
1129 {
1130    int num = r_last - r_first + 1;
1131    RES **res = (RES **)malloc(num*sizeof(RES *));
1132    for (int i=0; i<num; i++) {
1133       res[i] = res_head[i];
1134       res_head[i] = NULL;
1135    }
1136    return res;
1137 }
1138
1139 RES **new_res_head()
1140 {
1141    int size = (r_last - r_first + 1) * sizeof(RES *);
1142    RES **res = (RES **)malloc(size);
1143    memset(res, 0, size);
1144    return res;
1145 }
1146 #endif