]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/lex.c
kes Rework projects file to be current and ready for a vote.
[bacula/bacula] / bacula / src / lib / lex.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
5
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 and included
11    in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28 /*
29  * Lexical scanner for Bacula configuration file
30  *
31  *   Kern Sibbald, 2000
32  *
33  *   Version $Id$
34  *
35  */
36
37 #include "bacula.h"
38 #include "lex.h"
39
40 extern int debug_level;
41
42 /* Debug level for this source file */
43 static const int dbglvl = 5000;
44
45 /*
46  * Scan to "logical" end of line. I.e. end of line,
47  *   or semicolon, but stop on T_EOB (same as end of
48  *   line except it is not eaten).
49  */
50 void scan_to_eol(LEX *lc)
51 {
52    int token;
53    Dmsg0(dbglvl, "start scan to eof\n");
54    while ((token = lex_get_token(lc, T_ALL)) != T_EOL) {
55       if (token == T_EOB) {
56          lex_unget_char(lc);
57          return;
58       }
59    }
60 }
61
62 /*
63  * Get next token, but skip EOL
64  */
65 int scan_to_next_not_eol(LEX * lc)
66 {
67    int token;
68    do {
69       token = lex_get_token(lc, T_ALL);
70    } while (token == T_EOL);
71    return token;
72 }
73
74 /*
75  * Format a scanner error message
76  */
77 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
78 {
79    va_list arg_ptr;
80    char buf[MAXSTRING];
81    char more[MAXSTRING];
82
83    va_start(arg_ptr, msg);
84    bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
85    va_end(arg_ptr);
86
87    if (lc->err_type == 0) {     /* M_ERROR_TERM by default */
88       lc->err_type = M_ERROR_TERM;
89    }
90
91    if (lc->line_no > lc->begin_line_no) {
92       bsnprintf(more, sizeof(more),
93                 _("Problem probably begins at line %d.\n"), lc->begin_line_no);
94    } else {
95       more[0] = 0;
96    }  
97    if (lc->line_no > 0) {
98       e_msg(file, line, lc->err_type, 0, _("Config error: %s\n"
99 "            : line %d, col %d of file %s\n%s\n%s"),
100          buf, lc->line_no, lc->col_no, lc->fname, lc->line, more);
101    } else {
102       e_msg(file, line, lc->err_type, 0, _("Config error: %s\n"), buf);
103    }
104 }
105
106 void lex_set_default_error_handler(LEX *lf)
107 {
108    lf->scan_error = s_err;
109 }
110
111 /*
112  * Set err_type used in error_handler
113  * return the old value
114  */
115 int lex_set_error_handler_error_type(LEX *lf, int err_type)
116 {
117    int old = lf->err_type;
118    lf->err_type = err_type;
119    return old;
120 }
121
122 /*
123  * Free the current file, and retrieve the contents
124  * of the previous packet if any.
125  */
126 LEX *lex_close_file(LEX *lf)
127 {
128    LEX *of;
129
130    if (lf == NULL) {
131       Emsg0(M_ABORT, 0, _("Close of NULL file\n"));
132    }
133    Dmsg1(dbglvl, "Close lex file: %s\n", lf->fname);
134
135    of = lf->next;
136    if (lf->bpipe) {
137       close_bpipe(lf->bpipe);
138       lf->bpipe = NULL;
139    } else {
140       fclose(lf->fd);
141    }
142    Dmsg1(dbglvl, "Close cfg file %s\n", lf->fname);
143    free(lf->fname);
144    if (of) {
145       of->options = lf->options;      /* preserve options */
146       memcpy(lf, of, sizeof(LEX));
147       Dmsg1(dbglvl, "Restart scan of cfg file %s\n", of->fname);
148    } else {
149       of = lf;
150       lf = NULL;
151    }
152    free(of);
153    return lf;
154 }
155
156 /*
157  * Open a new configuration file. We push the
158  * state of the current file (lf) so that we
159  * can do includes.  This is a bit of a hammer.
160  * Instead of passing back the pointer to the
161  * new packet, I simply replace the contents
162  * of the caller's packet with the new packet,
163  * and link the contents of the old packet into
164  * the next field.
165  *
166  */
167 LEX *lex_open_file(LEX *lf, const char *filename, LEX_ERROR_HANDLER *scan_error)
168
169 {
170    LEX *nf;
171    FILE *fd;
172    BPIPE *bpipe = NULL;
173    char *fname = bstrdup(filename);
174
175
176    if (fname[0] == '|') {
177       if ((bpipe = open_bpipe(fname, 0, "rb")) == NULL) {
178          free(fname);
179          return NULL;
180       }
181       fd = bpipe->rfd;
182    } else if ((fd = fopen(fname, "rb")) == NULL) {
183       free(fname);
184       return NULL;
185    }
186    Dmsg1(400, "Open config file: %s\n", fname);
187    nf = (LEX *)malloc(sizeof(LEX));
188    if (lf) {
189       memcpy(nf, lf, sizeof(LEX));
190       memset(lf, 0, sizeof(LEX));
191       lf->next = nf;                  /* if have lf, push it behind new one */
192       lf->options = nf->options;      /* preserve user options */
193       /*
194        * preserve err_type to prevent bacula exiting on 'reload' 
195        * if config is invalid. Fixes bug #877         
196        */
197       lf->err_type = nf->err_type;    
198    } else {
199       lf = nf;                        /* start new packet */
200       memset(lf, 0, sizeof(LEX));
201       lex_set_error_handler_error_type(lf, M_ERROR_TERM);
202    }
203    if (scan_error) {
204       lf->scan_error = scan_error;
205    } else {
206       lex_set_default_error_handler(lf);
207    }
208    lf->fd = fd;
209    lf->bpipe = bpipe;
210    lf->fname = fname;
211    lf->state = lex_none;
212    lf->ch = L_EOL;
213    Dmsg1(dbglvl, "Return lex=%x\n", lf);
214    return lf;
215 }
216
217 /*
218  * Get the next character from the input.
219  *  Returns the character or
220  *    L_EOF if end of file
221  *    L_EOL if end of line
222  */
223 int lex_get_char(LEX *lf)
224 {
225    if (lf->ch == L_EOF) {
226       Emsg0(M_ABORT, 0, _("get_char: called after EOF."
227          " You may have a open double quote without the closing double quote.\n"));
228    }
229    if (lf->ch == L_EOL) {
230       if (bfgets(lf->line, MAXSTRING, lf->fd) == NULL) {
231          lf->ch = L_EOF;
232          if (lf->next) {
233             lex_close_file(lf);
234          }
235          return lf->ch;
236       }
237       lf->line_no++;
238       lf->col_no = 0;
239       Dmsg2(1000, "fget line=%d %s", lf->line_no, lf->line);
240    }
241    lf->ch = (uint8_t)lf->line[lf->col_no];
242    if (lf->ch == 0) {
243       lf->ch = L_EOL;
244    } else {
245       lf->col_no++;
246    }
247    Dmsg2(dbglvl, "lex_get_char: %c %d\n", lf->ch, lf->ch);
248    return lf->ch;
249 }
250
251 void lex_unget_char(LEX *lf)
252 {
253    if (lf->ch == L_EOL) {
254       lf->ch = 0;                     /* End of line, force read of next one */
255    } else {
256       lf->col_no--;                   /* Backup to re-read char */
257    }
258
259 }
260
261
262 /*
263  * Add a character to the current string
264  */
265 static void add_str(LEX *lf, int ch)
266 {
267    if (lf->str_len >= MAXSTRING-3) {
268       Emsg3(M_ERROR_TERM, 0, _(
269            _("Config token too long, file: %s, line %d, begins at line %d\n")),
270              lf->fname, lf->line_no, lf->begin_line_no);
271    }
272    lf->str[lf->str_len++] = ch;
273    lf->str[lf->str_len] = 0;
274 }
275
276 /*
277  * Begin the string
278  */
279 static void begin_str(LEX *lf, int ch)
280 {
281    lf->str_len = 0;
282    lf->str[0] = 0;
283    if (ch != 0) {
284       add_str(lf, ch);
285    }
286    lf->begin_line_no = lf->line_no;   /* save start string line no */
287 }
288
289 #ifdef DEBUG
290 static const char *lex_state_to_str(int state)
291 {
292    switch (state) {
293    case lex_none:          return _("none");
294    case lex_comment:       return _("comment");
295    case lex_number:        return _("number");
296    case lex_ip_addr:       return _("ip_addr");
297    case lex_identifier:    return _("identifier");
298    case lex_string:        return _("string");
299    case lex_quoted_string: return _("quoted_string");
300    case lex_utf8_bom:      return _("UTF-8 Byte Order Mark");
301    case lex_utf16_le_bom:  return _("UTF-16le Byte Order Mark");
302    default:                return "??????";
303    }
304 }
305 #endif
306
307 /*
308  * Convert a lex token to a string
309  * used for debug/error printing.
310  */
311 const char *lex_tok_to_str(int token)
312 {
313    switch(token) {
314    case L_EOF:             return "L_EOF";
315    case L_EOL:             return "L_EOL";
316    case T_NONE:            return "T_NONE";
317    case T_NUMBER:          return "T_NUMBER";
318    case T_IPADDR:          return "T_IPADDR";
319    case T_IDENTIFIER:      return "T_IDENTIFIER";
320    case T_UNQUOTED_STRING: return "T_UNQUOTED_STRING";
321    case T_QUOTED_STRING:   return "T_QUOTED_STRING";
322    case T_BOB:             return "T_BOB";
323    case T_EOB:             return "T_EOB";
324    case T_EQUALS:          return "T_EQUALS";
325    case T_ERROR:           return "T_ERROR";
326    case T_EOF:             return "T_EOF";
327    case T_COMMA:           return "T_COMMA";
328    case T_EOL:             return "T_EOL";
329    case T_UTF8_BOM:        return "T_UTF8_BOM";
330    case T_UTF16_BOM:       return "T_UTF16_BOM";
331    default:                return "??????";
332    }
333 }
334
335 static uint32_t scan_pint(LEX *lf, char *str)
336 {
337    int64_t val = 0;
338    if (!is_a_number(str)) {
339       scan_err1(lf, _("expected a positive integer number, got: %s"), str);
340       /* NOT REACHED */
341    } else {
342       errno = 0;
343       val = str_to_int64(str);
344       if (errno != 0 || val < 0) {
345          scan_err1(lf, _("expected a positive integer number, got: %s"), str);
346          /* NOT REACHED */
347       }
348    }
349    return (uint32_t)val;
350 }
351
352 /*
353  *
354  * Get the next token from the input
355  *
356  */
357 int
358 lex_get_token(LEX *lf, int expect)
359 {
360    int ch;
361    int token = T_NONE;
362    bool esc_next = false;
363    /* Unicode files, especially on Win32, may begin with a "Byte Order Mark"
364       to indicate which transmission format the file is in. The codepoint for
365       this mark is U+FEFF and is represented as the octets EF-BB-BF in UTF-8
366       and as FF-FE in UTF-16le(little endian) and  FE-FF in UTF-16(big endian).
367       We use a distinct state for UTF-8 and UTF-16le, and use bom_bytes_seen
368       to tell which byte we are expecting. */
369    int bom_bytes_seen = 0;
370
371    Dmsg0(dbglvl, "enter lex_get_token\n");
372    while (token == T_NONE) {
373       ch = lex_get_char(lf);
374       switch (lf->state) {
375       case lex_none:
376          Dmsg2(dbglvl, "Lex state lex_none ch=%d,%x\n", ch, ch);
377          if (B_ISSPACE(ch))
378             break;
379          if (B_ISALPHA(ch)) {
380             if (lf->options & LOPT_NO_IDENT || lf->options & LOPT_STRING) {
381                lf->state = lex_string;
382             } else {
383                lf->state = lex_identifier;
384             }
385             begin_str(lf, ch);
386             break;
387          }
388          if (B_ISDIGIT(ch)) {
389             if (lf->options & LOPT_STRING) {
390                lf->state = lex_string;
391             } else {
392                lf->state = lex_number;
393             }
394             begin_str(lf, ch);
395             break;
396          }
397          Dmsg0(dbglvl, "Enter lex_none switch\n");
398          switch (ch) {
399          case L_EOF:
400             token = T_EOF;
401             Dmsg0(dbglvl, "got L_EOF set token=T_EOF\n");
402             break;
403          case '#':
404             lf->state = lex_comment;
405             break;
406          case '{':
407             token = T_BOB;
408             begin_str(lf, ch);
409             break;
410          case '}':
411             token = T_EOB;
412             begin_str(lf, ch);
413             break;
414          case '"':
415             lf->state = lex_quoted_string;
416             begin_str(lf, 0);
417             break;
418          case '=':
419             token = T_EQUALS;
420             begin_str(lf, ch);
421             break;
422          case ',':
423             token = T_COMMA;
424             begin_str(lf, ch);
425             break;
426          case ';':
427             if (expect != T_SKIP_EOL) {
428                token = T_EOL;      /* treat ; like EOL */
429             }
430             break;
431          case L_EOL:
432             Dmsg0(dbglvl, "got L_EOL set token=T_EOL\n");
433             if (expect != T_SKIP_EOL) {
434                token = T_EOL;
435             }
436             break;
437          case '@':
438             lf->state = lex_include;
439             begin_str(lf, 0);
440             break;
441          case 0xEF: /* probably a UTF-8 BOM */
442          case 0xFF: /* probably a UTF-16le BOM */
443          case 0xFE: /* probably a UTF-16be BOM (error)*/
444             if (lf->line_no != 1 || lf->col_no != 1)
445             {
446                lf->state = lex_string;
447                begin_str(lf, ch);
448             } else {
449                bom_bytes_seen = 1;
450                if (ch == 0xEF) {
451                   lf->state = lex_utf8_bom;
452                } else if (ch == 0xFF) {
453                   lf->state = lex_utf16_le_bom;
454                } else {
455                   scan_err0(lf, _("This config file appears to be in an "
456                      "unsupported Unicode format (UTF-16be). Please resave as UTF-8\n"));
457                   return T_ERROR;
458                }
459             }
460             break;
461          default:
462             lf->state = lex_string;
463             begin_str(lf, ch);
464             break;
465          }
466          break;
467       case lex_comment:
468          Dmsg1(dbglvl, "Lex state lex_comment ch=%x\n", ch);
469          if (ch == L_EOL) {
470             lf->state = lex_none;
471             if (expect != T_SKIP_EOL) {
472                token = T_EOL;
473             }
474          } else if (ch == L_EOF) {
475             token = T_ERROR;
476          }
477          break;
478       case lex_number:
479          Dmsg2(dbglvl, "Lex state lex_number ch=%x %c\n", ch, ch);
480          if (ch == L_EOF) {
481             token = T_ERROR;
482             break;
483          }
484          /* Might want to allow trailing specifications here */
485          if (B_ISDIGIT(ch)) {
486             add_str(lf, ch);
487             break;
488          }
489
490          /* A valid number can be terminated by the following */
491          if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
492             token = T_NUMBER;
493             lf->state = lex_none;
494          } else {
495             lf->state = lex_string;
496          }
497          lex_unget_char(lf);
498          break;
499       case lex_ip_addr:
500          if (ch == L_EOF) {
501             token = T_ERROR;
502             break;
503          }
504          Dmsg1(dbglvl, "Lex state lex_ip_addr ch=%x\n", ch);
505          break;
506       case lex_string:
507          Dmsg1(dbglvl, "Lex state lex_string ch=%x\n", ch);
508          if (ch == L_EOF) {
509             token = T_ERROR;
510             break;
511          }
512          if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
513              ch == '\r' || ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) {
514             lex_unget_char(lf);
515             token = T_UNQUOTED_STRING;
516             lf->state = lex_none;
517             break;
518          }
519          add_str(lf, ch);
520          break;
521       case lex_identifier:
522          Dmsg2(dbglvl, "Lex state lex_identifier ch=%x %c\n", ch, ch);
523          if (B_ISALPHA(ch)) {
524             add_str(lf, ch);
525             break;
526          } else if (B_ISSPACE(ch)) {
527             break;
528          } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
529                     ch == '\r' || ch == ';' || ch == ','   || ch == '"' || ch == '#') {
530             lex_unget_char(lf);
531             token = T_IDENTIFIER;
532             lf->state = lex_none;
533             break;
534          } else if (ch == L_EOF) {
535             token = T_ERROR;
536             lf->state = lex_none;
537             begin_str(lf, ch);
538             break;
539          }
540          /* Some non-alpha character => string */
541          lf->state = lex_string;
542          add_str(lf, ch);
543          break;
544       case lex_quoted_string:
545          Dmsg2(dbglvl, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
546          if (ch == L_EOF) {
547             token = T_ERROR;
548             break;
549          }
550          if (ch == L_EOL) {
551             esc_next = false;
552             break;
553          }
554          if (esc_next) {
555             add_str(lf, ch);
556             esc_next = false;
557             break;
558          }
559          if (ch == '\\') {
560             esc_next = true;
561             break;
562          }
563          if (ch == '"') {
564             token = T_QUOTED_STRING;
565             lf->state = lex_none;
566             break;
567          }
568          add_str(lf, ch);
569          break;
570       case lex_include:            /* scanning a filename */
571          if (ch == L_EOF) {
572             token = T_ERROR;
573             break;
574          }
575          if (B_ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' ||
576              ch == ';' || ch == ','   || ch == '"' || ch == '#') {
577             /* Keep the original LEX so we can print an error if the included file can't be opened. */
578             LEX* lfori = lf;
579
580             lf->state = lex_none;
581             lf = lex_open_file(lf, lf->str, lf->scan_error);
582             if (lf == NULL) {
583                berrno be;
584                scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
585                   lfori->str, be.bstrerror());
586                return T_ERROR;
587             }
588             break;
589          }
590          add_str(lf, ch);
591          break;
592       case lex_utf8_bom:
593          /* we only end up in this state if we have read an 0xEF 
594             as the first byte of the file, indicating we are probably
595             reading a UTF-8 file */
596          if (ch == 0xBB && bom_bytes_seen == 1) {
597             bom_bytes_seen++;
598          } else if (ch == 0xBF && bom_bytes_seen == 2) {
599             token = T_UTF8_BOM;
600             lf->state = lex_none;
601          } else {
602             token = T_ERROR;
603          }
604          break;
605       case lex_utf16_le_bom:
606          /* we only end up in this state if we have read an 0xFF 
607             as the first byte of the file -- indicating that we are
608             probably dealing with an Intel based (little endian) UTF-16 file*/
609          if (ch == 0xFE) {
610             token = T_UTF16_BOM;
611             lf->state = lex_none;
612          } else {
613             token = T_ERROR;
614          }
615          break;
616       }
617       Dmsg4(dbglvl, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state),
618         lex_tok_to_str(token), ch);
619    }
620    Dmsg2(dbglvl, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
621    lf->token = token;
622
623    /*
624     * Here is where we check to see if the user has set certain
625     *  expectations (e.g. 32 bit integer). If so, we do type checking
626     *  and possible additional scanning (e.g. for range).
627     */
628    switch (expect) {
629    case T_PINT32:
630       lf->pint32_val = scan_pint(lf, lf->str);
631       lf->pint32_val2 = lf->pint32_val;
632       token = T_PINT32;
633       break;
634
635    case T_PINT32_RANGE:
636       if (token == T_NUMBER) {
637          lf->pint32_val = scan_pint(lf, lf->str);
638          lf->pint32_val2 = lf->pint32_val;
639          token = T_PINT32;
640       } else {
641          char *p = strchr(lf->str, '-');
642          if (!p) {
643             scan_err2(lf, _("expected an integer or a range, got %s: %s"),
644                lex_tok_to_str(token), lf->str);
645             token = T_ERROR;
646             break;
647          }
648          *p++ = 0;                       /* terminate first half of range */
649          lf->pint32_val  = scan_pint(lf, lf->str);
650          lf->pint32_val2 = scan_pint(lf, p);
651          token = T_PINT32_RANGE;
652       }
653       break;
654
655    case T_INT32:
656       if (token != T_NUMBER || !is_a_number(lf->str)) {
657          scan_err2(lf, _("expected an integer number, got %s: %s"),
658                lex_tok_to_str(token), lf->str);
659          token = T_ERROR;
660          break;
661       }
662       errno = 0;
663       lf->int32_val = (int32_t)str_to_int64(lf->str);
664       if (errno != 0) {
665          scan_err2(lf, _("expected an integer number, got %s: %s"),
666                lex_tok_to_str(token), lf->str);
667          token = T_ERROR;
668       } else {
669          token = T_INT32;
670       }
671       break;
672
673    case T_INT64:
674       Dmsg2(dbglvl, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL));
675       if (token != T_NUMBER || !is_a_number(lf->str)) {
676          scan_err2(lf, _("expected an integer number, got %s: %s"),
677                lex_tok_to_str(token), lf->str);
678          token = T_ERROR;
679          break;
680       }
681       errno = 0;
682       lf->int64_val = str_to_int64(lf->str);
683       if (errno != 0) {
684          scan_err2(lf, _("expected an integer number, got %s: %s"),
685                lex_tok_to_str(token), lf->str);
686          token = T_ERROR;
687       } else {
688          token = T_INT64;
689       }
690       break;
691
692    case T_NAME:
693       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
694          scan_err2(lf, _("expected a name, got %s: %s"),
695                lex_tok_to_str(token), lf->str);
696          token = T_ERROR;
697       } else if (lf->str_len > MAX_RES_NAME_LENGTH) {
698          scan_err3(lf, _("name %s length %d too long, max is %d\n"), lf->str,
699             lf->str_len, MAX_RES_NAME_LENGTH);
700          token = T_ERROR;
701       }
702       break;
703
704    case T_STRING:
705       if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
706          scan_err2(lf, _("expected a string, got %s: %s"),
707                lex_tok_to_str(token), lf->str);
708          token = T_ERROR;
709       } else {
710          token = T_STRING;
711       }
712       break;
713
714
715    default:
716       break;                          /* no expectation given */
717    }
718    lf->token = token;                 /* set possible new token */
719    return token;
720 }