2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation plus additions
11 that are listed in the file LICENSE.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Master Configuration routines.
31 * This file contains the common parts of the Bacula
32 * configuration routines.
34 * Note, the configuration file parser consists of three parts
36 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
38 * 2. The generic config scanner in lib/parse_conf.c and
40 * These files contain the parser code, some utility
41 * routines, and the common store routines (name, int,
42 * string, time, int64, size, ...).
44 * 3. The daemon specific file, which contains the Resource
45 * definitions as well as any specific store routines
46 * for the resource records.
48 * N.B. This is a two pass parser, so if you malloc() a string
49 * in a "store" routine, you must ensure to do it during
50 * only one of the two passes, or to free it between.
51 * Also, note that the resource record is malloced and
52 * saved in save_resource() during pass 1. Anything that
53 * you want saved after pass two (e.g. resource pointers)
54 * must explicitly be done in save_resource. Take a look
55 * at the Job resource in src/dird/dird_conf.c to see how
58 * Kern Sibbald, January MM
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) {
200 Emsg1(M_ABORT, 0, _("Unable to initialize resource lock. ERR=%s\n"),
201 be.bstrerror(errstat));
205 memset(&res_all, 0, res_all_size);
206 res_all.hdr.rcode = type;
207 res_all.hdr.refcnt = 1;
209 /* Set defaults in each item */
210 for (i=0; items[i].name; i++) {
211 Dmsg3(900, "Item=%s def=%s defval=%d\n", items[i].name,
212 (items[i].flags & ITEM_DEFAULT) ? "yes" : "no",
213 items[i].default_value);
214 if (items[i].flags & ITEM_DEFAULT && items[i].default_value != 0) {
215 if (items[i].handler == store_bit) {
216 *(int *)(items[i].value) |= items[i].code;
217 } else if (items[i].handler == store_bool) {
218 *(bool *)(items[i].value) = items[i].default_value != 0;
219 } else if (items[i].handler == store_pint ||
220 items[i].handler == store_int) {
221 *(int *)(items[i].value) = items[i].default_value;
222 } else if (items[i].handler == store_int64) {
223 *(int64_t *)(items[i].value) = items[i].default_value;
224 } else if (items[i].handler == store_size) {
225 *(uint64_t *)(items[i].value) = (uint64_t)items[i].default_value;
226 } else if (items[i].handler == store_time) {
227 *(utime_t *)(items[i].value) = (utime_t)items[i].default_value;
228 } else if (pass == 1 && items[i].handler == store_addresses) {
229 init_default_addresses((dlist**)items[i].value, items[i].default_value);
232 /* If this triggers, take a look at lib/parse_conf.h */
233 if (i >= MAX_RES_ITEMS) {
234 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
240 /* Store Messages Destination information */
241 void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass)
248 Dmsg2(900, "store_msgs pass=%d code=%d\n", pass, item->code);
250 switch (item->code) {
253 case MD_SYSLOG: /* syslog */
256 scan_types(lc, (MSGS *)(item->value), item->code, NULL, NULL);
258 case MD_OPERATOR: /* send to operator */
259 case MD_DIRECTOR: /* send to Director */
260 case MD_MAIL: /* mail */
261 case MD_MAIL_ON_ERROR: /* mail if Job errors */
262 case MD_MAIL_ON_SUCCESS: /* mail if Job succeeds */
263 if (item->code == MD_OPERATOR) {
264 cmd = res_all.res_msgs.operator_cmd;
266 cmd = res_all.res_msgs.mail_cmd;
268 dest = get_pool_memory(PM_MESSAGE);
271 /* Pick up comma separated list of destinations */
273 token = lex_get_token(lc, T_NAME); /* scan destination */
274 dest = check_pool_memory_size(dest, dest_len + lc->str_len + 2);
276 pm_strcat(dest, " "); /* separate multiple destinations with space */
279 pm_strcat(dest, lc->str);
280 dest_len += lc->str_len;
281 Dmsg2(900, "store_msgs newdest=%s: dest=%s:\n", lc->str, NPRT(dest));
282 token = lex_get_token(lc, T_SKIP_EOL);
283 if (token == T_COMMA) {
284 continue; /* get another destination */
286 if (token != T_EQUALS) {
287 scan_err1(lc, _("expected an =, got: %s"), lc->str);
291 Dmsg1(900, "mail_cmd=%s\n", NPRT(cmd));
292 scan_types(lc, (MSGS *)(item->value), item->code, dest, cmd);
293 free_pool_memory(dest);
294 Dmsg0(900, "done with dest codes\n");
296 case MD_FILE: /* file */
297 case MD_APPEND: /* append */
298 dest = get_pool_memory(PM_MESSAGE);
299 /* Pick up a single destination */
300 token = lex_get_token(lc, T_NAME); /* scan destination */
301 pm_strcpy(dest, lc->str);
302 dest_len = lc->str_len;
303 token = lex_get_token(lc, T_SKIP_EOL);
304 Dmsg1(900, "store_msgs dest=%s:\n", NPRT(dest));
305 if (token != T_EQUALS) {
306 scan_err1(lc, _("expected an =, got: %s"), lc->str);
308 scan_types(lc, (MSGS *)(item->value), item->code, dest, NULL);
309 free_pool_memory(dest);
310 Dmsg0(900, "done with dest codes\n");
314 scan_err1(lc, _("Unknown item code: %d\n"), item->code);
319 set_bit(index, res_all.hdr.item_present);
320 Dmsg0(900, "Done store_msgs\n");
324 * Scan for message types and add them to the message
325 * destination. The basic job here is to connect message types
326 * (WARNING, ERROR, FATAL, INFO, ...) with an appropriate
327 * destination (MAIL, FILE, OPERATOR, ...)
329 static void scan_types(LEX *lc, MSGS *msg, int dest_code, char *where, char *cmd)
337 lex_get_token(lc, T_NAME); /* expect at least one type */
339 if (lc->str[0] == '!') {
346 for (i=0; msg_types[i].name; i++) {
347 if (strcasecmp(str, msg_types[i].name) == 0) {
348 msg_type = msg_types[i].token;
354 scan_err1(lc, _("message type: %s not found"), str);
358 if (msg_type == M_MAX+1) { /* all? */
359 for (i=1; i<=M_MAX; i++) { /* yes set all types */
360 add_msg_dest(msg, dest_code, i, where, cmd);
363 rem_msg_dest(msg, dest_code, msg_type, where);
365 add_msg_dest(msg, dest_code, msg_type, where, cmd);
370 Dmsg0(900, "call lex_get_token() to eat comma\n");
371 lex_get_token(lc, T_ALL); /* eat comma */
373 Dmsg0(900, "Done scan_types()\n");
378 * This routine is ONLY for resource names
379 * Store a name at specified address.
381 void store_name(LEX *lc, RES_ITEM *item, int index, int pass)
383 POOLMEM *msg = get_pool_memory(PM_EMSG);
384 lex_get_token(lc, T_NAME);
385 if (!is_name_valid(lc->str, &msg)) {
386 scan_err1(lc, "%s\n", msg);
388 free_pool_memory(msg);
389 /* Store the name both pass 1 and pass 2 */
390 if (*(item->value)) {
391 scan_err2(lc, _("Attempt to redefine name \"%s\" to \"%s\"."),
392 *(item->value), lc->str);
394 *(item->value) = bstrdup(lc->str);
396 set_bit(index, res_all.hdr.item_present);
401 * Store a name string at specified address
402 * A name string is limited to MAX_RES_NAME_LENGTH
404 void store_strname(LEX *lc, RES_ITEM *item, int index, int pass)
406 lex_get_token(lc, T_NAME);
409 *(item->value) = bstrdup(lc->str);
412 set_bit(index, res_all.hdr.item_present);
415 /* Store a string at specified address */
416 void store_str(LEX *lc, RES_ITEM *item, int index, int pass)
418 lex_get_token(lc, T_STRING);
420 *(item->value) = bstrdup(lc->str);
423 set_bit(index, res_all.hdr.item_present);
427 * Store a directory name at specified address. Note, we do
428 * shell expansion except if the string begins with a vertical
429 * bar (i.e. it will likely be passed to the shell later).
431 void store_dir(LEX *lc, RES_ITEM *item, int index, int pass)
433 lex_get_token(lc, T_STRING);
435 if (lc->str[0] != '|') {
436 do_shell_expansion(lc->str, sizeof(lc->str));
438 *(item->value) = bstrdup(lc->str);
441 set_bit(index, res_all.hdr.item_present);
445 /* Store a password specified address in MD5 coding */
446 void store_password(LEX *lc, RES_ITEM *item, int index, int pass)
449 struct MD5Context md5c;
450 unsigned char digest[CRYPTO_DIGEST_MD5_SIZE];
454 lex_get_token(lc, T_STRING);
457 MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
458 MD5Final(digest, &md5c);
459 for (i = j = 0; i < sizeof(digest); i++) {
460 sprintf(&sig[j], "%02x", digest[i]);
463 *(item->value) = bstrdup(sig);
466 set_bit(index, res_all.hdr.item_present);
470 /* Store a resource at specified address.
471 * If we are in pass 2, do a lookup of the
474 void store_res(LEX *lc, RES_ITEM *item, int index, int pass)
478 lex_get_token(lc, T_NAME);
480 res = GetResWithName(item->code, lc->str);
482 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
483 lc->str, lc->line_no, lc->line);
485 if (*(item->value)) {
486 scan_err3(lc, _("Attempt to redefine resource \"%s\" referenced on line %d : %s\n"),
487 item->name, lc->line_no, lc->line);
489 *(item->value) = (char *)res;
492 set_bit(index, res_all.hdr.item_present);
496 * Store a resource pointer in an alist. default_value indicates how many
497 * times this routine can be called -- i.e. how many alists
499 * If we are in pass 2, do a lookup of the
502 void store_alist_res(LEX *lc, RES_ITEM *item, int index, int pass)
505 int count = item->default_value;
510 if (count == 0) { /* always store in item->value */
512 if ((item->value)[i] == NULL) {
513 list = New(alist(10, not_owned_by_alist));
515 list = (alist *)(item->value)[i];
518 /* Find empty place to store this directive */
519 while ((item->value)[i] != NULL && i++ < count) { }
521 scan_err4(lc, _("Too many %s directives. Max. is %d. line %d: %s\n"),
522 lc->str, count, lc->line_no, lc->line);
524 list = New(alist(10, not_owned_by_alist));
528 lex_get_token(lc, T_NAME); /* scan next item */
529 res = GetResWithName(item->code, lc->str);
531 scan_err3(lc, _("Could not find config Resource \"%s\" referenced on line %d : %s\n"),
532 item->name, lc->line_no, lc->line);
534 Dmsg5(900, "Append %p to alist %p size=%d i=%d %s\n",
535 res, list, list->size(), i, item->name);
537 (item->value)[i] = (char *)list;
538 if (lc->ch != ',') { /* if no other item follows */
541 lex_get_token(lc, T_ALL); /* eat comma */
545 set_bit(index, res_all.hdr.item_present);
550 * Store a string in an alist.
552 void store_alist_str(LEX *lc, RES_ITEM *item, int index, int pass)
557 if (*(item->value) == NULL) {
558 list = New(alist(10, owned_by_alist));
560 list = (alist *)(*(item->value));
563 lex_get_token(lc, T_STRING); /* scan next item */
564 Dmsg4(900, "Append %s to alist %p size=%d %s\n",
565 lc->str, list, list->size(), item->name);
566 list->append(bstrdup(lc->str));
567 *(item->value) = (char *)list;
570 set_bit(index, res_all.hdr.item_present);
576 * Store default values for Resource from xxxDefs
577 * If we are in pass 2, do a lookup of the
578 * resource and store everything not explicitly set
581 * Note, here item points to the main resource (e.g. Job, not
582 * the jobdefs, which we look up).
584 void store_defs(LEX *lc, RES_ITEM *item, int index, int pass)
588 lex_get_token(lc, T_NAME);
590 Dmsg2(900, "Code=%d name=%s\n", item->code, lc->str);
591 res = GetResWithName(item->code, lc->str);
593 scan_err3(lc, _("Missing config Resource \"%s\" referenced on line %d : %s\n"),
594 lc->str, lc->line_no, lc->line);
602 /* Store an integer at specified address */
603 void store_int(LEX *lc, RES_ITEM *item, int index, int pass)
605 lex_get_token(lc, T_INT32);
606 *(int *)(item->value) = lc->int32_val;
608 set_bit(index, res_all.hdr.item_present);
611 /* Store a positive integer at specified address */
612 void store_pint(LEX *lc, RES_ITEM *item, int index, int pass)
614 lex_get_token(lc, T_PINT32);
615 *(int *)(item->value) = lc->pint32_val;
617 set_bit(index, res_all.hdr.item_present);
621 /* Store an 64 bit integer at specified address */
622 void store_int64(LEX *lc, RES_ITEM *item, int index, int pass)
624 lex_get_token(lc, T_INT64);
625 *(int64_t *)(item->value) = lc->int64_val;
627 set_bit(index, res_all.hdr.item_present);
630 /* Store a size in bytes */
631 void store_size(LEX *lc, RES_ITEM *item, int index, int pass)
637 Dmsg0(900, "Enter store_size\n");
638 token = lex_get_token(lc, T_SKIP_EOL);
643 case T_UNQUOTED_STRING:
644 bstrncpy(bsize, lc->str, sizeof(bsize)); /* save first part */
645 /* if terminated by space, scan and get modifier */
646 while (lc->ch == ' ') {
647 token = lex_get_token(lc, T_ALL);
651 case T_UNQUOTED_STRING:
652 bstrncat(bsize, lc->str, sizeof(bsize));
656 if (!size_to_uint64(bsize, strlen(bsize), &uvalue)) {
657 scan_err1(lc, _("expected a size number, got: %s"), lc->str);
659 *(uint64_t *)(item->value) = uvalue;
662 scan_err1(lc, _("expected a size, got: %s"), lc->str);
665 if (token != T_EOL) {
668 set_bit(index, res_all.hdr.item_present);
669 Dmsg0(900, "Leave store_size\n");
673 /* Store a time period in seconds */
674 void store_time(LEX *lc, RES_ITEM *item, int index, int pass)
680 token = lex_get_token(lc, T_SKIP_EOL);
685 case T_UNQUOTED_STRING:
686 bstrncpy(period, lc->str, sizeof(period)); /* get first part */
687 /* if terminated by space, scan and get modifier */
688 while (lc->ch == ' ') {
689 token = lex_get_token(lc, T_ALL);
693 case T_UNQUOTED_STRING:
694 bstrncat(period, lc->str, sizeof(period));
698 if (!duration_to_utime(period, &utime)) {
699 scan_err1(lc, _("expected a time period, got: %s"), period);
701 *(utime_t *)(item->value) = utime;
704 scan_err1(lc, _("expected a time period, got: %s"), lc->str);
707 if (token != T_EOL) {
710 set_bit(index, res_all.hdr.item_present);
714 /* Store a yes/no in a bit field */
715 void store_bit(LEX *lc, RES_ITEM *item, int index, int pass)
717 lex_get_token(lc, T_NAME);
718 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
719 *(int *)(item->value) |= item->code;
720 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
721 *(int *)(item->value) &= ~(item->code);
723 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
726 set_bit(index, res_all.hdr.item_present);
729 /* Store a bool in a bit field */
730 void store_bool(LEX *lc, RES_ITEM *item, int index, int pass)
732 lex_get_token(lc, T_NAME);
733 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
734 *(bool *)(item->value) = true;
735 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
736 *(bool *)(item->value) = false;
738 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
741 set_bit(index, res_all.hdr.item_present);
746 * Store Tape Label Type (Bacula, ANSI, IBM)
749 void store_label(LEX *lc, RES_ITEM *item, int index, int pass)
753 token = lex_get_token(lc, T_NAME);
754 /* Store the label pass 2 so that type is defined */
755 for (i=0; tapelabels[i].name; i++) {
756 if (strcasecmp(lc->str, tapelabels[i].name) == 0) {
757 *(int *)(item->value) = tapelabels[i].token;
763 scan_err1(lc, _("Expected a Tape Label keyword, got: %s"), lc->str);
766 set_bit(index, res_all.hdr.item_present);
776 /*********************************************************************
778 * Parse configuration file
780 * Return 0 if reading failed, 1 otherwise
781 * Note, the default behavior unless you have set an alternate
782 * scan_error handler is to die on an error.
785 parse_config(const char *cf, LEX_ERROR_HANDLER *scan_error, int err_type)
790 enum parse_state state = p_none;
791 RES_ITEM *items = NULL;
794 char *full_path = (char *)alloca(MAX_PATH);
796 if (find_config_file(cf, full_path)) {
800 /* Make two passes. The first builds the name symbol table,
801 * and the second picks up the items.
803 Dmsg0(900, "Enter parse_config()\n");
804 for (pass=1; pass <= 2; pass++) {
805 Dmsg1(900, "parse_config pass %d\n", pass);
806 if ((lc = lex_open_file(lc, cf, scan_error)) == NULL) {
808 /* We must create a lex packet to print the error */
809 lc = (LEX *)malloc(sizeof(LEX));
810 memset(lc, 0, sizeof(LEX));
812 lc->scan_error = scan_error;
814 lex_set_default_error_handler(lc);
816 lex_set_error_handler_error_type(lc, err_type) ;
817 bstrncpy(lc->str, cf, sizeof(lc->str));
819 scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
820 lc->str, be.bstrerror());
824 lex_set_error_handler_error_type(lc, err_type) ;
825 while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
826 Dmsg1(900, "parse got token=%s\n", lex_tok_to_str(token));
829 if (token == T_EOL) {
832 if (token == T_UNICODE_MARK) {
835 if (token != T_IDENTIFIER) {
836 scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
839 for (i=0; resources[i].name; i++)
840 if (strcasecmp(resources[i].name, lc->str) == 0) {
842 items = resources[i].items;
843 res_type = resources[i].rcode;
844 init_resource(res_type, items, pass);
847 if (state == p_none) {
848 scan_err1(lc, _("expected resource name, got: %s"), lc->str);
859 scan_err1(lc, _("not in resource definition: %s"), lc->str);
862 for (i=0; items[i].name; i++) {
863 if (strcasecmp(items[i].name, lc->str) == 0) {
864 /* If the ITEM_NO_EQUALS flag is set we do NOT
865 * scan for = after the keyword */
866 if (!(items[i].flags & ITEM_NO_EQUALS)) {
867 token = lex_get_token(lc, T_SKIP_EOL);
868 Dmsg1 (900, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
869 if (token != T_EQUALS) {
870 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
874 Dmsg1(800, "calling handler for %s\n", items[i].name);
875 /* Call item handler */
876 items[i].handler(lc, &items[i], i, pass);
882 Dmsg2(900, "level=%d id=%s\n", level, lc->str);
883 Dmsg1(900, "Keyword = %s\n", lc->str);
884 scan_err1(lc, _("Keyword \"%s\" not permitted in this resource.\n"
885 "Perhaps you left the trailing brace off of the previous resource."), lc->str);
893 Dmsg0(900, "T_EOB => define new resource\n");
894 if (res_all.hdr.name == NULL) {
895 scan_err0(lc, _("Name not specified for resource"));
897 save_resource(res_type, items, pass); /* save resource */
904 scan_err2(lc, _("unexpected token %d %s in resource definition"),
905 token, lex_tok_to_str(token));
910 scan_err1(lc, _("Unknown parser state %d\n"), state);
914 if (state != p_none) {
915 scan_err0(lc, _("End of conf file reached with unclosed resource."));
918 if (debug_level >= 900 && pass == 2) {
920 for (i=r_first; i<=r_last; i++) {
921 dump_resource(i, res_head[i-r_first], prtmsg, NULL);
924 lc = lex_close_file(lc);
926 Dmsg0(900, "Leave parse_config()\n");
930 const char *get_default_configdir()
932 #if defined(HAVE_WIN32)
934 static char szConfigDir[MAX_PATH + 1] = { 0 };
936 if (!p_SHGetFolderPath) {
937 bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir));
941 if (szConfigDir[0] == '\0') {
942 hr = p_SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szConfigDir);
945 bstrncat(szConfigDir, "\\Bacula", sizeof(szConfigDir));
947 bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir));
957 find_config_file(const char *config_file, char *full_path)
959 if (first_path_separator(config_file) != NULL) {
965 if (stat(config_file, &st) == 0) {
969 const char *config_dir = get_default_configdir();
970 size_t dir_length = strlen(config_dir);
971 size_t file_length = strlen(config_file);
973 if ((dir_length + 1 + file_length + 1) > MAX_PATH) {
977 memcpy(full_path, config_dir, dir_length + 1);
979 if (!IsPathSeparator(full_path[dir_length - 1])) {
980 full_path[dir_length++] = '/';
983 memcpy(&full_path[dir_length], config_file, file_length + 1);
988 /*********************************************************************
990 * Free configuration resources
993 void free_config_resources()
995 for (int i=r_first; i<=r_last; i++) {
996 free_resource(res_head[i-r_first], i);
997 res_head[i-r_first] = NULL;
1001 RES **save_config_resources()
1003 int num = r_last - r_first + 1;
1004 RES **res = (RES **)malloc(num*sizeof(RES *));
1005 for (int i=0; i<num; i++) {
1006 res[i] = res_head[i];
1012 RES **new_res_head()
1014 int size = (r_last - r_first + 1) * sizeof(RES *);
1015 RES **res = (RES **)malloc(size);
1016 memset(res, 0, size);