]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/parse_conf.c
da676363a21f9b14fee3868a03bf3348ced013b0
[bacula/bacula] / bacula / src / lib / parse_conf.c
1 /*
2  *   Master Configuration routines.
3  *  
4  *   This file contains the common parts of the Bacula
5  *   configuration routines.
6  *
7  *   Note, the configuration file parser consists of three parts
8  *
9  *   1. The generic lexical scanner in lib/lex.c and lib/lex.h
10  *
11  *   2. The generic config  scanner in lib/parse_conf.c and 
12  *      lib/parse_conf.h.
13  *      These files contain the parser code, some utility
14  *      routines, and the common store routines (name, int,
15  *      string).
16  *
17  *   3. The daemon specific file, which contains the Resource
18  *      definitions as well as any specific store routines
19  *      for the resource records.
20  *
21  *     Kern Sibbald, January MM
22  *
23  *   Version $Id$
24  */
25
26 /*
27    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
28
29    This program is free software; you can redistribute it and/or
30    modify it under the terms of the GNU General Public License as
31    published by the Free Software Foundation; either version 2 of
32    the License, or (at your option) any later version.
33
34    This program is distributed in the hope that it will be useful,
35    but WITHOUT ANY WARRANTY; without even the implied warranty of
36    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
37    General Public License for more details.
38
39    You should have received a copy of the GNU General Public
40    License along with this program; if not, write to the Free
41    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
42    MA 02111-1307, USA.
43
44  */
45
46
47 #include "bacula.h"
48
49 extern int debug_level;
50
51 /* Each daemon has a slightly different set of 
52  * resources, so it will define the following
53  * global values.
54  */
55 extern int r_first;
56 extern int r_last;
57 extern pthread_mutex_t res_mutex;
58 extern struct s_res resources[];
59 extern CURES res_all;
60 extern int res_all_size;
61
62 static int res_locked = 0;             /* set when resource chains locked */
63
64 /* Forward referenced subroutines */
65 static void scan_types(LEX *lc, MSGS *msg, int dest, char *where, char *cmd);
66
67
68 /* Common Resource definitions */
69
70 /* Message resource directives
71  *  name         handler      value       code   flags  default_value
72  */
73 struct res_items msgs_items[] = {
74    {"name",        store_name,    ITEM(res_msgs.hdr.name),  0, 0, 0},
75    {"description", store_str,     ITEM(res_msgs.hdr.desc),  0, 0, 0},
76    {"mailcommand", store_str,     ITEM(res_msgs.mail_cmd),  0, 0, 0},
77    {"operatorcommand", store_str, ITEM(res_msgs.operator_cmd), 0, 0, 0},
78    {"syslog",      store_msgs, ITEM(res_msgs), MD_SYSLOG,   0, 0}, 
79    {"mail",        store_msgs, ITEM(res_msgs), MD_MAIL,     0, 0},
80    {"mailonerror", store_msgs, ITEM(res_msgs), MD_MAIL_ON_ERROR, 0, 0},
81    {"file",        store_msgs, ITEM(res_msgs), MD_FILE,     0, 0},
82    {"append",      store_msgs, ITEM(res_msgs), MD_APPEND,   0, 0},
83    {"stdout",      store_msgs, ITEM(res_msgs), MD_STDOUT,   0, 0},
84    {"stderr",      store_msgs, ITEM(res_msgs), MD_STDERR,   0, 0},
85    {"director",    store_msgs, ITEM(res_msgs), MD_DIRECTOR, 0, 0},
86    {"console",     store_msgs, ITEM(res_msgs), MD_CONSOLE,  0, 0},   
87    {"operator",    store_msgs, ITEM(res_msgs), MD_OPERATOR, 0, 0},
88    {NULL, NULL,    NULL, 0}
89 };
90
91 struct s_mtypes {       
92    char *name;
93    int token;   
94 };
95 /* Various message types */
96 static struct s_mtypes msg_types[] = {
97    {"debug",         M_DEBUG},
98    {"abort",         M_ABORT},
99    {"fatal",         M_FATAL},
100    {"error",         M_ERROR},
101    {"warning",       M_WARNING},
102    {"info",          M_INFO},
103    {"saved",         M_SAVED},
104    {"notsaved",      M_NOTSAVED},
105    {"skipped",       M_SKIPPED},
106    {"mount",         M_MOUNT},
107    {"terminate",     M_TERM},
108    {"all",           M_MAX+1},
109    {NULL,            0}
110 };
111
112
113 /* Simply print a message */
114 static void prtmsg(void *sock, char *fmt, ...)
115 {
116    va_list arg_ptr;
117
118    va_start(arg_ptr, fmt);
119    vfprintf(stdout, fmt, arg_ptr);
120    va_end(arg_ptr);
121 }
122
123 #ifdef DEBUG
124 char *res_to_str(int rcode)
125 {
126    if (rcode < r_first || rcode > r_last) {
127       return "***UNKNOWN***";
128    } else {
129       return resources[rcode-r_first].name;
130    }
131 }
132 #endif /* DEBUG */
133
134
135 /* 
136  * Initialize the static structure to zeros, then
137  *  apply all the default values.
138  */
139 void init_resource(int type, struct res_items *items)
140 {
141    int i;
142    int rindex = type - r_first;
143
144    memset(&res_all, 0, res_all_size);
145    res_all.hdr.rcode = type;
146    res_all.hdr.refcnt = 1;
147
148    for (i=0; items[i].name; i++) {
149       Dmsg3(300, "Item=%s def=%s defval=%d\n", items[i].name,
150             (items[i].flags & ITEM_DEFAULT) ? "yes" : "no",      
151             items[i].default_value);
152       if (items[i].flags & ITEM_DEFAULT && items[i].default_value != 0) {
153          if (items[i].handler == store_yesno) {
154             *(int *)(items[i].value) |= items[i].code;
155          } else if (items[i].handler == store_pint || 
156                     items[i].handler == store_int) {
157             *(int *)(items[i].value) = items[i].default_value;
158          } else if (items[i].handler == store_int64) {
159             *(int64_t *)(items[i].value) = items[i].default_value;
160          } else if (items[i].handler == store_size ||
161                     items[i].handler == store_time) {
162             *(uint64_t *)(items[i].value) = items[i].default_value;
163          }
164       }
165       /* If this triggers, take a look at lib/parse_conf.h */
166       if (i >= MAX_RES_ITEMS) {
167          Emsg1(M_ABORT, 0, _("Too many items in %s resource\n"), resources[rindex]);
168       }
169    }
170 }
171
172
173 /* Store Messages Destination information */
174 void store_msgs(LEX *lc, struct res_items *item, int index, int pass)
175 {
176    int token;
177    char *dest, *cmd;
178    int dest_len;
179
180    Dmsg2(200, "store_msgs pass=%d code=%d\n", pass, item->code);
181    if (pass == 1) {
182       switch (item->code) {
183          case MD_STDOUT:
184          case MD_STDERR:
185          case MD_SYSLOG:              /* syslog */
186          case MD_CONSOLE:
187             scan_types(lc, (MSGS *)(item->value), item->code, NULL, NULL);
188             break;
189          case MD_OPERATOR:            /* send to operator */
190          case MD_DIRECTOR:            /* send to Director */
191          case MD_MAIL:                /* mail */
192          case MD_MAIL_ON_ERROR:       /* mail if Job errors */
193             if (item->code == MD_OPERATOR) {
194                cmd = res_all.res_msgs.operator_cmd;
195             } else {
196                cmd = res_all.res_msgs.mail_cmd;
197             }
198             dest = (char *) get_pool_memory(PM_MESSAGE);
199             dest_len = 0;
200             dest[0] = 0;
201             /* Pick up comma separated list of destinations */
202             for ( ;; ) {
203                token = lex_get_token(lc);    /* scan destination */
204                if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
205                   scan_err1(lc, "expected a message destination, got: %s", lc->str);
206                }
207                dest = (char *) check_pool_memory_size(dest, dest_len + lc->str_len + 2);
208                if (dest[0] != 0) {
209                   strcat(dest, " ");  /* separate multiple destinations with space */
210                   dest_len++;
211                }
212                strcat(dest, lc->str);
213                dest_len += lc->str_len;
214                Dmsg2(100, "store_msgs newdest=%s: dest=%s:\n", lc->str, dest);
215                token = lex_get_token(lc);
216                if (token == T_COMMA) { 
217                   continue;           /* get another destination */
218                }
219                if (token != T_EQUALS) {
220                   scan_err1(lc, "expected an =, got: %s", lc->str); 
221                }
222                break;
223             }
224             Dmsg1(200, "mail_cmd=%s\n", cmd);
225             scan_types(lc, (MSGS *)(item->value), item->code, dest, cmd);
226             free_pool_memory(dest);
227             Dmsg0(200, "done with dest codes\n");
228             break;
229          case MD_FILE:                /* file */
230          case MD_APPEND:              /* append */
231             dest = (char *) get_pool_memory(PM_MESSAGE);
232             /* Pick up a single destination */
233             token = lex_get_token(lc);    /* scan destination */
234             if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
235                scan_err1(lc, "expected a message destination, got: %s", lc->str);
236             }
237             dest = (char *) check_pool_memory_size(dest, dest_len + lc->str_len + 2);
238             strcpy(dest, lc->str);
239             dest_len = lc->str_len;
240             token = lex_get_token(lc);
241             Dmsg1(200, "store_msgs dest=%s:\n", dest);
242             if (token != T_EQUALS) {
243                scan_err1(lc, "expected an =, got: %s", lc->str); 
244             }
245             scan_types(lc, (MSGS *)(item->value), item->code, dest, NULL);
246             free_pool_memory(dest);
247             Dmsg0(200, "done with dest codes\n");
248             break;
249
250          default:
251             scan_err1(lc, "Unknown item code: %d\n", item->code);
252             break;
253       }
254    }
255    scan_to_eol(lc);
256    set_bit(index, res_all.hdr.item_present);
257    Dmsg0(200, "Done store_msgs\n");
258 }
259
260 /* 
261  * Scan for message types and add them to the message
262  * destination. The basic job here is to connect message types
263  *  (WARNING, ERROR, FATAL, INFO, ...) with an appropriate
264  *  destination (MAIL, FILE, OPERATOR, ...)
265  */
266 static void scan_types(LEX *lc, MSGS *msg, int dest_code, char *where, char *cmd)
267 {
268    int token, i, found, quit, is_not;
269    int msg_type;
270    char *str;
271
272    for (quit=0; !quit;) {
273       token = lex_get_token(lc);             /* expect at least one type */       
274       if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
275          scan_err1(lc, "expected a message type, got: %s", lc->str);
276       }
277       found = FALSE;
278       if (lc->str[0] == '!') {
279          is_not = TRUE;
280          str = &lc->str[1];
281       } else {
282          is_not = FALSE;
283          str = &lc->str[0];
284       }
285       for (i=0; msg_types[i].name; i++) {
286          if (strcmp(str, msg_types[i].name) == 0) {
287             msg_type = msg_types[i].token;
288             found = TRUE;
289             break;
290          }
291       }
292       if (!found) {
293          scan_err1(lc, "message type: %s not found", str);
294       }
295
296       if (msg_type == M_MAX+1) {         /* all? */
297          for (i=1; i<=M_MAX; i++) {      /* yes set all types */
298             add_msg_dest(msg, dest_code, i, where, cmd);
299          }
300       } else {
301          if (is_not) {
302             rem_msg_dest(msg, dest_code, msg_type, where);
303          } else {
304             add_msg_dest(msg, dest_code, msg_type, where, cmd);
305          }
306       }
307       if (lc->ch != ',') {
308          break;
309       }
310       Dmsg0(200, "call lex_get_token() to eat comma\n");
311       token = lex_get_token(lc);          /* eat comma */
312    }
313    Dmsg0(200, "Done scan_types()\n");
314 }
315
316
317 /* 
318  * This routine is ONLY for resource names
319  *  Store a name at specified address.
320  */
321 void store_name(LEX *lc, struct res_items *item, int index, int pass)
322 {
323    int token;
324
325    token = lex_get_token(lc);
326    if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
327       scan_err1(lc, "expected an identifier or string, got: %s", lc->str);
328    } else if (lc->str_len > MAX_RES_NAME_LENGTH) {
329       scan_err3(lc, "name %s length %d too long, max is %d\n", lc->str, 
330          lc->str_len, MAX_RES_NAME_LENGTH);
331    } else {
332       /* Store the name both pass 1 and pass 2 */
333       *(item->value) = bstrdup(lc->str);
334    }
335    scan_to_eol(lc);
336    set_bit(index, res_all.hdr.item_present);
337 }
338
339
340 /*
341  * Store a name string at specified address
342  * A name string is limited to MAX_RES_NAME_LENGTH
343  */
344 void store_strname(LEX *lc, struct res_items *item, int index, int pass)
345 {
346    int token;
347
348    token = lex_get_token(lc);
349    if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
350       scan_err1(lc, "expected an identifier or string, got: %s", lc->str);
351    } else if (lc->str_len > MAX_RES_NAME_LENGTH) {
352       scan_err3(lc, "name %s length %d too long, max is %d\n", lc->str, 
353          lc->str_len, MAX_RES_NAME_LENGTH);
354    } else {
355       /* Store the name */
356       if (pass == 1)
357          *(item->value) = bstrdup(lc->str);
358    }
359    scan_to_eol(lc);
360    set_bit(index, res_all.hdr.item_present);
361 }
362
363
364
365 /* Store a string at specified address */
366 void store_str(LEX *lc, struct res_items *item, int index, int pass)
367 {
368    int token;
369
370    token = lex_get_token(lc);
371    if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
372       scan_err1(lc, "expected an identifier or string, got: %s", lc->str);
373    } else {
374       if (pass == 1) {
375          *(item->value) = bstrdup(lc->str);
376       }
377    }
378    scan_to_eol(lc);
379    set_bit(index, res_all.hdr.item_present);
380 }
381
382 /* Store a directory name at specified address */
383 void store_dir(LEX *lc, struct res_items *item, int index, int pass)
384 {
385    int token;
386
387    token = lex_get_token(lc);
388    if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
389       scan_err1(lc, "expected an identifier or string, got: %s", lc->str);
390    } else {
391       if (pass == 1) {
392          do_shell_expansion(lc->str);
393          *(item->value) = bstrdup(lc->str);
394       }
395    }
396    scan_to_eol(lc);
397    set_bit(index, res_all.hdr.item_present);
398 }
399
400
401 /* Store a password specified address in MD5 coding */
402 void store_password(LEX *lc, struct res_items *item, int index, int pass)
403 {
404    unsigned int token, i, j;
405    struct MD5Context md5c;
406    unsigned char signature[16];
407    char sig[100];
408
409
410    token = lex_get_token(lc);
411    if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
412       scan_err1(lc, "expected an identifier or string, got: %s\n", lc->str);
413    } else {
414       if (pass == 1) {
415          MD5Init(&md5c);
416          MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
417          MD5Final(signature, &md5c);
418          for (i = j = 0; i < sizeof(signature); i++) {
419             sprintf(&sig[j], "%02x", signature[i]); 
420             j += 2;
421          }
422          *(item->value) = bstrdup(sig);
423       }
424    }
425    scan_to_eol(lc);
426    set_bit(index, res_all.hdr.item_present);
427 }
428
429
430 /* Store a resource at specified address.
431  * If we are in pass 2, do a lookup of the 
432  * resource.
433  */
434 void store_res(LEX *lc, struct res_items *item, int index, int pass)
435 {
436    int token;
437    RES *res;
438
439    token = lex_get_token(lc);
440    if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
441       scan_err1(lc, "expected a Resource name, got: %s", lc->str);
442    }
443    if (pass == 2) {
444      res = GetResWithName(item->code, lc->str);
445      if (res == NULL) {
446         scan_err3(lc, "Could not find Resource %s referenced on line %d : %s\n", 
447            lc->str, lc->line_no, lc->line);
448      }
449      *(item->value) = (char *)res;
450    }
451    scan_to_eol(lc);
452    set_bit(index, res_all.hdr.item_present);
453 }
454
455
456 /* Store an integer at specified address */
457 void store_int(LEX *lc, struct res_items *item, int index, int pass)
458 {
459    int token;
460
461    token = lex_get_token(lc);
462    if (token != T_NUMBER || !is_a_number(lc->str)) {
463       scan_err1(lc, "expected an integer number, got: %s", lc->str);
464    } else {
465       errno = 0;
466       *(int *)(item->value) = (int)strtod(lc->str, NULL);
467       if (errno != 0) {
468          scan_err1(lc, "expected an integer number, got: %s", lc->str);
469       }
470    }
471    scan_to_eol(lc);
472    set_bit(index, res_all.hdr.item_present);
473 }
474
475 /* Store a positive integer at specified address */
476 void store_pint(LEX *lc, struct res_items *item, int index, int pass)
477 {
478    int token;
479
480    token = lex_get_token(lc);
481    if (token != T_NUMBER || !is_a_number(lc->str)) {
482       scan_err1(lc, "expected a positive integer number, got: %s", lc->str);
483    } else {
484       errno = 0;
485       token = (int)strtod(lc->str, NULL);
486       if (errno != 0 || token < 0) {
487          scan_err1(lc, "expected a postive integer number, got: %s", lc->str);
488       }
489       *(int *)(item->value) = token;
490    }
491    scan_to_eol(lc);
492    set_bit(index, res_all.hdr.item_present);
493 }
494
495
496 /* Store an 64 bit integer at specified address */
497 void store_int64(LEX *lc, struct res_items *item, int index, int pass)
498 {
499    int token;
500
501    token = lex_get_token(lc);
502    Dmsg2(400, "int64=:%s: %f\n", lc->str, strtod(lc->str, NULL)); 
503    if (token != T_NUMBER || !is_a_number(lc->str)) {
504       scan_err1(lc, "expected an integer number, got: %s", lc->str);
505    } else {
506       errno = 0;
507       *(int64_t *)(item->value) = (int64_t)strtod(lc->str, NULL);
508       if (errno != 0)
509          scan_err1(lc, "expected an integer number, got: %s", lc->str);
510    }
511    scan_to_eol(lc);
512    set_bit(index, res_all.hdr.item_present);
513 }
514
515 /* Store a size in bytes */
516 void store_size(LEX *lc, struct res_items *item, int index, int pass)
517 {
518    int token, i, ch;
519    uint64_t value;
520    int mod[]  = {'*', 'k', 'm', 'g', 0}; /* first item * not used */
521    uint64_t mult[] = {1,             /* byte */
522                       1024,          /* kilobyte */
523                       1048576,       /* megabyte */
524                       1073741824};   /* gigabyte */
525
526 #ifdef we_have_a_compiler_that_works
527    int mod[]  = {'*', 'k', 'm', 'g', 't', 0};
528    uint64_t mult[] = {1,             /* byte */
529                       1024,          /* kilobyte */
530                       1048576,       /* megabyte */
531                       1073741824,    /* gigabyte */
532                       1099511627776};/* terabyte */
533 #endif
534
535    Dmsg0(400, "Enter store_size\n");
536    token = lex_get_token(lc);
537    errno = 0;
538    switch (token) {
539    case T_NUMBER:
540       Dmsg2(400, "size num=:%s: %f\n", lc->str, strtod(lc->str, NULL)); 
541       value = (uint64_t)strtod(lc->str, NULL);
542       if (errno != 0 || token < 0) {
543          scan_err1(lc, "expected a size number, got: %s", lc->str);
544       }
545       *(uint64_t *)(item->value) = value;
546       break;
547    case T_IDENTIFIER:
548    case T_STRING:
549       /* Look for modifier */
550       ch = lc->str[lc->str_len - 1];
551       i = 0;
552       if (ISALPHA(ch)) {
553          if (ISUPPER(ch)) {
554             ch = tolower(ch);
555          }
556          while (mod[++i] != 0) {
557             if (ch == mod[i]) {
558                lc->str_len--;
559                lc->str[lc->str_len] = 0; /* strip modifier */
560                break;
561             }
562          }
563       }
564       if (mod[i] == 0 || !is_a_number(lc->str)) {
565          scan_err1(lc, "expected a size number, got: %s", lc->str);
566       }
567       Dmsg3(400, "size str=:%s: %f i=%d\n", lc->str, strtod(lc->str, NULL), i);
568
569       value = (uint64_t)strtod(lc->str, NULL);
570       Dmsg1(400, "Int value = %d\n", (int)value);
571       if (errno != 0 || value < 0) {
572          scan_err1(lc, "expected a size number, got: %s", lc->str);
573       }
574       *(uint64_t *)(item->value) = value * mult[i];
575       Dmsg2(400, "Full value = %f %" lld "\n", strtod(lc->str, NULL) * mult[i],
576           value *mult[i]);
577       break;
578    default:
579       scan_err1(lc, "expected a size, got: %s", lc->str);
580       break;
581    }
582    scan_to_eol(lc);
583    set_bit(index, res_all.hdr.item_present);
584    Dmsg0(400, "Leave store_size\n");
585 }
586
587
588 /* Store a time period in seconds */
589 void store_time(LEX *lc, struct res_items *item, int index, int pass)
590 {
591    int token; 
592    btime_t value;
593
594    token = lex_get_token(lc);
595    errno = 0;
596    switch (token) {
597    case T_NUMBER:
598       value = (btime_t)strtod(lc->str, NULL);
599       if (errno != 0 || value < 0) {
600          scan_err1(lc, "expected a time period, got: %s", lc->str);
601       }
602       *(btime_t *)(item->value) = value;
603       break;
604    case T_IDENTIFIER:
605    case T_STRING:
606       if (!string_to_btime(lc->str, &value)) {
607          scan_err1(lc, "expected a time period, got: %s", lc->str);
608       }
609       *(btime_t *)(item->value) = value;
610       break;
611    default:
612       scan_err1(lc, "expected a time period, got: %s", lc->str);
613       break;
614    }
615    scan_to_eol(lc);
616    set_bit(index, res_all.hdr.item_present);
617 }
618
619
620 /* Store a yes/no in a bit field */
621 void store_yesno(LEX *lc, struct res_items *item, int index, int pass)
622 {
623    int token;
624
625    token = lex_get_token(lc);
626    lcase(lc->str);
627    if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) {
628       scan_err1(lc, "expected an identifier or string, got: %s", lc->str);
629    } else if (strcmp(lc->str, "yes") == 0) {
630       *(int *)(item->value) |= item->code;
631    } else if (strcmp(lc->str, "no") == 0) {
632       *(int *)(item->value) &= ~(item->code);
633    } else {
634       scan_err1(lc, "Expect a YES or NO, got: %s", lc->str);
635    }
636    scan_to_eol(lc);
637    set_bit(index, res_all.hdr.item_present);
638 }
639
640
641 /*
642  * Scan to "logical" end of line. I.e. end of line,
643  * or semicolon.
644  */
645 void scan_to_eol(LEX *lc)
646 {
647    int token;
648    Dmsg0(150, "start scan to eof\n");
649    while ((token = lex_get_token(lc)) != T_EOL) {
650    }
651    Dmsg0(150, "done scan to eof\n");
652 }
653
654    
655 /*
656  * Format a scanner error message 
657  */
658 void s_err(char *file, int line, LEX *lc, char *msg, ...)
659 {
660    va_list arg_ptr;
661    char buf[MAXSTRING];
662
663    va_start(arg_ptr, msg);
664    bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
665    va_end(arg_ptr);
666      
667    e_msg(file, line, M_ABORT, 0, "Config error: %s,\n\
668             : Line %d, col %d of file %s\n%s\n",
669       buf, lc->line_no, lc->col_no, lc->fname, lc->line);
670 }
671
672 void LockRes()
673 {
674    P(res_mutex);
675    res_locked = 1;
676 }
677
678 void UnlockRes()
679 {
680    res_locked = 0;
681    V(res_mutex);
682 }
683
684 /*
685  * Return resource of type rcode that matches name
686  */
687 RES *
688 GetResWithName(int rcode, char *name)
689 {
690    RES *res;
691    int rindex = rcode - r_first;
692
693    LockRes();
694    res = resources[rindex].res_head;
695    while (res) {
696       if (strcmp(res->name, name) == 0) {
697          break;
698       }
699       res = res->next;
700    }
701    UnlockRes();
702    return res;
703    
704 }
705
706 /*
707  * Return next resource of type rcode. On first
708  * call second arg (res) is NULL, on subsequent
709  * calls, it is called with previous value.
710  */
711 RES *
712 GetNextRes(int rcode, RES *res)
713 {
714    RES *nres;
715    int rindex = rcode - r_first;
716        
717
718    if (!res_locked) {
719       Emsg0(M_ABORT, 0, "Resource chain not locked.\n");
720    }
721    if (res == NULL) {
722       nres = resources[rindex].res_head;
723    } else {
724       nres = res->next;
725    }
726    return nres;
727 }
728
729
730 /* Parser state */
731 enum parse_state {
732    p_none,
733    p_resource
734 };
735
736 /*********************************************************************
737  *
738  *      Parse configuration file
739  *
740  */
741 void 
742 parse_config(char *cf)
743 {
744    LEX *lc = NULL;
745    int token, i, res_type, pass;
746    enum parse_state state = p_none;
747    struct res_items *items;
748    int level = 0;
749
750    /* Make two passes. The first builds the name symbol table,
751     * and the second picks up the items. 
752     */
753    Dmsg0(200, "Enter parse_config()\n");
754    for (pass=1; pass<= 2; pass++) {
755       Dmsg1(200, "parse_config pass %d\n", pass);
756       lc = lex_open_file(lc, cf);
757       while ((token=lex_get_token(lc)) != T_EOF) {
758          Dmsg1(150, "parse got token=%s\n", lex_tok_to_str(token));
759          switch (state) {
760             case p_none:
761                if (token == T_EOL) {
762                   break;
763                }
764                if (token != T_IDENTIFIER) {
765                   scan_err1(lc, "Expected a Resource name identifier, got: %s", lc->str);
766                }
767                lcase(lc->str);
768                for (i=0; resources[i].name; i++)
769                   if (strcmp(resources[i].name, lc->str) == 0) {
770                      state = p_resource;
771                      items = resources[i].items;
772                      res_type = resources[i].rcode;
773                      init_resource(res_type, items);
774                      break;
775                   }
776                if (state == p_none) {
777                   scan_err1(lc, "expected resource name, got: %s", lc->str);
778                }
779                break;
780             case p_resource:
781                switch (token) {
782                   case T_BOB:
783                      level++;
784                      break;
785                   case T_IDENTIFIER:
786                      if (level != 1) {
787                         scan_err1(lc, "not in resource definition: %s", lc->str);
788                      }
789                      lcase(lc->str);
790                      for (i=0; items[i].name; i++) {
791                         if (strcmp(items[i].name, lc->str) == 0) {
792                            token = lex_get_token(lc);
793                            Dmsg1 (150, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
794                            if (token != T_EQUALS) {
795                               scan_err1(lc, "expected an equals, got: %s", lc->str);
796                            }
797                            Dmsg1(150, "calling handler for %s\n", items[i].name);
798                            /* Call item handler */
799                            items[i].handler(lc, &items[i], i, pass);
800                            i = -1;
801                            break;
802                         }
803                      }
804                      if (i >= 0) {
805                         Dmsg2(150, "level=%d id=%s\n", level, lc->str);
806                         Dmsg1(150, "Keyword = %s\n", lc->str);
807                         scan_err1(lc, "Keyword %s not permitted in this resource", lc->str);
808                      }
809                      break;
810
811                   case T_EOB:
812                      level--;
813                      state = p_none;
814                      Dmsg0(150, "T_EOB => define new resource\n");
815                      save_resource(res_type, items, pass);  /* save resource */
816                      break;
817
818                   case T_EOL:
819                      break;
820
821                   default:
822                      scan_err2(lc, "unexpected token %d %s in resource definition",    
823                         token, lex_tok_to_str(token));
824                }
825                break;
826             default:
827                scan_err1(lc, "Unknown parser state %d\n", state);
828          }
829       }
830       if (debug_level > 50 && pass == 2) {
831          int i;
832          for (i=r_first; i<=r_last; i++) {
833             dump_resource(i, resources[i-r_first].res_head, prtmsg, NULL);
834          }
835       }
836       lc = lex_close_file(lc);
837    }
838    Dmsg0(200, "Leave parse_config()\n");
839 }
840
841 /*********************************************************************
842  *
843  *      Free configuration resources
844  *
845  */
846 void 
847 free_config_resources()
848 {
849    int i;
850    for (i=r_first; i<=r_last; i++) {
851       free_resource(i);
852    }
853 }