2 * Master Configuration routines.
4 * This file contains the common parts of the Bacula
5 * configuration routines.
7 * Note, the configuration file parser consists of three parts
9 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
11 * 2. The generic config scanner in lib/parse_conf.c and
13 * These files contain the parser code, some utility
14 * routines, and the common store routines (name, int,
15 * string, time, int64, size, ...).
17 * 3. The daemon specific file, which contains the Resource
18 * definitions as well as any specific store routines
19 * for the resource records.
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
31 * Kern Sibbald, January MM
36 Copyright (C) 2000-2006 Kern Sibbald
38 This program is free software; you can redistribute it and/or
39 modify it under the terms of the GNU General Public License
40 version 2 as amended with additional clauses defined in the
41 file LICENSE in the main source directory.
43 This program is distributed in the hope that it will be useful,
44 but WITHOUT ANY WARRANTY; without even the implied warranty of
45 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46 the file LICENSE for additional details.
53 #if defined(HAVE_WIN32)
59 /* Each daemon has a slightly different set of
60 * resources, so it will define the following
65 extern RES_TABLE resources[];
66 extern RES **res_head;
69 // work around visual studio name mangling preventing external linkage since res_all
70 // is declared as a different type when instantiated.
71 extern "C" CURES res_all;
75 extern int res_all_size;
77 extern brwlock_t res_lock; /* resource lock */
80 /* Forward referenced subroutines */
81 static void scan_types(LEX *lc, MSGS *msg, int dest, char *where, char *cmd);
82 static const char *get_default_configdir();
83 static bool find_config_file(const char *config_file, char *full_path);
85 /* Common Resource definitions */
87 /* Message resource directives
88 * name handler value code flags default_value
90 RES_ITEM msgs_items[] = {
91 {"name", store_name, ITEM(res_msgs.hdr.name), 0, 0, 0},
92 {"description", store_str, ITEM(res_msgs.hdr.desc), 0, 0, 0},
93 {"mailcommand", store_str, ITEM(res_msgs.mail_cmd), 0, 0, 0},
94 {"operatorcommand", store_str, ITEM(res_msgs.operator_cmd), 0, 0, 0},
95 {"syslog", store_msgs, ITEM(res_msgs), MD_SYSLOG, 0, 0},
96 {"mail", store_msgs, ITEM(res_msgs), MD_MAIL, 0, 0},
97 {"mailonerror", store_msgs, ITEM(res_msgs), MD_MAIL_ON_ERROR, 0, 0},
98 {"mailonsuccess", store_msgs, ITEM(res_msgs), MD_MAIL_ON_SUCCESS, 0, 0},
99 {"file", store_msgs, ITEM(res_msgs), MD_FILE, 0, 0},
100 {"append", store_msgs, ITEM(res_msgs), MD_APPEND, 0, 0},
101 {"stdout", store_msgs, ITEM(res_msgs), MD_STDOUT, 0, 0},
102 {"stderr", store_msgs, ITEM(res_msgs), MD_STDERR, 0, 0},
103 {"director", store_msgs, ITEM(res_msgs), MD_DIRECTOR, 0, 0},
104 {"console", store_msgs, ITEM(res_msgs), MD_CONSOLE, 0, 0},
105 {"operator", store_msgs, ITEM(res_msgs), MD_OPERATOR, 0, 0},
106 {"catalog", store_msgs, ITEM(res_msgs), MD_CATALOG, 0, 0},
107 {NULL, NULL, {0}, 0, 0, 0}
114 /* Various message types */
115 static struct s_mtypes msg_types[] = {
120 {"warning", M_WARNING},
123 {"notsaved", M_NOTSAVED},
124 {"skipped", M_SKIPPED},
126 {"terminate", M_TERM},
127 {"restored", M_RESTORED},
128 {"security", M_SECURITY},
130 {"volmgmt", M_VOLMGMT},
135 /* Used for certain KeyWord tables */
142 * Tape Label types permitted in Pool records
144 * tape label label code = token
146 static s_kw tapelabels[] = {
147 {"bacula", B_BACULA_LABEL},
148 {"ansi", B_ANSI_LABEL},
149 {"ibm", B_IBM_LABEL},
154 /* Simply print a message */
155 static void prtmsg(void *sock, const char *fmt, ...)
159 va_start(arg_ptr, fmt);
160 vfprintf(stdout, fmt, arg_ptr);
164 const char *res_to_str(int rcode)
166 if (rcode < r_first || rcode > r_last) {
167 return _("***UNKNOWN***");
169 return resources[rcode-r_first].name;
175 * Initialize the static structure to zeros, then
176 * apply all the default values.
178 void init_resource(int type, RES_ITEM *items, int pass)
181 int rindex = type - r_first;
182 static bool first = true;
185 if (first && (errstat=rwl_init(&res_lock)) != 0) {
186 Emsg1(M_ABORT, 0, _("Unable to initialize resource lock. ERR=%s\n"),
191 memset(&res_all, 0, res_all_size);
192 res_all.hdr.rcode = type;
193 res_all.hdr.refcnt = 1;
195 /* Set defaults in each item */
196 for (i=0; items[i].name; i++) {
197 Dmsg3(900, "Item=%s def=%s defval=%d\n", items[i].name,
198 (items[i].flags & ITEM_DEFAULT) ? "yes" : "no",
199 items[i].default_value);
200 if (items[i].flags & ITEM_DEFAULT && items[i].default_value != 0) {
201 if (items[i].handler == store_bit) {
202 *(int *)(items[i].value) |= items[i].code;
203 } else if (items[i].handler == store_bool) {
204 *(bool *)(items[i].value) = items[i].default_value != 0;
205 } else if (items[i].handler == store_pint ||
206 items[i].handler == store_int) {
207 *(int *)(items[i].value) = items[i].default_value;
208 } else if (items[i].handler == store_int64) {
209 *(int64_t *)(items[i].value) = items[i].default_value;
210 } else if (items[i].handler == store_size) {
211 *(uint64_t *)(items[i].value) = (uint64_t)items[i].default_value;
212 } else if (items[i].handler == store_time) {
213 *(utime_t *)(items[i].value) = (utime_t)items[i].default_value;
214 } else if (pass == 1 && items[i].handler == store_addresses) {
215 init_default_addresses((dlist**)items[i].value, items[i].default_value);
218 /* If this triggers, take a look at lib/parse_conf.h */
219 if (i >= MAX_RES_ITEMS) {
220 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
226 /* Store Messages Destination information */
227 void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass)
234 Dmsg2(900, "store_msgs pass=%d code=%d\n", pass, item->code);
236 switch (item->code) {
239 case MD_SYSLOG: /* syslog */
242 scan_types(lc, (MSGS *)(item->value), item->code, NULL, NULL);
244 case MD_OPERATOR: /* send to operator */
245 case MD_DIRECTOR: /* send to Director */
246 case MD_MAIL: /* mail */
247 case MD_MAIL_ON_ERROR: /* mail if Job errors */
248 case MD_MAIL_ON_SUCCESS: /* mail if Job succeeds */
249 if (item->code == MD_OPERATOR) {
250 cmd = res_all.res_msgs.operator_cmd;
252 cmd = res_all.res_msgs.mail_cmd;
254 dest = get_pool_memory(PM_MESSAGE);
257 /* Pick up comma separated list of destinations */
259 token = lex_get_token(lc, T_NAME); /* scan destination */
260 dest = check_pool_memory_size(dest, dest_len + lc->str_len + 2);
262 pm_strcat(dest, " "); /* separate multiple destinations with space */
265 pm_strcat(dest, lc->str);
266 dest_len += lc->str_len;
267 Dmsg2(900, "store_msgs newdest=%s: dest=%s:\n", lc->str, NPRT(dest));
268 token = lex_get_token(lc, T_SKIP_EOL);
269 if (token == T_COMMA) {
270 continue; /* get another destination */
272 if (token != T_EQUALS) {
273 scan_err1(lc, _("expected an =, got: %s"), lc->str);
277 Dmsg1(900, "mail_cmd=%s\n", NPRT(cmd));
278 scan_types(lc, (MSGS *)(item->value), item->code, dest, cmd);
279 free_pool_memory(dest);
280 Dmsg0(900, "done with dest codes\n");
282 case MD_FILE: /* file */
283 case MD_APPEND: /* append */
284 dest = get_pool_memory(PM_MESSAGE);
285 /* Pick up a single destination */
286 token = lex_get_token(lc, T_NAME); /* scan destination */
287 pm_strcpy(dest, lc->str);
288 dest_len = lc->str_len;
289 token = lex_get_token(lc, T_SKIP_EOL);
290 Dmsg1(900, "store_msgs dest=%s:\n", NPRT(dest));
291 if (token != T_EQUALS) {
292 scan_err1(lc, _("expected an =, got: %s"), lc->str);
294 scan_types(lc, (MSGS *)(item->value), item->code, dest, NULL);
295 free_pool_memory(dest);
296 Dmsg0(900, "done with dest codes\n");
300 scan_err1(lc, _("Unknown item code: %d\n"), item->code);
305 set_bit(index, res_all.hdr.item_present);
306 Dmsg0(900, "Done store_msgs\n");
310 * Scan for message types and add them to the message
311 * destination. The basic job here is to connect message types
312 * (WARNING, ERROR, FATAL, INFO, ...) with an appropriate
313 * destination (MAIL, FILE, OPERATOR, ...)
315 static void scan_types(LEX *lc, MSGS *msg, int dest_code, char *where, char *cmd)
323 lex_get_token(lc, T_NAME); /* expect at least one type */
325 if (lc->str[0] == '!') {
332 for (i=0; msg_types[i].name; i++) {
333 if (strcasecmp(str, msg_types[i].name) == 0) {
334 msg_type = msg_types[i].token;
340 scan_err1(lc, _("message type: %s not found"), str);
344 if (msg_type == M_MAX+1) { /* all? */
345 for (i=1; i<=M_MAX; i++) { /* yes set all types */
346 add_msg_dest(msg, dest_code, i, where, cmd);
349 rem_msg_dest(msg, dest_code, msg_type, where);
351 add_msg_dest(msg, dest_code, msg_type, where, cmd);
356 Dmsg0(900, "call lex_get_token() to eat comma\n");
357 lex_get_token(lc, T_ALL); /* eat comma */
359 Dmsg0(900, "Done scan_types()\n");
364 * This routine is ONLY for resource names
365 * Store a name at specified address.
367 void store_name(LEX *lc, RES_ITEM *item, int index, int pass)
369 POOLMEM *msg = get_pool_memory(PM_EMSG);
370 lex_get_token(lc, T_NAME);
371 if (!is_name_valid(lc->str, &msg)) {
372 scan_err1(lc, "%s\n", msg);
374 free_pool_memory(msg);
375 /* Store the name both pass 1 and pass 2 */
376 if (*(item->value)) {
377 scan_err2(lc, _("Attempt to redefine name \"%s\" to \"%s\"."),
378 *(item->value), lc->str);
380 *(item->value) = bstrdup(lc->str);
382 set_bit(index, res_all.hdr.item_present);
387 * Store a name string at specified address
388 * A name string is limited to MAX_RES_NAME_LENGTH
390 void store_strname(LEX *lc, RES_ITEM *item, int index, int pass)
392 lex_get_token(lc, T_NAME);
395 *(item->value) = bstrdup(lc->str);
398 set_bit(index, res_all.hdr.item_present);
401 /* Store a string at specified address */
402 void store_str(LEX *lc, RES_ITEM *item, int index, int pass)
404 lex_get_token(lc, T_STRING);
406 *(item->value) = bstrdup(lc->str);
409 set_bit(index, res_all.hdr.item_present);
413 * Store a directory name at specified address. Note, we do
414 * shell expansion except if the string begins with a vertical
415 * bar (i.e. it will likely be passed to the shell later).
417 void store_dir(LEX *lc, RES_ITEM *item, int index, int pass)
419 lex_get_token(lc, T_STRING);
421 if (lc->str[0] != '|') {
422 do_shell_expansion(lc->str, sizeof(lc->str));
424 *(item->value) = bstrdup(lc->str);
427 set_bit(index, res_all.hdr.item_present);
431 /* Store a password specified address in MD5 coding */
432 void store_password(LEX *lc, RES_ITEM *item, int index, int pass)
435 struct MD5Context md5c;
436 unsigned char digest[CRYPTO_DIGEST_MD5_SIZE];
440 lex_get_token(lc, T_STRING);
443 MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
444 MD5Final(digest, &md5c);
445 for (i = j = 0; i < sizeof(digest); i++) {
446 sprintf(&sig[j], "%02x", digest[i]);
449 *(item->value) = bstrdup(sig);
452 set_bit(index, res_all.hdr.item_present);
456 /* Store a resource at specified address.
457 * If we are in pass 2, do a lookup of the
460 void store_res(LEX *lc, RES_ITEM *item, int index, int pass)
464 lex_get_token(lc, T_NAME);
466 res = GetResWithName(item->code, lc->str);
468 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
469 lc->str, lc->line_no, lc->line);
471 if (*(item->value)) {
472 scan_err3(lc, _("Attempt to redefine resource \"%s\" referenced on line %d : %s\n"),
473 item->name, lc->line_no, lc->line);
475 *(item->value) = (char *)res;
478 set_bit(index, res_all.hdr.item_present);
482 * Store a resource pointer in an alist. default_value indicates how many
483 * times this routine can be called -- i.e. how many alists
485 * If we are in pass 2, do a lookup of the
488 void store_alist_res(LEX *lc, RES_ITEM *item, int index, int pass)
491 int count = item->default_value;
496 if (count == 0) { /* always store in item->value */
498 if ((item->value)[i] == NULL) {
499 list = New(alist(10, not_owned_by_alist));
501 list = (alist *)(item->value)[i];
504 /* Find empty place to store this directive */
505 while ((item->value)[i] != NULL && i++ < count) { }
507 scan_err4(lc, _("Too many %s directives. Max. is %d. line %d: %s\n"),
508 lc->str, count, lc->line_no, lc->line);
510 list = New(alist(10, not_owned_by_alist));
514 lex_get_token(lc, T_NAME); /* scan next item */
515 res = GetResWithName(item->code, lc->str);
517 scan_err3(lc, _("Could not find config Resource \"%s\" referenced on line %d : %s\n"),
518 item->name, lc->line_no, lc->line);
520 Dmsg5(900, "Append %p to alist %p size=%d i=%d %s\n",
521 res, list, list->size(), i, item->name);
523 (item->value)[i] = (char *)list;
524 if (lc->ch != ',') { /* if no other item follows */
527 lex_get_token(lc, T_ALL); /* eat comma */
531 set_bit(index, res_all.hdr.item_present);
536 * Store a string in an alist.
538 void store_alist_str(LEX *lc, RES_ITEM *item, int index, int pass)
543 if (*(item->value) == NULL) {
544 list = New(alist(10, owned_by_alist));
546 list = (alist *)(*(item->value));
549 lex_get_token(lc, T_STRING); /* scan next item */
550 Dmsg4(900, "Append %s to alist %p size=%d %s\n",
551 lc->str, list, list->size(), item->name);
552 list->append(bstrdup(lc->str));
553 *(item->value) = (char *)list;
556 set_bit(index, res_all.hdr.item_present);
562 * Store default values for Resource from xxxDefs
563 * If we are in pass 2, do a lookup of the
564 * resource and store everything not explicitly set
567 * Note, here item points to the main resource (e.g. Job, not
568 * the jobdefs, which we look up).
570 void store_defs(LEX *lc, RES_ITEM *item, int index, int pass)
574 lex_get_token(lc, T_NAME);
576 Dmsg2(900, "Code=%d name=%s\n", item->code, lc->str);
577 res = GetResWithName(item->code, lc->str);
579 scan_err3(lc, _("Missing config Resource \"%s\" referenced on line %d : %s\n"),
580 lc->str, lc->line_no, lc->line);
588 /* Store an integer at specified address */
589 void store_int(LEX *lc, RES_ITEM *item, int index, int pass)
591 lex_get_token(lc, T_INT32);
592 *(int *)(item->value) = lc->int32_val;
594 set_bit(index, res_all.hdr.item_present);
597 /* Store a positive integer at specified address */
598 void store_pint(LEX *lc, RES_ITEM *item, int index, int pass)
600 lex_get_token(lc, T_PINT32);
601 *(int *)(item->value) = lc->pint32_val;
603 set_bit(index, res_all.hdr.item_present);
607 /* Store an 64 bit integer at specified address */
608 void store_int64(LEX *lc, RES_ITEM *item, int index, int pass)
610 lex_get_token(lc, T_INT64);
611 *(int64_t *)(item->value) = lc->int64_val;
613 set_bit(index, res_all.hdr.item_present);
616 /* Store a size in bytes */
617 void store_size(LEX *lc, RES_ITEM *item, int index, int pass)
623 Dmsg0(900, "Enter store_size\n");
624 token = lex_get_token(lc, T_SKIP_EOL);
629 case T_UNQUOTED_STRING:
630 bstrncpy(bsize, lc->str, sizeof(bsize)); /* save first part */
631 /* if terminated by space, scan and get modifier */
632 while (lc->ch == ' ') {
633 token = lex_get_token(lc, T_ALL);
637 case T_UNQUOTED_STRING:
638 bstrncat(bsize, lc->str, sizeof(bsize));
642 if (!size_to_uint64(bsize, strlen(bsize), &uvalue)) {
643 scan_err1(lc, _("expected a size number, got: %s"), lc->str);
645 *(uint64_t *)(item->value) = uvalue;
648 scan_err1(lc, _("expected a size, got: %s"), lc->str);
651 if (token != T_EOL) {
654 set_bit(index, res_all.hdr.item_present);
655 Dmsg0(900, "Leave store_size\n");
659 /* Store a time period in seconds */
660 void store_time(LEX *lc, RES_ITEM *item, int index, int pass)
666 token = lex_get_token(lc, T_SKIP_EOL);
671 case T_UNQUOTED_STRING:
672 bstrncpy(period, lc->str, sizeof(period)); /* get first part */
673 /* if terminated by space, scan and get modifier */
674 while (lc->ch == ' ') {
675 token = lex_get_token(lc, T_ALL);
679 case T_UNQUOTED_STRING:
680 bstrncat(period, lc->str, sizeof(period));
684 if (!duration_to_utime(period, &utime)) {
685 scan_err1(lc, _("expected a time period, got: %s"), period);
687 *(utime_t *)(item->value) = utime;
690 scan_err1(lc, _("expected a time period, got: %s"), lc->str);
693 if (token != T_EOL) {
696 set_bit(index, res_all.hdr.item_present);
700 /* Store a yes/no in a bit field */
701 void store_bit(LEX *lc, RES_ITEM *item, int index, int pass)
703 lex_get_token(lc, T_NAME);
704 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
705 *(int *)(item->value) |= item->code;
706 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
707 *(int *)(item->value) &= ~(item->code);
709 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
712 set_bit(index, res_all.hdr.item_present);
715 /* Store a bool in a bit field */
716 void store_bool(LEX *lc, RES_ITEM *item, int index, int pass)
718 lex_get_token(lc, T_NAME);
719 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
720 *(bool *)(item->value) = true;
721 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
722 *(bool *)(item->value) = false;
724 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
727 set_bit(index, res_all.hdr.item_present);
732 * Store Tape Label Type (Bacula, ANSI, IBM)
735 void store_label(LEX *lc, RES_ITEM *item, int index, int pass)
739 token = lex_get_token(lc, T_NAME);
740 /* Store the label pass 2 so that type is defined */
741 for (i=0; tapelabels[i].name; i++) {
742 if (strcasecmp(lc->str, tapelabels[i].name) == 0) {
743 *(int *)(item->value) = tapelabels[i].token;
749 scan_err1(lc, _("Expected a Tape Label keyword, got: %s"), lc->str);
752 set_bit(index, res_all.hdr.item_present);
762 /*********************************************************************
764 * Parse configuration file
766 * Return 0 if reading failed, 1 otherwise
767 * Note, the default behavior unless you have set an alternate
768 * scan_error handler is to die on an error.
771 parse_config(const char *cf, LEX_ERROR_HANDLER *scan_error, int err_type)
776 enum parse_state state = p_none;
777 RES_ITEM *items = NULL;
780 char *full_path = (char *)alloca(MAX_PATH);
782 if (find_config_file(cf, full_path)) {
786 /* Make two passes. The first builds the name symbol table,
787 * and the second picks up the items.
789 Dmsg0(900, "Enter parse_config()\n");
790 for (pass=1; pass <= 2; pass++) {
791 Dmsg1(900, "parse_config pass %d\n", pass);
792 if ((lc = lex_open_file(lc, cf, scan_error)) == NULL) {
794 /* We must create a lex packet to print the error */
795 lc = (LEX *)malloc(sizeof(LEX));
796 memset(lc, 0, sizeof(LEX));
798 lc->scan_error = scan_error;
800 lex_set_default_error_handler(lc);
802 lex_set_error_handler_error_type(lc, err_type) ;
803 bstrncpy(lc->str, cf, sizeof(lc->str));
805 scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
806 lc->str, be.strerror());
810 lex_set_error_handler_error_type(lc, err_type) ;
811 while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
812 Dmsg1(900, "parse got token=%s\n", lex_tok_to_str(token));
815 if (token == T_EOL) {
818 if (token == T_UNICODE_MARK) {
821 if (token != T_IDENTIFIER) {
822 scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
825 for (i=0; resources[i].name; i++)
826 if (strcasecmp(resources[i].name, lc->str) == 0) {
828 items = resources[i].items;
829 res_type = resources[i].rcode;
830 init_resource(res_type, items, pass);
833 if (state == p_none) {
834 scan_err1(lc, _("expected resource name, got: %s"), lc->str);
845 scan_err1(lc, _("not in resource definition: %s"), lc->str);
848 for (i=0; items[i].name; i++) {
849 if (strcasecmp(items[i].name, lc->str) == 0) {
850 /* If the ITEM_NO_EQUALS flag is set we do NOT
851 * scan for = after the keyword */
852 if (!(items[i].flags & ITEM_NO_EQUALS)) {
853 token = lex_get_token(lc, T_SKIP_EOL);
854 Dmsg1 (900, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
855 if (token != T_EQUALS) {
856 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
860 Dmsg1(800, "calling handler for %s\n", items[i].name);
861 /* Call item handler */
862 items[i].handler(lc, &items[i], i, pass);
868 Dmsg2(900, "level=%d id=%s\n", level, lc->str);
869 Dmsg1(900, "Keyword = %s\n", lc->str);
870 scan_err1(lc, _("Keyword \"%s\" not permitted in this resource.\n"
871 "Perhaps you left the trailing brace off of the previous resource."), lc->str);
879 Dmsg0(900, "T_EOB => define new resource\n");
880 if (res_all.hdr.name == NULL) {
881 scan_err0(lc, _("Name not specified for resource"));
883 save_resource(res_type, items, pass); /* save resource */
890 scan_err2(lc, _("unexpected token %d %s in resource definition"),
891 token, lex_tok_to_str(token));
896 scan_err1(lc, _("Unknown parser state %d\n"), state);
900 if (state != p_none) {
901 scan_err0(lc, _("End of conf file reached with unclosed resource."));
904 if (debug_level >= 900 && pass == 2) {
906 for (i=r_first; i<=r_last; i++) {
907 dump_resource(i, res_head[i-r_first], prtmsg, NULL);
910 lc = lex_close_file(lc);
912 Dmsg0(900, "Leave parse_config()\n");
916 const char *get_default_configdir()
918 #if defined(HAVE_WIN32)
919 #define DEFAULT_CONFIGDIR "C:\\Documents and Settings\\All Users\\Application Data\\Bacula"
922 static char szConfigDir[MAX_PATH + 1] = { 0 };
924 if (szConfigDir[0] == '\0') {
925 hr = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szConfigDir);
928 bstrncat(szConfigDir, "\\Bacula", sizeof(szConfigDir));
930 bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir));
940 find_config_file(const char *config_file, char *full_path)
942 #if defined(HAVE_WIN32)
943 if (strpbrk(config_file, ":/\\") != NULL) {
947 if (strchr(config_file, '/') != NULL) {
954 if (stat(config_file, &st) == 0) {
958 const char *config_dir = get_default_configdir();
959 size_t dir_length = strlen(config_dir);
960 size_t file_length = strlen(config_file);
962 if ((dir_length + 1 + file_length + 1) > MAX_PATH) {
966 memcpy(full_path, config_dir, dir_length + 1);
968 if (full_path[dir_length - 1] != '/' &&
969 full_path[dir_length - 1] != '\\') {
970 full_path[dir_length++] = '/';
973 memcpy(&full_path[dir_length], config_file, file_length + 1);
978 /*********************************************************************
980 * Free configuration resources
983 void free_config_resources()
985 for (int i=r_first; i<=r_last; i++) {
986 free_resource(res_head[i-r_first], i);
987 res_head[i-r_first] = NULL;
991 RES **save_config_resources()
993 int num = r_last - r_first + 1;
994 RES **res = (RES **)malloc(num*sizeof(RES *));
995 for (int i=0; i<num; i++) {
996 res[i] = res_head[i];
1002 RES **new_res_head()
1004 int size = (r_last - r_first + 1) * sizeof(RES *);
1005 RES **res = (RES **)malloc(size);
1006 memset(res, 0, size);