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 Bacula® - The Network Backup Solution
38 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
40 The main author of Bacula is Kern Sibbald, with contributions from
41 many others, a complete list can be found in the file AUTHORS.
42 This program is Free Software; you can redistribute it and/or
43 modify it under the terms of version two of the GNU General Public
44 License as published by the Free Software Foundation plus additions
45 that are listed in the file LICENSE.
47 This program is distributed in the hope that it will be useful, but
48 WITHOUT ANY WARRANTY; without even the implied warranty of
49 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
50 General Public License for more details.
52 You should have received a copy of the GNU General Public License
53 along with this program; if not, write to the Free Software
54 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
57 Bacula® is a registered trademark of John Walker.
58 The licensor of Bacula is the Free Software Foundation Europe
59 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
60 Switzerland, email:ftf@fsfeurope.org.
66 #if defined(HAVE_WIN32)
72 /* Each daemon has a slightly different set of
73 * resources, so it will define the following
78 extern RES_TABLE resources[];
79 extern RES **res_head;
82 // work around visual studio name mangling preventing external linkage since res_all
83 // is declared as a different type when instantiated.
84 extern "C" CURES res_all;
88 extern int res_all_size;
90 extern brwlock_t res_lock; /* resource lock */
93 /* Forward referenced subroutines */
94 static void scan_types(LEX *lc, MSGS *msg, int dest, char *where, char *cmd);
95 static const char *get_default_configdir();
96 static bool find_config_file(const char *config_file, char *full_path);
98 /* Common Resource definitions */
100 /* Message resource directives
101 * name handler value code flags default_value
103 RES_ITEM msgs_items[] = {
104 {"name", store_name, ITEM(res_msgs.hdr.name), 0, 0, 0},
105 {"description", store_str, ITEM(res_msgs.hdr.desc), 0, 0, 0},
106 {"mailcommand", store_str, ITEM(res_msgs.mail_cmd), 0, 0, 0},
107 {"operatorcommand", store_str, ITEM(res_msgs.operator_cmd), 0, 0, 0},
108 {"syslog", store_msgs, ITEM(res_msgs), MD_SYSLOG, 0, 0},
109 {"mail", store_msgs, ITEM(res_msgs), MD_MAIL, 0, 0},
110 {"mailonerror", store_msgs, ITEM(res_msgs), MD_MAIL_ON_ERROR, 0, 0},
111 {"mailonsuccess", store_msgs, ITEM(res_msgs), MD_MAIL_ON_SUCCESS, 0, 0},
112 {"file", store_msgs, ITEM(res_msgs), MD_FILE, 0, 0},
113 {"append", store_msgs, ITEM(res_msgs), MD_APPEND, 0, 0},
114 {"stdout", store_msgs, ITEM(res_msgs), MD_STDOUT, 0, 0},
115 {"stderr", store_msgs, ITEM(res_msgs), MD_STDERR, 0, 0},
116 {"director", store_msgs, ITEM(res_msgs), MD_DIRECTOR, 0, 0},
117 {"console", store_msgs, ITEM(res_msgs), MD_CONSOLE, 0, 0},
118 {"operator", store_msgs, ITEM(res_msgs), MD_OPERATOR, 0, 0},
119 {"catalog", store_msgs, ITEM(res_msgs), MD_CATALOG, 0, 0},
120 {NULL, NULL, {0}, 0, 0, 0}
127 /* Various message types */
128 static struct s_mtypes msg_types[] = {
133 {"warning", M_WARNING},
136 {"notsaved", M_NOTSAVED},
137 {"skipped", M_SKIPPED},
139 {"terminate", M_TERM},
140 {"restored", M_RESTORED},
141 {"security", M_SECURITY},
143 {"volmgmt", M_VOLMGMT},
148 /* Used for certain KeyWord tables */
155 * Tape Label types permitted in Pool records
157 * tape label label code = token
159 static s_kw tapelabels[] = {
160 {"bacula", B_BACULA_LABEL},
161 {"ansi", B_ANSI_LABEL},
162 {"ibm", B_IBM_LABEL},
167 /* Simply print a message */
168 static void prtmsg(void *sock, const char *fmt, ...)
172 va_start(arg_ptr, fmt);
173 vfprintf(stdout, fmt, arg_ptr);
177 const char *res_to_str(int rcode)
179 if (rcode < r_first || rcode > r_last) {
180 return _("***UNKNOWN***");
182 return resources[rcode-r_first].name;
188 * Initialize the static structure to zeros, then
189 * apply all the default values.
191 void init_resource(int type, RES_ITEM *items, int pass)
194 int rindex = type - r_first;
195 static bool first = true;
198 if (first && (errstat=rwl_init(&res_lock)) != 0) {
199 Emsg1(M_ABORT, 0, _("Unable to initialize resource lock. ERR=%s\n"),
204 memset(&res_all, 0, res_all_size);
205 res_all.hdr.rcode = type;
206 res_all.hdr.refcnt = 1;
208 /* Set defaults in each item */
209 for (i=0; items[i].name; i++) {
210 Dmsg3(900, "Item=%s def=%s defval=%d\n", items[i].name,
211 (items[i].flags & ITEM_DEFAULT) ? "yes" : "no",
212 items[i].default_value);
213 if (items[i].flags & ITEM_DEFAULT && items[i].default_value != 0) {
214 if (items[i].handler == store_bit) {
215 *(int *)(items[i].value) |= items[i].code;
216 } else if (items[i].handler == store_bool) {
217 *(bool *)(items[i].value) = items[i].default_value != 0;
218 } else if (items[i].handler == store_pint ||
219 items[i].handler == store_int) {
220 *(int *)(items[i].value) = items[i].default_value;
221 } else if (items[i].handler == store_int64) {
222 *(int64_t *)(items[i].value) = items[i].default_value;
223 } else if (items[i].handler == store_size) {
224 *(uint64_t *)(items[i].value) = (uint64_t)items[i].default_value;
225 } else if (items[i].handler == store_time) {
226 *(utime_t *)(items[i].value) = (utime_t)items[i].default_value;
227 } else if (pass == 1 && items[i].handler == store_addresses) {
228 init_default_addresses((dlist**)items[i].value, items[i].default_value);
231 /* If this triggers, take a look at lib/parse_conf.h */
232 if (i >= MAX_RES_ITEMS) {
233 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
239 /* Store Messages Destination information */
240 void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass)
247 Dmsg2(900, "store_msgs pass=%d code=%d\n", pass, item->code);
249 switch (item->code) {
252 case MD_SYSLOG: /* syslog */
255 scan_types(lc, (MSGS *)(item->value), item->code, NULL, NULL);
257 case MD_OPERATOR: /* send to operator */
258 case MD_DIRECTOR: /* send to Director */
259 case MD_MAIL: /* mail */
260 case MD_MAIL_ON_ERROR: /* mail if Job errors */
261 case MD_MAIL_ON_SUCCESS: /* mail if Job succeeds */
262 if (item->code == MD_OPERATOR) {
263 cmd = res_all.res_msgs.operator_cmd;
265 cmd = res_all.res_msgs.mail_cmd;
267 dest = get_pool_memory(PM_MESSAGE);
270 /* Pick up comma separated list of destinations */
272 token = lex_get_token(lc, T_NAME); /* scan destination */
273 dest = check_pool_memory_size(dest, dest_len + lc->str_len + 2);
275 pm_strcat(dest, " "); /* separate multiple destinations with space */
278 pm_strcat(dest, lc->str);
279 dest_len += lc->str_len;
280 Dmsg2(900, "store_msgs newdest=%s: dest=%s:\n", lc->str, NPRT(dest));
281 token = lex_get_token(lc, T_SKIP_EOL);
282 if (token == T_COMMA) {
283 continue; /* get another destination */
285 if (token != T_EQUALS) {
286 scan_err1(lc, _("expected an =, got: %s"), lc->str);
290 Dmsg1(900, "mail_cmd=%s\n", NPRT(cmd));
291 scan_types(lc, (MSGS *)(item->value), item->code, dest, cmd);
292 free_pool_memory(dest);
293 Dmsg0(900, "done with dest codes\n");
295 case MD_FILE: /* file */
296 case MD_APPEND: /* append */
297 dest = get_pool_memory(PM_MESSAGE);
298 /* Pick up a single destination */
299 token = lex_get_token(lc, T_NAME); /* scan destination */
300 pm_strcpy(dest, lc->str);
301 dest_len = lc->str_len;
302 token = lex_get_token(lc, T_SKIP_EOL);
303 Dmsg1(900, "store_msgs dest=%s:\n", NPRT(dest));
304 if (token != T_EQUALS) {
305 scan_err1(lc, _("expected an =, got: %s"), lc->str);
307 scan_types(lc, (MSGS *)(item->value), item->code, dest, NULL);
308 free_pool_memory(dest);
309 Dmsg0(900, "done with dest codes\n");
313 scan_err1(lc, _("Unknown item code: %d\n"), item->code);
318 set_bit(index, res_all.hdr.item_present);
319 Dmsg0(900, "Done store_msgs\n");
323 * Scan for message types and add them to the message
324 * destination. The basic job here is to connect message types
325 * (WARNING, ERROR, FATAL, INFO, ...) with an appropriate
326 * destination (MAIL, FILE, OPERATOR, ...)
328 static void scan_types(LEX *lc, MSGS *msg, int dest_code, char *where, char *cmd)
336 lex_get_token(lc, T_NAME); /* expect at least one type */
338 if (lc->str[0] == '!') {
345 for (i=0; msg_types[i].name; i++) {
346 if (strcasecmp(str, msg_types[i].name) == 0) {
347 msg_type = msg_types[i].token;
353 scan_err1(lc, _("message type: %s not found"), str);
357 if (msg_type == M_MAX+1) { /* all? */
358 for (i=1; i<=M_MAX; i++) { /* yes set all types */
359 add_msg_dest(msg, dest_code, i, where, cmd);
362 rem_msg_dest(msg, dest_code, msg_type, where);
364 add_msg_dest(msg, dest_code, msg_type, where, cmd);
369 Dmsg0(900, "call lex_get_token() to eat comma\n");
370 lex_get_token(lc, T_ALL); /* eat comma */
372 Dmsg0(900, "Done scan_types()\n");
377 * This routine is ONLY for resource names
378 * Store a name at specified address.
380 void store_name(LEX *lc, RES_ITEM *item, int index, int pass)
382 POOLMEM *msg = get_pool_memory(PM_EMSG);
383 lex_get_token(lc, T_NAME);
384 if (!is_name_valid(lc->str, &msg)) {
385 scan_err1(lc, "%s\n", msg);
387 free_pool_memory(msg);
388 /* Store the name both pass 1 and pass 2 */
389 if (*(item->value)) {
390 scan_err2(lc, _("Attempt to redefine name \"%s\" to \"%s\"."),
391 *(item->value), lc->str);
393 *(item->value) = bstrdup(lc->str);
395 set_bit(index, res_all.hdr.item_present);
400 * Store a name string at specified address
401 * A name string is limited to MAX_RES_NAME_LENGTH
403 void store_strname(LEX *lc, RES_ITEM *item, int index, int pass)
405 lex_get_token(lc, T_NAME);
408 *(item->value) = bstrdup(lc->str);
411 set_bit(index, res_all.hdr.item_present);
414 /* Store a string at specified address */
415 void store_str(LEX *lc, RES_ITEM *item, int index, int pass)
417 lex_get_token(lc, T_STRING);
419 *(item->value) = bstrdup(lc->str);
422 set_bit(index, res_all.hdr.item_present);
426 * Store a directory name at specified address. Note, we do
427 * shell expansion except if the string begins with a vertical
428 * bar (i.e. it will likely be passed to the shell later).
430 void store_dir(LEX *lc, RES_ITEM *item, int index, int pass)
432 lex_get_token(lc, T_STRING);
434 if (lc->str[0] != '|') {
435 do_shell_expansion(lc->str, sizeof(lc->str));
437 *(item->value) = bstrdup(lc->str);
440 set_bit(index, res_all.hdr.item_present);
444 /* Store a password specified address in MD5 coding */
445 void store_password(LEX *lc, RES_ITEM *item, int index, int pass)
448 struct MD5Context md5c;
449 unsigned char digest[CRYPTO_DIGEST_MD5_SIZE];
453 lex_get_token(lc, T_STRING);
456 MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
457 MD5Final(digest, &md5c);
458 for (i = j = 0; i < sizeof(digest); i++) {
459 sprintf(&sig[j], "%02x", digest[i]);
462 *(item->value) = bstrdup(sig);
465 set_bit(index, res_all.hdr.item_present);
469 /* Store a resource at specified address.
470 * If we are in pass 2, do a lookup of the
473 void store_res(LEX *lc, RES_ITEM *item, int index, int pass)
477 lex_get_token(lc, T_NAME);
479 res = GetResWithName(item->code, lc->str);
481 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
482 lc->str, lc->line_no, lc->line);
484 if (*(item->value)) {
485 scan_err3(lc, _("Attempt to redefine resource \"%s\" referenced on line %d : %s\n"),
486 item->name, lc->line_no, lc->line);
488 *(item->value) = (char *)res;
491 set_bit(index, res_all.hdr.item_present);
495 * Store a resource pointer in an alist. default_value indicates how many
496 * times this routine can be called -- i.e. how many alists
498 * If we are in pass 2, do a lookup of the
501 void store_alist_res(LEX *lc, RES_ITEM *item, int index, int pass)
504 int count = item->default_value;
509 if (count == 0) { /* always store in item->value */
511 if ((item->value)[i] == NULL) {
512 list = New(alist(10, not_owned_by_alist));
514 list = (alist *)(item->value)[i];
517 /* Find empty place to store this directive */
518 while ((item->value)[i] != NULL && i++ < count) { }
520 scan_err4(lc, _("Too many %s directives. Max. is %d. line %d: %s\n"),
521 lc->str, count, lc->line_no, lc->line);
523 list = New(alist(10, not_owned_by_alist));
527 lex_get_token(lc, T_NAME); /* scan next item */
528 res = GetResWithName(item->code, lc->str);
530 scan_err3(lc, _("Could not find config Resource \"%s\" referenced on line %d : %s\n"),
531 item->name, lc->line_no, lc->line);
533 Dmsg5(900, "Append %p to alist %p size=%d i=%d %s\n",
534 res, list, list->size(), i, item->name);
536 (item->value)[i] = (char *)list;
537 if (lc->ch != ',') { /* if no other item follows */
540 lex_get_token(lc, T_ALL); /* eat comma */
544 set_bit(index, res_all.hdr.item_present);
549 * Store a string in an alist.
551 void store_alist_str(LEX *lc, RES_ITEM *item, int index, int pass)
556 if (*(item->value) == NULL) {
557 list = New(alist(10, owned_by_alist));
559 list = (alist *)(*(item->value));
562 lex_get_token(lc, T_STRING); /* scan next item */
563 Dmsg4(900, "Append %s to alist %p size=%d %s\n",
564 lc->str, list, list->size(), item->name);
565 list->append(bstrdup(lc->str));
566 *(item->value) = (char *)list;
569 set_bit(index, res_all.hdr.item_present);
575 * Store default values for Resource from xxxDefs
576 * If we are in pass 2, do a lookup of the
577 * resource and store everything not explicitly set
580 * Note, here item points to the main resource (e.g. Job, not
581 * the jobdefs, which we look up).
583 void store_defs(LEX *lc, RES_ITEM *item, int index, int pass)
587 lex_get_token(lc, T_NAME);
589 Dmsg2(900, "Code=%d name=%s\n", item->code, lc->str);
590 res = GetResWithName(item->code, lc->str);
592 scan_err3(lc, _("Missing config Resource \"%s\" referenced on line %d : %s\n"),
593 lc->str, lc->line_no, lc->line);
601 /* Store an integer at specified address */
602 void store_int(LEX *lc, RES_ITEM *item, int index, int pass)
604 lex_get_token(lc, T_INT32);
605 *(int *)(item->value) = lc->int32_val;
607 set_bit(index, res_all.hdr.item_present);
610 /* Store a positive integer at specified address */
611 void store_pint(LEX *lc, RES_ITEM *item, int index, int pass)
613 lex_get_token(lc, T_PINT32);
614 *(int *)(item->value) = lc->pint32_val;
616 set_bit(index, res_all.hdr.item_present);
620 /* Store an 64 bit integer at specified address */
621 void store_int64(LEX *lc, RES_ITEM *item, int index, int pass)
623 lex_get_token(lc, T_INT64);
624 *(int64_t *)(item->value) = lc->int64_val;
626 set_bit(index, res_all.hdr.item_present);
629 /* Store a size in bytes */
630 void store_size(LEX *lc, RES_ITEM *item, int index, int pass)
636 Dmsg0(900, "Enter store_size\n");
637 token = lex_get_token(lc, T_SKIP_EOL);
642 case T_UNQUOTED_STRING:
643 bstrncpy(bsize, lc->str, sizeof(bsize)); /* save first part */
644 /* if terminated by space, scan and get modifier */
645 while (lc->ch == ' ') {
646 token = lex_get_token(lc, T_ALL);
650 case T_UNQUOTED_STRING:
651 bstrncat(bsize, lc->str, sizeof(bsize));
655 if (!size_to_uint64(bsize, strlen(bsize), &uvalue)) {
656 scan_err1(lc, _("expected a size number, got: %s"), lc->str);
658 *(uint64_t *)(item->value) = uvalue;
661 scan_err1(lc, _("expected a size, got: %s"), lc->str);
664 if (token != T_EOL) {
667 set_bit(index, res_all.hdr.item_present);
668 Dmsg0(900, "Leave store_size\n");
672 /* Store a time period in seconds */
673 void store_time(LEX *lc, RES_ITEM *item, int index, int pass)
679 token = lex_get_token(lc, T_SKIP_EOL);
684 case T_UNQUOTED_STRING:
685 bstrncpy(period, lc->str, sizeof(period)); /* get first part */
686 /* if terminated by space, scan and get modifier */
687 while (lc->ch == ' ') {
688 token = lex_get_token(lc, T_ALL);
692 case T_UNQUOTED_STRING:
693 bstrncat(period, lc->str, sizeof(period));
697 if (!duration_to_utime(period, &utime)) {
698 scan_err1(lc, _("expected a time period, got: %s"), period);
700 *(utime_t *)(item->value) = utime;
703 scan_err1(lc, _("expected a time period, got: %s"), lc->str);
706 if (token != T_EOL) {
709 set_bit(index, res_all.hdr.item_present);
713 /* Store a yes/no in a bit field */
714 void store_bit(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 *(int *)(item->value) |= item->code;
719 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
720 *(int *)(item->value) &= ~(item->code);
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);
728 /* Store a bool in a bit field */
729 void store_bool(LEX *lc, RES_ITEM *item, int index, int pass)
731 lex_get_token(lc, T_NAME);
732 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
733 *(bool *)(item->value) = true;
734 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
735 *(bool *)(item->value) = false;
737 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
740 set_bit(index, res_all.hdr.item_present);
745 * Store Tape Label Type (Bacula, ANSI, IBM)
748 void store_label(LEX *lc, RES_ITEM *item, int index, int pass)
752 token = lex_get_token(lc, T_NAME);
753 /* Store the label pass 2 so that type is defined */
754 for (i=0; tapelabels[i].name; i++) {
755 if (strcasecmp(lc->str, tapelabels[i].name) == 0) {
756 *(int *)(item->value) = tapelabels[i].token;
762 scan_err1(lc, _("Expected a Tape Label keyword, got: %s"), lc->str);
765 set_bit(index, res_all.hdr.item_present);
775 /*********************************************************************
777 * Parse configuration file
779 * Return 0 if reading failed, 1 otherwise
780 * Note, the default behavior unless you have set an alternate
781 * scan_error handler is to die on an error.
784 parse_config(const char *cf, LEX_ERROR_HANDLER *scan_error, int err_type)
789 enum parse_state state = p_none;
790 RES_ITEM *items = NULL;
793 char *full_path = (char *)alloca(MAX_PATH);
795 if (find_config_file(cf, full_path)) {
799 /* Make two passes. The first builds the name symbol table,
800 * and the second picks up the items.
802 Dmsg0(900, "Enter parse_config()\n");
803 for (pass=1; pass <= 2; pass++) {
804 Dmsg1(900, "parse_config pass %d\n", pass);
805 if ((lc = lex_open_file(lc, cf, scan_error)) == NULL) {
807 /* We must create a lex packet to print the error */
808 lc = (LEX *)malloc(sizeof(LEX));
809 memset(lc, 0, sizeof(LEX));
811 lc->scan_error = scan_error;
813 lex_set_default_error_handler(lc);
815 lex_set_error_handler_error_type(lc, err_type) ;
816 bstrncpy(lc->str, cf, sizeof(lc->str));
818 scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
819 lc->str, be.strerror());
823 lex_set_error_handler_error_type(lc, err_type) ;
824 while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
825 Dmsg1(900, "parse got token=%s\n", lex_tok_to_str(token));
828 if (token == T_EOL) {
831 if (token == T_UNICODE_MARK) {
834 if (token != T_IDENTIFIER) {
835 scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
838 for (i=0; resources[i].name; i++)
839 if (strcasecmp(resources[i].name, lc->str) == 0) {
841 items = resources[i].items;
842 res_type = resources[i].rcode;
843 init_resource(res_type, items, pass);
846 if (state == p_none) {
847 scan_err1(lc, _("expected resource name, got: %s"), lc->str);
858 scan_err1(lc, _("not in resource definition: %s"), lc->str);
861 for (i=0; items[i].name; i++) {
862 if (strcasecmp(items[i].name, lc->str) == 0) {
863 /* If the ITEM_NO_EQUALS flag is set we do NOT
864 * scan for = after the keyword */
865 if (!(items[i].flags & ITEM_NO_EQUALS)) {
866 token = lex_get_token(lc, T_SKIP_EOL);
867 Dmsg1 (900, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
868 if (token != T_EQUALS) {
869 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
873 Dmsg1(800, "calling handler for %s\n", items[i].name);
874 /* Call item handler */
875 items[i].handler(lc, &items[i], i, pass);
881 Dmsg2(900, "level=%d id=%s\n", level, lc->str);
882 Dmsg1(900, "Keyword = %s\n", lc->str);
883 scan_err1(lc, _("Keyword \"%s\" not permitted in this resource.\n"
884 "Perhaps you left the trailing brace off of the previous resource."), lc->str);
892 Dmsg0(900, "T_EOB => define new resource\n");
893 if (res_all.hdr.name == NULL) {
894 scan_err0(lc, _("Name not specified for resource"));
896 save_resource(res_type, items, pass); /* save resource */
903 scan_err2(lc, _("unexpected token %d %s in resource definition"),
904 token, lex_tok_to_str(token));
909 scan_err1(lc, _("Unknown parser state %d\n"), state);
913 if (state != p_none) {
914 scan_err0(lc, _("End of conf file reached with unclosed resource."));
917 if (debug_level >= 900 && pass == 2) {
919 for (i=r_first; i<=r_last; i++) {
920 dump_resource(i, res_head[i-r_first], prtmsg, NULL);
923 lc = lex_close_file(lc);
925 Dmsg0(900, "Leave parse_config()\n");
929 const char *get_default_configdir()
931 #if defined(HAVE_WIN32)
933 static char szConfigDir[MAX_PATH + 1] = { 0 };
935 if (!p_SHGetFolderPath) {
936 bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir));
940 if (szConfigDir[0] == '\0') {
941 hr = p_SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szConfigDir);
944 bstrncat(szConfigDir, "\\Bacula", sizeof(szConfigDir));
946 bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir));
956 find_config_file(const char *config_file, char *full_path)
958 if (first_path_separator(config_file) != NULL) {
964 if (stat(config_file, &st) == 0) {
968 const char *config_dir = get_default_configdir();
969 size_t dir_length = strlen(config_dir);
970 size_t file_length = strlen(config_file);
972 if ((dir_length + 1 + file_length + 1) > MAX_PATH) {
976 memcpy(full_path, config_dir, dir_length + 1);
978 if (!IsPathSeparator(full_path[dir_length - 1])) {
979 full_path[dir_length++] = '/';
982 memcpy(&full_path[dir_length], config_file, file_length + 1);
987 /*********************************************************************
989 * Free configuration resources
992 void free_config_resources()
994 for (int i=r_first; i<=r_last; i++) {
995 free_resource(res_head[i-r_first], i);
996 res_head[i-r_first] = NULL;
1000 RES **save_config_resources()
1002 int num = r_last - r_first + 1;
1003 RES **res = (RES **)malloc(num*sizeof(RES *));
1004 for (int i=0; i<num; i++) {
1005 res[i] = res_head[i];
1011 RES **new_res_head()
1013 int size = (r_last - r_first + 1) * sizeof(RES *);
1014 RES **res = (RES **)malloc(size);
1015 memset(res, 0, size);