]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lex.c
- fix : reload a bad configuration file doesn't kill director any more
[bacula/bacula] / bacula / src / lib / lex.c
1 /*
2  * Lexical scanner for Bacula configuration file
3  *
4  *   Kern Sibbald, 2000
5  *
6  *   Version $Id$
7  *
8  */
9
10 /*
11    Copyright (C) 2000-2005 Kern Sibbald
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of
16    the License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public
24    License along with this program; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "lex.h"
32
33 extern int debug_level;
34
35 /*
36  * Scan to "logical" end of line. I.e. end of line,
37  *   or semicolon, but stop on T_EOB (same as end of
38  *   line except it is not eaten).
39  */
40 void scan_to_eol(LEX *lc)
41 {
42    int token;
43    Dmsg0(2000, "start scan to eof\n");
44    while ((token = lex_get_token(lc, T_ALL)) != T_EOL) {
45       if (token == T_EOB) {
46          lex_unget_char(lc);
47          return;
48       }
49    }
50 }
51
52 /*
53  * Get next token, but skip EOL
54  */
55 int scan_to_next_not_eol(LEX * lc)
56 {
57    int token;
58    do {
59       token = lex_get_token(lc, T_ALL);
60    } while (token == T_EOL);
61    return token;
62 }
63
64 /*
65  * Format a scanner error message
66  */
67 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
68 {
69    va_list arg_ptr;
70    char buf[MAXSTRING];
71    char more[MAXSTRING];
72
73    va_start(arg_ptr, msg);
74    bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
75    va_end(arg_ptr);
76
77    if (lc->err_type == 0) {     /* M_ERROR_TERM by default */
78       lc->err_type = M_ERROR_TERM;
79    }
80
81    if (lc->line_no > lc->begin_line_no) {
82       bsnprintf(more, sizeof(more),
83                 _("Problem probably begins at line %d.\n"), lc->begin_line_no);
84    } else {
85       more[0] = 0;
86    }  
87    if (lc->line_no > 0) {
88       e_msg(file, line, lc->err_type, 0, _("Config error: %s\n"
89 "            : line %d, col %d of file %s\n%s\n%s"),
90          buf, lc->line_no, lc->col_no, lc->fname, lc->line, more);
91    } else {
92       e_msg(file, line, lc->err_type, 0, _("Config error: %s\n"), buf);
93    }
94 }
95
96 void lex_set_default_error_handler(LEX *lf)
97 {
98    lf->scan_error = s_err;
99 }
100
101 /*
102  * Set err_type used in error_handler
103  * return the old value
104  */
105 int lex_set_error_handler_error_type(LEX *lf, int err_type)
106 {
107    int old = lf->err_type;
108    lf->err_type = err_type;
109    return old;
110 }
111
112 /*
113  * Free the current file, and retrieve the contents
114  * of the previous packet if any.
115  */
116 LEX *lex_close_file(LEX *lf)
117 {
118    LEX *of;
119
120    if (lf == NULL) {
121       Emsg0(M_ABORT, 0, _("Close of NULL file\n"));
122    }
123    Dmsg1(2000, "Close lex file: %s\n", lf->fname);
124
125    of = lf->next;
126    fclose(lf->fd);
127    Dmsg1(2000, "Close cfg file %s\n", lf->fname);
128    free(lf->fname);
129    if (of) {
130       of->options = lf->options;      /* preserve options */
131       memcpy(lf, of, sizeof(LEX));
132       Dmsg1(2000, "Restart scan of cfg file %s\n", of->fname);
133    } else {
134       of = lf;
135       lf = NULL;
136    }
137    free(of);
138    return lf;
139 }
140
141 /*
142  * Open a new configuration file. We push the
143  * state of the current file (lf) so that we
144  * can do includes.  This is a bit of a hammer.
145  * Instead of passing back the pointer to the
146  * new packet, I simply replace the contents
147  * of the caller's packet with the new packet,
148  * and link the contents of the old packet into
149  * the next field.
150  *
151  */
152 LEX *lex_open_file(LEX *lf, const char *filename, LEX_ERROR_HANDLER *scan_error)
153
154 {
155    LEX *nf;
156    FILE *fd;
157    char *fname = bstrdup(filename);
158
159
160    if ((fd = fopen(fname, "r")) == NULL) {
161       return NULL;
162    }
163    Dmsg1(400, "Open config file: %s\n", fname);
164    nf = (LEX *)malloc(sizeof(LEX));
165    if (lf) {
166       memcpy(nf, lf, sizeof(LEX));
167       memset(lf, 0, sizeof(LEX));
168       lf->next = nf;                  /* if have lf, push it behind new one */
169       lf->options = nf->options;      /* preserve user options */
170    } else {
171       lf = nf;                        /* start new packet */
172       memset(lf, 0, sizeof(LEX));
173       lex_set_error_handler_error_type(lf, M_ERROR_TERM);
174    }
175    if (scan_error) {
176       lf->scan_error = scan_error;
177    } else {
178       lex_set_default_error_handler(lf);
179    }
180    lf->fd = fd;
181    lf->fname = fname;
182    lf->state = lex_none;
183    lf->ch = L_EOL;
184    Dmsg1(2000, "Return lex=%x\n", lf);
185    return lf;
186 }
187
188 /*
189  * Get the next character from the input.
190  *  Returns the character or
191  *    L_EOF if end of file
192  *    L_EOL if end of line
193  */
194 int lex_get_char(LEX *lf)
195 {
196    if (lf->ch == L_EOF) {
197       Emsg0(M_ABORT, 0, _("get_char: called after EOF\n"));
198    }
199    if (lf->ch == L_EOL) {
200       if (bfgets(lf->line, MAXSTRING, lf->fd) == NULL) {
201          lf->ch = L_EOF;
202          if (lf->next) {
203             lex_close_file(lf);
204          }
205          return lf->ch;
206       }
207       lf->line_no++;
208       lf->col_no = 0;
209       Dmsg2(1000, "fget line=%d %s", lf->line_no, lf->line);
210    }
211    lf->ch = (uint8_t)lf->line[lf->col_no];
212    if (lf->ch == 0) {
213       lf->ch = L_EOL;
214    } else {
215       lf->col_no++;
216    }
217    Dmsg2(2000, "lex_get_char: %c %d\n", lf->ch, lf->ch);
218    return lf->ch;
219 }
220
221 void lex_unget_char(LEX *lf)
222 {
223    lf->col_no--;
224    if (lf->ch == L_EOL)
225       lf->ch = 0;
226 }
227
228
229 /*
230  * Add a character to the current string
231  */
232 static void add_str(LEX *lf, int ch)
233 {
234    if (lf->str_len >= MAXSTRING-3) {
235       Emsg3(M_ERROR_TERM, 0, _(
236            _("Config token too long, file: %s, line %d, begins at line %d\n")),
237              lf->fname, lf->line_no, lf->begin_line_no);
238    }
239    lf->str[lf->str_len++] = ch;
240    lf->str[lf->str_len] = 0;
241 }
242
243 /*
244  * Begin the string
245  */
246 static void begin_str(LEX *lf, int ch)
247 {
248    lf->str_len = 0;
249    lf->str[0] = 0;
250    if (ch != 0) {
251       add_str(lf, ch);
252    }
253    lf->begin_line_no = lf->line_no;   /* save start string line no */
254 }
255
256 #ifdef DEBUG
257 static const char *lex_state_to_str(int state)
258 {
259    switch (state) {
260    case lex_none:          return _("none");
261    case lex_comment:       return _("comment");
262    case lex_number:        return _("number");
263    case lex_ip_addr:       return _("ip_addr");
264    case lex_identifier:    return _("identifier");
265    case lex_string:        return _("string");
266    case lex_quoted_string: return _("quoted_string");
267    default:                return "??????";
268    }
269 }
270 #endif
271
272 /*
273  * Convert a lex token to a string
274  * used for debug/error printing.
275  */
276 const char *lex_tok_to_str(int token)
277 {
278    switch(token) {
279    case L_EOF:             return "L_EOF";
280    case L_EOL:             return "L_EOL";
281    case T_NONE:            return "T_NONE";
282    case T_NUMBER:          return "T_NUMBER";
283    case T_IPADDR:          return "T_IPADDR";
284    case T_IDENTIFIER:      return "T_IDENTIFIER";
285    case T_UNQUOTED_STRING: return "T_UNQUOTED_STRING";
286    case T_QUOTED_STRING:   return "T_QUOTED_STRING";
287    case T_BOB:             return "T_BOB";
288    case T_EOB:             return "T_EOB";
289    case T_EQUALS:          return "T_EQUALS";
290    case T_ERROR:           return "T_ERROR";
291    case T_EOF:             return "T_EOF";
292    case T_COMMA:           return "T_COMMA";
293    case T_EOL:             return "T_EOL";
294    default:                return "??????";
295    }
296 }
297
298 static uint32_t scan_pint(LEX *lf, char *str)
299 {
300    int64_t val = 0;
301    if (!is_a_number(str)) {
302       scan_err1(lf, _("expected a positive integer number, got: %s"), str);
303       /* NOT REACHED */
304    } else {
305       errno = 0;
306       val = str_to_int64(str);
307       if (errno != 0 || val < 0) {
308          scan_err1(lf, _("expected a positive integer number, got: %s"), str);
309          /* NOT REACHED */
310       }
311    }
312    return (uint32_t)val;
313 }
314
315 /*
316  *
317  * Get the next token from the input
318  *
319  */
320 int
321 lex_get_token(LEX *lf, int expect)
322 {
323    int ch;
324    int token = T_NONE;
325    bool esc_next = false;
326
327    Dmsg0(2000, "enter lex_get_token\n");
328    while (token == T_NONE) {
329       ch = lex_get_char(lf);
330       switch (lf->state) {
331       case lex_none:
332          Dmsg2(2000, "Lex state lex_none ch=%d,%x\n", ch, ch);
333          if (B_ISSPACE(ch))
334             break;
335          if (B_ISALPHA(ch)) {
336             if (lf->options & LOPT_NO_IDENT || lf->options & LOPT_STRING) {
337                lf->state = lex_string;
338             } else {
339                lf->state = lex_identifier;
340             }
341             begin_str(lf, ch);
342             break;
343          }
344          if (B_ISDIGIT(ch)) {
345             if (lf->options & LOPT_STRING) {
346                lf->state = lex_string;
347             } else {
348                lf->state = lex_number;
349             }
350             begin_str(lf, ch);
351             break;
352          }
353          Dmsg0(2000, "Enter lex_none switch\n");
354          switch (ch) {
355          case L_EOF:
356             token = T_EOF;
357             Dmsg0(2000, "got L_EOF set token=T_EOF\n");
358             break;
359          case '#':
360             lf->state = lex_comment;
361             break;
362          case '{':
363             token = T_BOB;
364             begin_str(lf, ch);
365             break;
366          case '}':
367             token = T_EOB;
368             begin_str(lf, ch);
369             break;
370          case '"':
371             lf->state = lex_quoted_string;
372             begin_str(lf, 0);
373             break;
374          case '=':
375             token = T_EQUALS;
376             begin_str(lf, ch);
377             break;
378          case ',':
379             token = T_COMMA;
380             begin_str(lf, ch);
381             break;
382          case ';':
383             if (expect != T_SKIP_EOL) {
384                token = T_EOL;      /* treat ; like EOL */
385             }
386             break;
387          case L_EOL:
388             Dmsg0(2000, "got L_EOL set token=T_EOL\n");
389             if (expect != T_SKIP_EOL) {
390                token = T_EOL;
391             }
392             break;
393          case '@':
394             lf->state = lex_include;
395             begin_str(lf, 0);
396             break;
397          default:
398             lf->state = lex_string;
399             begin_str(lf, ch);
400             break;
401          }
402          break;
403       case lex_comment:
404          Dmsg1(2000, "Lex state lex_comment ch=%x\n", ch);
405          if (ch == L_EOL) {
406             lf->state = lex_none;
407             if (expect != T_SKIP_EOL) {
408                token = T_EOL;
409             }
410          } else if (ch == L_EOF) {
411             token = T_ERROR;
412          }
413          break;
414       case lex_number:
415          Dmsg2(2000, "Lex state lex_number ch=%x %c\n", ch, ch);
416          if (ch == L_EOF) {
417             token = T_ERROR;
418             break;
419          }
420          /* Might want to allow trailing specifications here */
421          if (B_ISDIGIT(ch)) {
422             add_str(lf, ch);
423             break;
424          }
425
426          /* A valid number can be terminated by the following */
427          if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
428             token = T_NUMBER;
429             lf->state = lex_none;
430          } else {
431             lf->state = lex_string;
432          }
433          lex_unget_char(lf);
434          break;
435       case lex_ip_addr:
436          if (ch == L_EOF) {
437             token = T_ERROR;
438             break;
439          }
440          Dmsg1(2000, "Lex state lex_ip_addr ch=%x\n", ch);
441          break;
442       case lex_string:
443          Dmsg1(2000, "Lex state lex_string ch=%x\n", ch);
444          if (ch == L_EOF) {
445             token = T_ERROR;
446             break;
447          }
448          if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
449              ch == '\r' || ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) {
450             lex_unget_char(lf);
451             token = T_UNQUOTED_STRING;
452             lf->state = lex_none;
453             break;
454          }
455          add_str(lf, ch);
456          break;
457       case lex_identifier:
458          Dmsg2(2000, "Lex state lex_identifier ch=%x %c\n", ch, ch);
459          if (B_ISALPHA(ch)) {
460             add_str(lf, ch);
461             break;
462          } else if (B_ISSPACE(ch)) {
463             break;
464          } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
465                     ch == '\r' || ch == ';' || ch == ','   || ch == '"' || ch == '#') {
466             lex_unget_char(lf);
467             token = T_IDENTIFIER;
468             lf->state = lex_none;
469             break;
470          } else if (ch == L_EOF) {
471             token = T_ERROR;
472             lf->state = lex_none;
473             begin_str(lf, ch);
474             break;
475          }
476          /* Some non-alpha character => string */
477          lf->state = lex_string;
478          add_str(lf, ch);
479          break;
480       case lex_quoted_string:
481          Dmsg2(2000, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
482          if (ch == L_EOF) {
483             token = T_ERROR;
484             break;
485          }
486          if (ch == L_EOL) {
487             esc_next = false;
488             break;
489          }
490          if (esc_next) {
491             add_str(lf, ch);
492             esc_next = false;
493             break;
494          }
495          if (ch == '\\') {
496             esc_next = true;
497             break;
498          }
499          if (ch == '"') {
500             token = T_QUOTED_STRING;
501             lf->state = lex_none;
502             break;
503          }
504          add_str(lf, ch);
505          break;
506       case lex_include:            /* scanning a filename */
507          if (ch == L_EOF) {
508             token = T_ERROR;
509             break;
510          }
511          if (B_ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' ||
512              ch == ';' || ch == ','   || ch == '"' || ch == '#') {
513             /* Keep the original LEX so we can print an error if the included file can't be opened. */
514             LEX* lfori = lf;
515             
516             lf->state = lex_none;
517             lf = lex_open_file(lf, lf->str, lf->scan_error);
518             if (lf == NULL) {
519                berrno be;
520                scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
521                   lfori->str, be.strerror());
522                return T_ERROR;
523             }
524             break;
525          }
526          add_str(lf, ch);
527          break;
528       }
529       Dmsg4(2000, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state),
530         lex_tok_to_str(token), ch);
531    }
532    Dmsg2(2000, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
533    lf->token = token;
534
535    /*
536     * Here is where we check to see if the user has set certain
537     *  expectations (e.g. 32 bit integer). If so, we do type checking
538     *  and possible additional scanning (e.g. for range).
539     */
540    switch (expect) {
541    case T_PINT32:
542       lf->pint32_val = scan_pint(lf, lf->str);
543       lf->pint32_val2 = lf->pint32_val;
544       token = T_PINT32;
545       break;
546
547    case T_PINT32_RANGE:
548       if (token == T_NUMBER) {
549          lf->pint32_val = scan_pint(lf, lf->str);
550          lf->pint32_val2 = lf->pint32_val;
551          token = T_PINT32;
552       } else {
553          char *p = strchr(lf->str, '-');
554          if (!p) {
555             scan_err2(lf, _("expected an integer or a range, got %s: %s"),
556                lex_tok_to_str(token), lf->str);
557             token = T_ERROR;
558             break;
559          }
560          *p++ = 0;                       /* terminate first half of range */
561          lf->pint32_val  = scan_pint(lf, lf->str);
562          lf->pint32_val2 = scan_pint(lf, p);
563          token = T_PINT32_RANGE;
564       }
565       break;
566
567    case T_INT32:
568       if (token != T_NUMBER || !is_a_number(lf->str)) {
569          scan_err2(lf, _("expected an integer number, got %s: %s"),
570                lex_tok_to_str(token), lf->str);
571          token = T_ERROR;
572          break;
573       }
574       errno = 0;
575       lf->int32_val = (int32_t)str_to_int64(lf->str);
576       if (errno != 0) {
577          scan_err2(lf, _("expected an integer number, got %s: %s"),
578                lex_tok_to_str(token), lf->str);
579          token = T_ERROR;
580       } else {
581          token = T_INT32;
582       }
583       break;
584
585    case T_INT64:
586       Dmsg2(2000, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL));
587       if (token != T_NUMBER || !is_a_number(lf->str)) {
588          scan_err2(lf, _("expected an integer number, got %s: %s"),
589                lex_tok_to_str(token), lf->str);
590          token = T_ERROR;
591          break;
592       }
593       errno = 0;
594       lf->int64_val = str_to_int64(lf->str);
595       if (errno != 0) {
596          scan_err2(lf, _("expected an integer number, got %s: %s"),
597                lex_tok_to_str(token), lf->str);
598          token = T_ERROR;
599       } else {
600          token = T_INT64;
601       }
602       break;
603
604    case T_NAME:
605       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
606          scan_err2(lf, _("expected a name, got %s: %s"),
607                lex_tok_to_str(token), lf->str);
608          token = T_ERROR;
609       } else if (lf->str_len > MAX_RES_NAME_LENGTH) {
610          scan_err3(lf, _("name %s length %d too long, max is %d\n"), lf->str,
611             lf->str_len, MAX_RES_NAME_LENGTH);
612          token = T_ERROR;
613       }
614       break;
615
616    case T_STRING:
617       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
618          scan_err2(lf, _("expected a string, got %s: %s"),
619                lex_tok_to_str(token), lf->str);
620          token = T_ERROR;
621       } else {
622          token = T_STRING;
623       }
624       break;
625
626
627    default:
628       break;                          /* no expectation given */
629    }
630    lf->token = token;                 /* set possible new token */
631    return token;
632 }