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 {"file", store_msgs, ITEM(res_msgs), MD_FILE, 0, 0},
99 {"append", store_msgs, ITEM(res_msgs), MD_APPEND, 0, 0},
100 {"stdout", store_msgs, ITEM(res_msgs), MD_STDOUT, 0, 0},
101 {"stderr", store_msgs, ITEM(res_msgs), MD_STDERR, 0, 0},
102 {"director", store_msgs, ITEM(res_msgs), MD_DIRECTOR, 0, 0},
103 {"console", store_msgs, ITEM(res_msgs), MD_CONSOLE, 0, 0},
104 {"operator", store_msgs, ITEM(res_msgs), MD_OPERATOR, 0, 0},
105 {"catalog", store_msgs, ITEM(res_msgs), MD_CATALOG, 0, 0},
106 {NULL, NULL, {0}, 0, 0, 0}
113 /* Various message types */
114 static struct s_mtypes msg_types[] = {
119 {"warning", M_WARNING},
122 {"notsaved", M_NOTSAVED},
123 {"skipped", M_SKIPPED},
125 {"terminate", M_TERM},
126 {"restored", M_RESTORED},
127 {"security", M_SECURITY},
129 {"volmgmt", M_VOLMGMT},
134 /* Used for certain KeyWord tables */
141 * Tape Label types permitted in Pool records
143 * tape label label code = token
145 static s_kw tapelabels[] = {
146 {"bacula", B_BACULA_LABEL},
147 {"ansi", B_ANSI_LABEL},
148 {"ibm", B_IBM_LABEL},
153 /* Simply print a message */
154 static void prtmsg(void *sock, const char *fmt, ...)
158 va_start(arg_ptr, fmt);
159 vfprintf(stdout, fmt, arg_ptr);
163 const char *res_to_str(int rcode)
165 if (rcode < r_first || rcode > r_last) {
166 return _("***UNKNOWN***");
168 return resources[rcode-r_first].name;
174 * Initialize the static structure to zeros, then
175 * apply all the default values.
177 void init_resource(int type, RES_ITEM *items, int pass)
180 int rindex = type - r_first;
181 static bool first = true;
184 if (first && (errstat=rwl_init(&res_lock)) != 0) {
185 Emsg1(M_ABORT, 0, _("Unable to initialize resource lock. ERR=%s\n"),
190 memset(&res_all, 0, res_all_size);
191 res_all.hdr.rcode = type;
192 res_all.hdr.refcnt = 1;
194 /* Set defaults in each item */
195 for (i=0; items[i].name; i++) {
196 Dmsg3(900, "Item=%s def=%s defval=%d\n", items[i].name,
197 (items[i].flags & ITEM_DEFAULT) ? "yes" : "no",
198 items[i].default_value);
199 if (items[i].flags & ITEM_DEFAULT && items[i].default_value != 0) {
200 if (items[i].handler == store_bit) {
201 *(int *)(items[i].value) |= items[i].code;
202 } else if (items[i].handler == store_bool) {
203 *(bool *)(items[i].value) = items[i].default_value != 0;
204 } else if (items[i].handler == store_pint ||
205 items[i].handler == store_int) {
206 *(int *)(items[i].value) = items[i].default_value;
207 } else if (items[i].handler == store_int64) {
208 *(int64_t *)(items[i].value) = items[i].default_value;
209 } else if (items[i].handler == store_size) {
210 *(uint64_t *)(items[i].value) = (uint64_t)items[i].default_value;
211 } else if (items[i].handler == store_time) {
212 *(utime_t *)(items[i].value) = (utime_t)items[i].default_value;
213 } else if (pass == 1 && items[i].handler == store_addresses) {
214 init_default_addresses((dlist**)items[i].value, items[i].default_value);
217 /* If this triggers, take a look at lib/parse_conf.h */
218 if (i >= MAX_RES_ITEMS) {
219 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
225 /* Store Messages Destination information */
226 void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass)
233 Dmsg2(900, "store_msgs pass=%d code=%d\n", pass, item->code);
235 switch (item->code) {
238 case MD_SYSLOG: /* syslog */
241 scan_types(lc, (MSGS *)(item->value), item->code, NULL, NULL);
243 case MD_OPERATOR: /* send to operator */
244 case MD_DIRECTOR: /* send to Director */
245 case MD_MAIL: /* mail */
246 case MD_MAIL_ON_ERROR: /* mail if Job errors */
247 if (item->code == MD_OPERATOR) {
248 cmd = res_all.res_msgs.operator_cmd;
250 cmd = res_all.res_msgs.mail_cmd;
252 dest = get_pool_memory(PM_MESSAGE);
255 /* Pick up comma separated list of destinations */
257 token = lex_get_token(lc, T_NAME); /* scan destination */
258 dest = check_pool_memory_size(dest, dest_len + lc->str_len + 2);
260 pm_strcat(dest, " "); /* separate multiple destinations with space */
263 pm_strcat(dest, lc->str);
264 dest_len += lc->str_len;
265 Dmsg2(900, "store_msgs newdest=%s: dest=%s:\n", lc->str, NPRT(dest));
266 token = lex_get_token(lc, T_SKIP_EOL);
267 if (token == T_COMMA) {
268 continue; /* get another destination */
270 if (token != T_EQUALS) {
271 scan_err1(lc, _("expected an =, got: %s"), lc->str);
275 Dmsg1(900, "mail_cmd=%s\n", NPRT(cmd));
276 scan_types(lc, (MSGS *)(item->value), item->code, dest, cmd);
277 free_pool_memory(dest);
278 Dmsg0(900, "done with dest codes\n");
280 case MD_FILE: /* file */
281 case MD_APPEND: /* append */
282 dest = get_pool_memory(PM_MESSAGE);
283 /* Pick up a single destination */
284 token = lex_get_token(lc, T_NAME); /* scan destination */
285 pm_strcpy(dest, lc->str);
286 dest_len = lc->str_len;
287 token = lex_get_token(lc, T_SKIP_EOL);
288 Dmsg1(900, "store_msgs dest=%s:\n", NPRT(dest));
289 if (token != T_EQUALS) {
290 scan_err1(lc, _("expected an =, got: %s"), lc->str);
292 scan_types(lc, (MSGS *)(item->value), item->code, dest, NULL);
293 free_pool_memory(dest);
294 Dmsg0(900, "done with dest codes\n");
298 scan_err1(lc, _("Unknown item code: %d\n"), item->code);
303 set_bit(index, res_all.hdr.item_present);
304 Dmsg0(900, "Done store_msgs\n");
308 * Scan for message types and add them to the message
309 * destination. The basic job here is to connect message types
310 * (WARNING, ERROR, FATAL, INFO, ...) with an appropriate
311 * destination (MAIL, FILE, OPERATOR, ...)
313 static void scan_types(LEX *lc, MSGS *msg, int dest_code, char *where, char *cmd)
321 lex_get_token(lc, T_NAME); /* expect at least one type */
323 if (lc->str[0] == '!') {
330 for (i=0; msg_types[i].name; i++) {
331 if (strcasecmp(str, msg_types[i].name) == 0) {
332 msg_type = msg_types[i].token;
338 scan_err1(lc, _("message type: %s not found"), str);
342 if (msg_type == M_MAX+1) { /* all? */
343 for (i=1; i<=M_MAX; i++) { /* yes set all types */
344 add_msg_dest(msg, dest_code, i, where, cmd);
347 rem_msg_dest(msg, dest_code, msg_type, where);
349 add_msg_dest(msg, dest_code, msg_type, where, cmd);
354 Dmsg0(900, "call lex_get_token() to eat comma\n");
355 lex_get_token(lc, T_ALL); /* eat comma */
357 Dmsg0(900, "Done scan_types()\n");
362 * This routine is ONLY for resource names
363 * Store a name at specified address.
365 void store_name(LEX *lc, RES_ITEM *item, int index, int pass)
367 POOLMEM *msg = get_pool_memory(PM_EMSG);
368 lex_get_token(lc, T_NAME);
369 if (!is_name_valid(lc->str, &msg)) {
370 scan_err1(lc, "%s\n", msg);
372 free_pool_memory(msg);
373 /* Store the name both pass 1 and pass 2 */
374 if (*(item->value)) {
375 scan_err2(lc, _("Attempt to redefine name \"%s\" to \"%s\"."),
376 *(item->value), lc->str);
378 *(item->value) = bstrdup(lc->str);
380 set_bit(index, res_all.hdr.item_present);
385 * Store a name string at specified address
386 * A name string is limited to MAX_RES_NAME_LENGTH
388 void store_strname(LEX *lc, RES_ITEM *item, int index, int pass)
390 lex_get_token(lc, T_NAME);
393 *(item->value) = bstrdup(lc->str);
396 set_bit(index, res_all.hdr.item_present);
399 /* Store a string at specified address */
400 void store_str(LEX *lc, RES_ITEM *item, int index, int pass)
402 lex_get_token(lc, T_STRING);
404 *(item->value) = bstrdup(lc->str);
407 set_bit(index, res_all.hdr.item_present);
411 * Store a directory name at specified address. Note, we do
412 * shell expansion except if the string begins with a vertical
413 * bar (i.e. it will likely be passed to the shell later).
415 void store_dir(LEX *lc, RES_ITEM *item, int index, int pass)
417 lex_get_token(lc, T_STRING);
419 if (lc->str[0] != '|') {
420 do_shell_expansion(lc->str, sizeof(lc->str));
422 *(item->value) = bstrdup(lc->str);
425 set_bit(index, res_all.hdr.item_present);
429 /* Store a password specified address in MD5 coding */
430 void store_password(LEX *lc, RES_ITEM *item, int index, int pass)
433 struct MD5Context md5c;
434 unsigned char digest[CRYPTO_DIGEST_MD5_SIZE];
438 lex_get_token(lc, T_STRING);
441 MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
442 MD5Final(digest, &md5c);
443 for (i = j = 0; i < sizeof(digest); i++) {
444 sprintf(&sig[j], "%02x", digest[i]);
447 *(item->value) = bstrdup(sig);
450 set_bit(index, res_all.hdr.item_present);
454 /* Store a resource at specified address.
455 * If we are in pass 2, do a lookup of the
458 void store_res(LEX *lc, RES_ITEM *item, int index, int pass)
462 lex_get_token(lc, T_NAME);
464 res = GetResWithName(item->code, lc->str);
466 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
467 lc->str, lc->line_no, lc->line);
469 if (*(item->value)) {
470 scan_err3(lc, _("Attempt to redefine resource \"%s\" referenced on line %d : %s\n"),
471 item->name, lc->line_no, lc->line);
473 *(item->value) = (char *)res;
476 set_bit(index, res_all.hdr.item_present);
480 * Store a resource pointer in an alist. default_value indicates how many
481 * times this routine can be called -- i.e. how many alists
483 * If we are in pass 2, do a lookup of the
486 void store_alist_res(LEX *lc, RES_ITEM *item, int index, int pass)
489 int count = item->default_value;
494 if (count == 0) { /* always store in item->value */
496 if ((item->value)[i] == NULL) {
497 list = New(alist(10, not_owned_by_alist));
499 list = (alist *)(item->value)[i];
502 /* Find empty place to store this directive */
503 while ((item->value)[i] != NULL && i++ < count) { }
505 scan_err4(lc, _("Too many %s directives. Max. is %d. line %d: %s\n"),
506 lc->str, count, lc->line_no, lc->line);
508 list = New(alist(10, not_owned_by_alist));
512 lex_get_token(lc, T_NAME); /* scan next item */
513 res = GetResWithName(item->code, lc->str);
515 scan_err3(lc, _("Could not find config Resource \"%s\" referenced on line %d : %s\n"),
516 item->name, lc->line_no, lc->line);
518 Dmsg5(900, "Append %p to alist %p size=%d i=%d %s\n",
519 res, list, list->size(), i, item->name);
521 (item->value)[i] = (char *)list;
522 if (lc->ch != ',') { /* if no other item follows */
525 lex_get_token(lc, T_ALL); /* eat comma */
529 set_bit(index, res_all.hdr.item_present);
534 * Store a string in an alist.
536 void store_alist_str(LEX *lc, RES_ITEM *item, int index, int pass)
541 if (*(item->value) == NULL) {
542 list = New(alist(10, owned_by_alist));
544 list = (alist *)(*(item->value));
547 lex_get_token(lc, T_STRING); /* scan next item */
548 Dmsg4(900, "Append %s to alist %p size=%d %s\n",
549 lc->str, list, list->size(), item->name);
550 list->append(bstrdup(lc->str));
551 *(item->value) = (char *)list;
554 set_bit(index, res_all.hdr.item_present);
560 * Store default values for Resource from xxxDefs
561 * If we are in pass 2, do a lookup of the
562 * resource and store everything not explicitly set
565 * Note, here item points to the main resource (e.g. Job, not
566 * the jobdefs, which we look up).
568 void store_defs(LEX *lc, RES_ITEM *item, int index, int pass)
572 lex_get_token(lc, T_NAME);
574 Dmsg2(900, "Code=%d name=%s\n", item->code, lc->str);
575 res = GetResWithName(item->code, lc->str);
577 scan_err3(lc, _("Missing config Resource \"%s\" referenced on line %d : %s\n"),
578 lc->str, lc->line_no, lc->line);
586 /* Store an integer at specified address */
587 void store_int(LEX *lc, RES_ITEM *item, int index, int pass)
589 lex_get_token(lc, T_INT32);
590 *(int *)(item->value) = lc->int32_val;
592 set_bit(index, res_all.hdr.item_present);
595 /* Store a positive integer at specified address */
596 void store_pint(LEX *lc, RES_ITEM *item, int index, int pass)
598 lex_get_token(lc, T_PINT32);
599 *(int *)(item->value) = lc->pint32_val;
601 set_bit(index, res_all.hdr.item_present);
605 /* Store an 64 bit integer at specified address */
606 void store_int64(LEX *lc, RES_ITEM *item, int index, int pass)
608 lex_get_token(lc, T_INT64);
609 *(int64_t *)(item->value) = lc->int64_val;
611 set_bit(index, res_all.hdr.item_present);
614 /* Store a size in bytes */
615 void store_size(LEX *lc, RES_ITEM *item, int index, int pass)
621 Dmsg0(900, "Enter store_size\n");
622 token = lex_get_token(lc, T_SKIP_EOL);
627 case T_UNQUOTED_STRING:
628 bstrncpy(bsize, lc->str, sizeof(bsize)); /* save first part */
629 /* if terminated by space, scan and get modifier */
630 while (lc->ch == ' ') {
631 token = lex_get_token(lc, T_ALL);
635 case T_UNQUOTED_STRING:
636 bstrncat(bsize, lc->str, sizeof(bsize));
640 if (!size_to_uint64(bsize, strlen(bsize), &uvalue)) {
641 scan_err1(lc, _("expected a size number, got: %s"), lc->str);
643 *(uint64_t *)(item->value) = uvalue;
646 scan_err1(lc, _("expected a size, got: %s"), lc->str);
649 if (token != T_EOL) {
652 set_bit(index, res_all.hdr.item_present);
653 Dmsg0(900, "Leave store_size\n");
657 /* Store a time period in seconds */
658 void store_time(LEX *lc, RES_ITEM *item, int index, int pass)
664 token = lex_get_token(lc, T_SKIP_EOL);
669 case T_UNQUOTED_STRING:
670 bstrncpy(period, lc->str, sizeof(period)); /* get first part */
671 /* if terminated by space, scan and get modifier */
672 while (lc->ch == ' ') {
673 token = lex_get_token(lc, T_ALL);
677 case T_UNQUOTED_STRING:
678 bstrncat(period, lc->str, sizeof(period));
682 if (!duration_to_utime(period, &utime)) {
683 scan_err1(lc, _("expected a time period, got: %s"), period);
685 *(utime_t *)(item->value) = utime;
688 scan_err1(lc, _("expected a time period, got: %s"), lc->str);
691 if (token != T_EOL) {
694 set_bit(index, res_all.hdr.item_present);
698 /* Store a yes/no in a bit field */
699 void store_bit(LEX *lc, RES_ITEM *item, int index, int pass)
701 lex_get_token(lc, T_NAME);
702 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
703 *(int *)(item->value) |= item->code;
704 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
705 *(int *)(item->value) &= ~(item->code);
707 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
710 set_bit(index, res_all.hdr.item_present);
713 /* Store a bool in a bit field */
714 void store_bool(LEX *lc, RES_ITEM *item, int index, int pass)
716 lex_get_token(lc, T_NAME);
717 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
718 *(bool *)(item->value) = true;
719 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
720 *(bool *)(item->value) = false;
722 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
725 set_bit(index, res_all.hdr.item_present);
730 * Store Tape Label Type (Bacula, ANSI, IBM)
733 void store_label(LEX *lc, RES_ITEM *item, int index, int pass)
737 token = lex_get_token(lc, T_NAME);
738 /* Store the label pass 2 so that type is defined */
739 for (i=0; tapelabels[i].name; i++) {
740 if (strcasecmp(lc->str, tapelabels[i].name) == 0) {
741 *(int *)(item->value) = tapelabels[i].token;
747 scan_err1(lc, _("Expected a Tape Label keyword, got: %s"), lc->str);
750 set_bit(index, res_all.hdr.item_present);
760 /*********************************************************************
762 * Parse configuration file
764 * Return 0 if reading failed, 1 otherwise
765 * Note, the default behavior unless you have set an alternate
766 * scan_error handler is to die on an error.
769 parse_config(const char *cf, LEX_ERROR_HANDLER *scan_error, int err_type)
774 enum parse_state state = p_none;
775 RES_ITEM *items = NULL;
778 char *full_path = (char *)alloca(MAX_PATH);
780 if (find_config_file(cf, full_path)) {
784 /* Make two passes. The first builds the name symbol table,
785 * and the second picks up the items.
787 Dmsg0(900, "Enter parse_config()\n");
788 for (pass=1; pass <= 2; pass++) {
789 Dmsg1(900, "parse_config pass %d\n", pass);
790 if ((lc = lex_open_file(lc, cf, scan_error)) == NULL) {
792 /* We must create a lex packet to print the error */
793 lc = (LEX *)malloc(sizeof(LEX));
794 memset(lc, 0, sizeof(LEX));
796 lc->scan_error = scan_error;
798 lex_set_default_error_handler(lc);
800 lex_set_error_handler_error_type(lc, err_type) ;
801 bstrncpy(lc->str, cf, sizeof(lc->str));
803 scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
804 lc->str, be.strerror());
808 lex_set_error_handler_error_type(lc, err_type) ;
809 while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
810 Dmsg1(900, "parse got token=%s\n", lex_tok_to_str(token));
813 if (token == T_EOL) {
816 if (token != T_IDENTIFIER) {
817 scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
820 for (i=0; resources[i].name; i++)
821 if (strcasecmp(resources[i].name, lc->str) == 0) {
823 items = resources[i].items;
824 res_type = resources[i].rcode;
825 init_resource(res_type, items, pass);
828 if (state == p_none) {
829 scan_err1(lc, _("expected resource name, got: %s"), lc->str);
840 scan_err1(lc, _("not in resource definition: %s"), lc->str);
843 for (i=0; items[i].name; i++) {
844 if (strcasecmp(items[i].name, lc->str) == 0) {
845 /* If the ITEM_NO_EQUALS flag is set we do NOT
846 * scan for = after the keyword */
847 if (!(items[i].flags & ITEM_NO_EQUALS)) {
848 token = lex_get_token(lc, T_SKIP_EOL);
849 Dmsg1 (900, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
850 if (token != T_EQUALS) {
851 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
855 Dmsg1(800, "calling handler for %s\n", items[i].name);
856 /* Call item handler */
857 items[i].handler(lc, &items[i], i, pass);
863 Dmsg2(900, "level=%d id=%s\n", level, lc->str);
864 Dmsg1(900, "Keyword = %s\n", lc->str);
865 scan_err1(lc, _("Keyword \"%s\" not permitted in this resource.\n"
866 "Perhaps you left the trailing brace off of the previous resource."), lc->str);
874 Dmsg0(900, "T_EOB => define new resource\n");
875 if (res_all.hdr.name == NULL) {
876 scan_err0(lc, _("Name not specified for resource"));
878 save_resource(res_type, items, pass); /* save resource */
885 scan_err2(lc, _("unexpected token %d %s in resource definition"),
886 token, lex_tok_to_str(token));
891 scan_err1(lc, _("Unknown parser state %d\n"), state);
895 if (state != p_none) {
896 scan_err0(lc, _("End of conf file reached with unclosed resource."));
899 if (debug_level >= 900 && pass == 2) {
901 for (i=r_first; i<=r_last; i++) {
902 dump_resource(i, res_head[i-r_first], prtmsg, NULL);
905 lc = lex_close_file(lc);
907 Dmsg0(900, "Leave parse_config()\n");
911 const char *get_default_configdir()
913 #if defined(HAVE_WIN32)
914 #define DEFAULT_CONFIGDIR "C:\\Documents and Settings\\All Users\\Application Data\\Bacula"
917 static char szConfigDir[MAX_PATH + 1] = { 0 };
919 if (szConfigDir[0] == '\0') {
920 hr = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szConfigDir);
923 bstrncat(szConfigDir, "\\Bacula", sizeof(szConfigDir));
925 bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir));
930 return "/etc/bacula";
935 find_config_file(const char *config_file, char *full_path)
937 #if defined(HAVE_WIN32)
938 if (strpbrk(config_file, ":/\\") != NULL) {
942 if (strchr(config_file, '/') != NULL) {
949 if (stat(config_file, &st) == 0) {
953 const char *config_dir = get_default_configdir();
954 size_t dir_length = strlen(config_dir);
955 size_t file_length = strlen(config_file);
957 if ((dir_length + 1 + file_length + 1) > MAX_PATH) {
961 memcpy(full_path, config_dir, dir_length + 1);
963 if (full_path[dir_length - 1] != '/' &&
964 full_path[dir_length - 1] != '\\') {
965 full_path[dir_length++] = '/';
968 memcpy(&full_path[dir_length], config_file, file_length + 1);
973 /*********************************************************************
975 * Free configuration resources
978 void free_config_resources()
980 for (int i=r_first; i<=r_last; i++) {
981 free_resource(res_head[i-r_first], i);
982 res_head[i-r_first] = NULL;
986 RES **save_config_resources()
988 int num = r_last - r_first + 1;
989 RES **res = (RES **)malloc(num*sizeof(RES *));
990 for (int i=0; i<num; i++) {
991 res[i] = res_head[i];
999 int size = (r_last - r_first + 1) * sizeof(RES *);
1000 RES **res = (RES **)malloc(size);
1001 memset(res, 0, size);