1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 * Lexical scanner for Bacula configuration file
21 *
22 * Kern Sibbald, 2000
23 *
24 */
25
26 #include "bacula.h"
27 #include "lex.h"
28
29 /* Debug level for this source file */
30 static const int dbglvl = 5000;
31
32 /*
33 * Return false if the end of the line contains anything other
34 * than spaces, or a semicolon or a comment.
35 */
lex_check_eol(LEX * lf)36 bool lex_check_eol(LEX *lf)
37 {
38 char *ch = lf->line+lf->col_no;
39 while (*ch != '\0' && *ch != '#' && B_ISSPACE(*ch) && *ch != ';') {
40 ch++;
41 }
42 return *ch == '\0' || *ch == '#' || *ch == ';';
43 }
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 */
scan_to_eol(LEX * lc)50 void scan_to_eol(LEX *lc)
51 {
52 int token;
53 Dmsg0(dbglvl, "start scan to eol\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 if (token == T_EOF) {
60 return;
61 }
62 }
63 }
64
65 /*
66 * Get next token, but skip EOL
67 */
scan_to_next_not_eol(LEX * lc)68 int scan_to_next_not_eol(LEX * lc)
69 {
70 int token;
71 do {
72 token = lex_get_token(lc, T_ALL);
73 } while (token == T_EOL);
74 return token;
75 }
76
77 /*
78 * Format a scanner error message
79 */
s_err(const char * file,int line,LEX * lc,const char * msg,...)80 static void s_err(const char *file, int line, LEX *lc, const char *msg, ...)
81 {
82 va_list arg_ptr;
83 char buf[MAXSTRING];
84 char more[MAXSTRING];
85
86 va_start(arg_ptr, msg);
87 bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
88 va_end(arg_ptr);
89
90 if (lc->err_type == 0) { /* M_ERROR_TERM by default */
91 lc->err_type = M_ERROR_TERM;
92 }
93
94 if (lc->line_no > lc->begin_line_no) {
95 bsnprintf(more, sizeof(more),
96 _("Problem probably begins at line %d.\n"), lc->begin_line_no);
97 } else {
98 more[0] = 0;
99 }
100 if (lc->line_no > 0) {
101 e_msg(file, line, lc->err_type, 0, _("Config error: %s\n"
102 " : line %d, col %d of file %s\n%s\n%s"),
103 buf, lc->line_no, lc->col_no, lc->fname, lc->line, more);
104 } else {
105 e_msg(file, line, lc->err_type, 0, _("Config error: %s\n"), buf);
106 }
107 }
108
lex_set_default_error_handler(LEX * lf)109 void lex_set_default_error_handler(LEX *lf)
110 {
111 lf->scan_error = s_err;
112 }
113
114 /*
115 * Set err_type used in error_handler
116 * return the old value
117 */
lex_set_error_handler_error_type(LEX * lf,int err_type)118 int lex_set_error_handler_error_type(LEX *lf, int err_type)
119 {
120 int old = lf->err_type;
121 lf->err_type = err_type;
122 return old;
123 }
124
125 /* Store passwords in clear text or with MD5 encoding */
lex_store_clear_passwords(LEX * lf)126 void lex_store_clear_passwords(LEX *lf)
127 {
128 lf->options |= LOPT_NO_MD5;
129 }
130
131 /*
132 * Free the current file, and retrieve the contents
133 * of the previous packet if any.
134 */
lex_close_file(LEX * lf)135 LEX *lex_close_file(LEX *lf)
136 {
137 LEX *of;
138
139 if (lf == NULL) {
140 Emsg0(M_ABORT, 0, _("Close of NULL file\n"));
141 }
142 Dmsg1(dbglvl, "Close lex file: %s\n", lf->fname);
143
144 of = lf->next;
145 if (lf->bpipe) {
146 close_bpipe(lf->bpipe);
147 lf->bpipe = NULL;
148 } else if (lf->fd) {
149 fclose(lf->fd);
150 }
151 Dmsg1(dbglvl, "Close cfg file %s\n", lf->fname);
152 if (lf->fname) {
153 free(lf->fname);
154 }
155 free_memory(lf->line);
156 lf->line = NULL;
157 free_memory(lf->str);
158 lf->str = NULL;
159 if (of) {
160 of->options = lf->options; /* preserve options */
161 memcpy(lf, of, sizeof(LEX));
162 Dmsg1(dbglvl, "Restart scan of cfg file %s\n", of->fname);
163 } else {
164 of = lf;
165 lf = NULL;
166 }
167 if (of) {
168 free(of);
169 }
170 return lf;
171 }
172
173 /*
174 * Open a configuration in memory buffer. We push the
175 * state of the current file (lf) so that we
176 * can do includes. This is a bit of a hammer.
177 * Instead of passing back the pointer to the
178 * new packet, I simply replace the contents
179 * of the caller's packet with the new packet,
180 * and link the contents of the old packet into
181 * the next field.
182 *
183 */
lex_open_buf(LEX * lf,const char * buffer,LEX_ERROR_HANDLER * scan_error)184 LEX *lex_open_buf(LEX *lf, const char *buffer, LEX_ERROR_HANDLER *scan_error)
185
186 {
187 LEX *nf;
188
189 Dmsg0(400, "Open config buffer\n");
190 nf = (LEX *)malloc(sizeof(LEX));
191 if (lf) {
192 memcpy(nf, lf, sizeof(LEX));
193 memset(lf, 0, sizeof(LEX));
194 lf->next = nf; /* if have lf, push it behind new one */
195 lf->options = nf->options; /* preserve user options */
196 /*
197 * preserve err_type to prevent bacula exiting on 'reload'
198 * if config is invalid. Fixes bug #877
199 */
200 lf->err_type = nf->err_type;
201 } else {
202 lf = nf; /* start new packet */
203 memset(lf, 0, sizeof(LEX));
204 lex_set_error_handler_error_type(lf, M_ERROR_TERM);
205 }
206 if (scan_error) {
207 lf->scan_error = scan_error;
208 } else {
209 lex_set_default_error_handler(lf);
210 }
211 lf->fd = NULL;
212 lf->bpipe = NULL;
213 lf->fname = NULL;
214 lf->line = get_memory(5000);
215 pm_strcpy(lf->line, buffer);
216 pm_strcat(lf->line, "");
217 lf->state = lex_none;
218 lf->ch = 0;
219 lf->str = get_memory(5000);
220 return lf;
221 }
222
223 /*
224 * Open a new configuration file. We push the
225 * state of the current file (lf) so that we
226 * can do includes. This is a bit of a hammer.
227 * Instead of passing back the pointer to the
228 * new packet, I simply replace the contents
229 * of the caller's packet with the new packet,
230 * and link the contents of the old packet into
231 * the next field.
232 *
233 */
lex_open_file(LEX * lf,const char * filename,LEX_ERROR_HANDLER * scan_error)234 LEX *lex_open_file(LEX *lf, const char *filename, LEX_ERROR_HANDLER *scan_error)
235
236 {
237 LEX *nf;
238 FILE *fd;
239 BPIPE *bpipe = NULL;
240 char *fname = bstrdup(filename);
241
242 if (fname[0] == '|') {
243 if ((bpipe = open_bpipe(fname+1, 0, "reb")) == NULL) {
244 free(fname);
245 return NULL;
246 }
247 close_epipe(bpipe); /* discard stderr messages */
248 fd = bpipe->rfd;
249 } else if ((fd = fopen(fname, "rb")) == NULL) {
250 free(fname);
251 return NULL;
252 }
253 Dmsg1(400, "Open config file: %s\n", fname);
254 nf = (LEX *)malloc(sizeof(LEX));
255 if (lf) {
256 memcpy(nf, lf, sizeof(LEX));
257 memset(lf, 0, sizeof(LEX));
258 lf->next = nf; /* if have lf, push it behind new one */
259 lf->options = nf->options; /* preserve user options */
260 /*
261 * preserve err_type to prevent bacula exiting on 'reload'
262 * if config is invalid. Fixes bug #877
263 */
264 lf->err_type = nf->err_type;
265 } else {
266 lf = nf; /* start new packet */
267 memset(lf, 0, sizeof(LEX));
268 lex_set_error_handler_error_type(lf, M_ERROR_TERM);
269 }
270 if (scan_error) {
271 lf->scan_error = scan_error;
272 } else {
273 lex_set_default_error_handler(lf);
274 }
275 lf->fd = fd;
276 lf->bpipe = bpipe;
277 lf->fname = fname;
278 lf->line = get_memory(5000);
279 lf->state = lex_none;
280 lf->ch = L_EOL;
281 lf->str = get_memory(5000);
282 Dmsg1(dbglvl, "Return lex=%x\n", lf);
283 return lf;
284 }
285
286 /*
287 * Get the next character from the input.
288 * Returns the character or
289 * L_EOF if end of file
290 * L_EOL if end of line
291 */
lex_get_char(LEX * lf)292 int lex_get_char(LEX *lf)
293 {
294 if (lf->ch == L_EOF) {
295 Emsg0(M_ABORT, 0, _("get_char: called after EOF."
296 " You may have a open double quote without the closing double quote.\n"));
297 }
298 if (lf->fd && lf->ch == L_EOL) {
299 if (bfgets(lf->line, lf->fd) == NULL) {
300 lf->ch = L_EOF;
301 if (lf->next) {
302 lex_close_file(lf);
303 }
304 return lf->ch;
305 }
306 lf->line_no++;
307 lf->col_no = 0;
308 Dmsg2(1000, "fget line=%d %s", lf->line_no, lf->line);
309 } else if (lf->ch == L_EOL) {
310 lf->line_no++;
311 lf->col_no++;
312 }
313 lf->ch = (uint8_t)lf->line[lf->col_no];
314 if (lf->fd) {
315 if (lf->ch == 0) {
316 lf->ch = L_EOL; /* reached end of line, force bfgets */
317 } else {
318 lf->col_no++;
319 }
320 } else {
321 if (lf->ch == 0) { /* End of buffer, stop scan */
322 lf->ch = L_EOF;
323 if (lf->next) {
324 lex_close_file(lf);
325 }
326 return lf->ch;
327 } else if (lf->ch == '\n') { /* End of line */
328 Dmsg0(dbglvl, "Found newline return L_EOL\n");
329 lf->ch = L_EOL;
330 } else {
331 lf->col_no++;
332 }
333 }
334 Dmsg3(dbglvl, "lex_get_char: %c %d col=%d\n", lf->ch, lf->ch, lf->col_no);
335 return lf->ch;
336 }
337
lex_unget_char(LEX * lf)338 void lex_unget_char(LEX *lf)
339 {
340 if (lf->ch == L_EOL) {
341 lf->ch = 0; /* End of line, force read of next one */
342 } else {
343 lf->col_no--; /* Backup to re-read char */
344 }
345 }
346
347
348 /*
349 * Add a character to the current string
350 */
add_str(LEX * lf,int ch)351 static void add_str(LEX *lf, int ch)
352 {
353 if (lf->str_len >= sizeof_pool_memory(lf->str)) {
354 Emsg3(M_ERROR_TERM, 0, _(
355 _("Config token too long, file: %s, line %d, begins at line %d\n")),
356 lf->fname, lf->line_no, lf->begin_line_no);
357 }
358 lf->str[lf->str_len++] = ch;
359 lf->str[lf->str_len] = 0;
360 }
361
362 /*
363 * Begin the string
364 */
begin_str(LEX * lf,int ch)365 static void begin_str(LEX *lf, int ch)
366 {
367 lf->str_len = 0;
368 lf->str[0] = 0;
369 if (ch != 0) {
370 add_str(lf, ch);
371 }
372 lf->begin_line_no = lf->line_no; /* save start string line no */
373 }
374
375 #ifdef DEBUG
lex_state_to_str(int state)376 static const char *lex_state_to_str(int state)
377 {
378 switch (state) {
379 case lex_none: return _("none");
380 case lex_comment: return _("comment");
381 case lex_number: return _("number");
382 case lex_ip_addr: return _("ip_addr");
383 case lex_identifier: return _("identifier");
384 case lex_string: return _("string");
385 case lex_quoted_string: return _("quoted_string");
386 case lex_include: return _("include");
387 case lex_include_quoted_string: return _("include_quoted_string");
388 case lex_utf8_bom: return _("UTF-8 Byte Order Mark");
389 case lex_utf16_le_bom: return _("UTF-16le Byte Order Mark");
390 default: return "??????";
391 }
392 }
393 #endif
394
395 /*
396 * Convert a lex token to a string
397 * used for debug/error printing.
398 */
lex_tok_to_str(int token)399 const char *lex_tok_to_str(int token)
400 {
401 switch(token) {
402 case L_EOF: return "L_EOF";
403 case L_EOL: return "L_EOL";
404 case T_NONE: return "T_NONE";
405 case T_NUMBER: return "T_NUMBER";
406 case T_IPADDR: return "T_IPADDR";
407 case T_IDENTIFIER: return "T_IDENTIFIER";
408 case T_UNQUOTED_STRING: return "T_UNQUOTED_STRING";
409 case T_QUOTED_STRING: return "T_QUOTED_STRING";
410 case T_BOB: return "T_BOB";
411 case T_EOB: return "T_EOB";
412 case T_EQUALS: return "T_EQUALS";
413 case T_ERROR: return "T_ERROR";
414 case T_EOF: return "T_EOF";
415 case T_COMMA: return "T_COMMA";
416 case T_EOL: return "T_EOL";
417 case T_UTF8_BOM: return "T_UTF8_BOM";
418 case T_UTF16_BOM: return "T_UTF16_BOM";
419 default: return "??????";
420 }
421 }
422
scan_pint(LEX * lf,char * str)423 static uint32_t scan_pint(LEX *lf, char *str)
424 {
425 int64_t val = 0;
426 if (!is_a_number(str)) {
427 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
428 /* NOT REACHED */
429 } else {
430 errno = 0;
431 val = str_to_int64(str);
432 if (errno != 0 || val < 0) {
433 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
434 /* NOT REACHED */
435 }
436 }
437 return (uint32_t)val;
438 }
439
scan_pint64(LEX * lf,char * str)440 static uint64_t scan_pint64(LEX *lf, char *str)
441 {
442 uint64_t val = 0;
443 if (!is_a_number(str)) {
444 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
445 /* NOT REACHED */
446 } else {
447 errno = 0;
448 val = str_to_uint64(str);
449 if (errno != 0) {
450 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
451 /* NOT REACHED */
452 }
453 }
454 return val;
455 }
456
457 /*
458 *
459 * Get the next token from the input
460 *
461 */
462 int
lex_get_token(LEX * lf,int expect)463 lex_get_token(LEX *lf, int expect)
464 {
465 int ch, nch;
466 int token = T_NONE;
467 bool esc_next = false;
468 /* Unicode files, especially on Win32, may begin with a "Byte Order Mark"
469 to indicate which transmission format the file is in. The codepoint for
470 this mark is U+FEFF and is represented as the octets EF-BB-BF in UTF-8
471 and as FF-FE in UTF-16le(little endian) and FE-FF in UTF-16(big endian).
472 We use a distinct state for UTF-8 and UTF-16le, and use bom_bytes_seen
473 to tell which byte we are expecting. */
474 int bom_bytes_seen = 0;
475
476 Dmsg1(dbglvl, "enter lex_get_token state=%s\n", lex_state_to_str(lf->state));
477 while (token == T_NONE) {
478 ch = lex_get_char(lf);
479 switch (lf->state) {
480 case lex_none:
481 Dmsg2(dbglvl, "Lex state lex_none ch=%c,%d\n", ch, ch);
482 if (B_ISSPACE(ch))
483 break;
484 if (B_ISALPHA(ch)) {
485 if (lf->options & LOPT_NO_IDENT || lf->options & LOPT_STRING) {
486 lf->state = lex_string;
487 } else {
488 lf->state = lex_identifier;
489 }
490 begin_str(lf, ch);
491 break;
492 }
493 if (B_ISDIGIT(ch)) {
494 if (lf->options & LOPT_STRING) {
495 lf->state = lex_string;
496 } else {
497 lf->state = lex_number;
498 }
499 begin_str(lf, ch);
500 break;
501 }
502 Dmsg0(dbglvl, "Enter lex_none switch\n");
503 switch (ch) {
504 case L_EOF:
505 token = T_EOF;
506 Dmsg0(dbglvl, "got L_EOF set token=T_EOF\n");
507 break;
508 case '\\':
509 nch = lex_get_char(lf);
510 if (nch == ' ' || nch == '\n' || nch == '\r' || nch == L_EOL) {
511 lf->ch = L_EOL; /* force end of line */
512 }
513 break;
514 case '#':
515 lf->state = lex_comment;
516 break;
517 case '{':
518 token = T_BOB;
519 begin_str(lf, ch);
520 break;
521 case '}':
522 token = T_EOB;
523 begin_str(lf, ch);
524 break;
525 case '"':
526 lf->state = lex_quoted_string;
527 begin_str(lf, 0);
528 break;
529 case '=':
530 token = T_EQUALS;
531 begin_str(lf, ch);
532 break;
533 case ',':
534 token = T_COMMA;
535 begin_str(lf, ch);
536 break;
537 case ';':
538 if (expect != T_SKIP_EOL) {
539 token = T_EOL; /* treat ; like EOL */
540 }
541 break;
542 case L_EOL:
543 Dmsg0(dbglvl, "got L_EOL set token=T_EOL\n");
544 if (expect != T_SKIP_EOL) {
545 token = T_EOL;
546 }
547 break;
548 case '@':
549 /* In NO_EXTERN mode, @ is part of a string */
550 if (lf->options & LOPT_NO_EXTERN) {
551 lf->state = lex_string;
552 begin_str(lf, ch);
553 } else {
554 lf->state = lex_include;
555 begin_str(lf, 0);
556 }
557 break;
558 case 0xEF: /* probably a UTF-8 BOM */
559 case 0xFF: /* probably a UTF-16le BOM */
560 case 0xFE: /* probably a UTF-16be BOM (error)*/
561 if (lf->line_no != 1 || lf->col_no != 1)
562 {
563 lf->state = lex_string;
564 begin_str(lf, ch);
565 } else {
566 bom_bytes_seen = 1;
567 if (ch == 0xEF) {
568 lf->state = lex_utf8_bom;
569 } else if (ch == 0xFF) {
570 lf->state = lex_utf16_le_bom;
571 } else {
572 scan_err0(lf, _("This config file appears to be in an "
573 "unsupported Unicode format (UTF-16be). Please resave as UTF-8\n"));
574 return T_ERROR;
575 }
576 }
577 break;
578 default:
579 lf->state = lex_string;
580 begin_str(lf, ch);
581 break;
582 }
583 break;
584 case lex_comment:
585 Dmsg1(dbglvl, "Lex state lex_comment ch=%x\n", ch);
586 if (ch == L_EOL) {
587 lf->state = lex_none;
588 if (expect != T_SKIP_EOL) {
589 token = T_EOL;
590 }
591 } else if (ch == L_EOF) {
592 token = T_ERROR;
593 }
594 break;
595 case lex_number:
596 Dmsg2(dbglvl, "Lex state lex_number ch=%x %c\n", ch, ch);
597 if (ch == L_EOF) {
598 token = T_ERROR;
599 break;
600 }
601 /* Might want to allow trailing specifications here */
602 if (B_ISDIGIT(ch)) {
603 add_str(lf, ch);
604 break;
605 }
606
607 /* A valid number can be terminated by the following */
608 if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
609 token = T_NUMBER;
610 lf->state = lex_none;
611 } else {
612 lf->state = lex_string;
613 }
614 lex_unget_char(lf);
615 break;
616 case lex_ip_addr:
617 if (ch == L_EOF) {
618 token = T_ERROR;
619 break;
620 }
621 Dmsg1(dbglvl, "Lex state lex_ip_addr ch=%x\n", ch);
622 break;
623 case lex_string:
624 Dmsg1(dbglvl, "Lex state lex_string ch=%x\n", ch);
625 if (ch == L_EOF) {
626 token = T_ERROR;
627 break;
628 }
629 if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
630 ch == '\r' || ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) {
631 lex_unget_char(lf);
632 token = T_UNQUOTED_STRING;
633 lf->state = lex_none;
634 break;
635 }
636 add_str(lf, ch);
637 break;
638 case lex_identifier:
639 Dmsg2(dbglvl, "Lex state lex_identifier ch=%x %c\n", ch, ch);
640 if (B_ISALPHA(ch)) {
641 add_str(lf, ch);
642 break;
643 } else if (B_ISSPACE(ch)) {
644 break;
645 } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
646 ch == '\r' || ch == ';' || ch == ',' || ch == '"' || ch == '#') {
647 lex_unget_char(lf);
648 token = T_IDENTIFIER;
649 lf->state = lex_none;
650 break;
651 } else if (ch == L_EOF) {
652 token = T_ERROR;
653 lf->state = lex_none;
654 begin_str(lf, ch);
655 break;
656 }
657 /* Some non-alpha character => string */
658 lf->state = lex_string;
659 add_str(lf, ch);
660 break;
661 case lex_quoted_string:
662 Dmsg2(dbglvl, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
663 if (ch == L_EOF) {
664 token = T_ERROR;
665 break;
666 }
667 if (ch == L_EOL) {
668 esc_next = false;
669 break;
670 }
671 if (esc_next) {
672 add_str(lf, ch);
673 esc_next = false;
674 break;
675 }
676 if (ch == '\\') {
677 esc_next = true;
678 break;
679 }
680 if (ch == '"') {
681 token = T_QUOTED_STRING;
682 /*
683 * Since we may be scanning a quoted list of names,
684 * we get the next character (a comma indicates another
685 * one), then we put it back for rescanning.
686 */
687 lex_get_char(lf);
688 lex_unget_char(lf);
689 lf->state = lex_none;
690 break;
691 }
692 add_str(lf, ch);
693 break;
694 case lex_include_quoted_string:
695 if (ch == L_EOF) {
696 token = T_ERROR;
697 break;
698 }
699 if (esc_next) {
700 add_str(lf, ch);
701 esc_next = false;
702 break;
703 }
704 if (ch == '\\') {
705 esc_next = true;
706 break;
707 }
708 if (ch == '"') {
709 /* Keep the original LEX so we can print an error if the included file can't be opened. */
710 LEX* lfori = lf;
711 /* Skip the double quote when restarting parsing */
712 lex_get_char(lf);
713
714 lf->state = lex_none;
715 lf = lex_open_file(lf, lf->str, lf->scan_error);
716 if (lf == NULL) {
717 berrno be;
718 scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
719 lfori->str, be.bstrerror());
720 return T_ERROR;
721 }
722 break;
723 }
724 add_str(lf, ch);
725 break;
726 case lex_include: /* scanning a filename */
727 if (ch == L_EOF) {
728 token = T_ERROR;
729 break;
730 }
731 if (ch == '"') {
732 lf->state = lex_include_quoted_string;
733 break;
734 }
735
736
737 if (B_ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' ||
738 ch == ';' || ch == ',' || ch == '"' || ch == '#') {
739 /* Keep the original LEX so we can print an error if the included file can't be opened. */
740 LEX* lfori = lf;
741
742 lf->state = lex_none;
743 lf = lex_open_file(lf, lf->str, lf->scan_error);
744 if (lf == NULL) {
745 berrno be;
746 scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
747 lfori->str, be.bstrerror());
748 return T_ERROR;
749 }
750 break;
751 }
752 add_str(lf, ch);
753 break;
754 case lex_utf8_bom:
755 /* we only end up in this state if we have read an 0xEF
756 as the first byte of the file, indicating we are probably
757 reading a UTF-8 file */
758 if (ch == 0xBB && bom_bytes_seen == 1) {
759 bom_bytes_seen++;
760 } else if (ch == 0xBF && bom_bytes_seen == 2) {
761 token = T_UTF8_BOM;
762 lf->state = lex_none;
763 } else {
764 token = T_ERROR;
765 }
766 break;
767 case lex_utf16_le_bom:
768 /* we only end up in this state if we have read an 0xFF
769 as the first byte of the file -- indicating that we are
770 probably dealing with an Intel based (little endian) UTF-16 file*/
771 if (ch == 0xFE) {
772 token = T_UTF16_BOM;
773 lf->state = lex_none;
774 } else {
775 token = T_ERROR;
776 }
777 break;
778 }
779 Dmsg4(dbglvl, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state),
780 lex_tok_to_str(token), ch);
781 }
782 Dmsg2(dbglvl, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
783 lf->token = token;
784
785 /*
786 * Here is where we check to see if the user has set certain
787 * expectations (e.g. 32 bit integer). If so, we do type checking
788 * and possible additional scanning (e.g. for range).
789 */
790 switch (expect) {
791 case T_PINT32:
792 lf->pint32_val = scan_pint(lf, lf->str);
793 lf->pint32_val2 = lf->pint32_val;
794 token = T_PINT32;
795 break;
796
797 case T_PINT32_RANGE:
798 if (token == T_NUMBER) {
799 lf->pint32_val = scan_pint(lf, lf->str);
800 lf->pint32_val2 = lf->pint32_val;
801 token = T_PINT32;
802 } else {
803 char *p = strchr(lf->str, '-');
804 if (!p) {
805 scan_err2(lf, _("expected an integer or a range, got %s: %s"),
806 lex_tok_to_str(token), lf->str);
807 token = T_ERROR;
808 break;
809 }
810 *p++ = 0; /* terminate first half of range */
811 lf->pint32_val = scan_pint(lf, lf->str);
812 lf->pint32_val2 = scan_pint(lf, p);
813 token = T_PINT32_RANGE;
814 }
815 break;
816
817 case T_INT32:
818 if (token != T_NUMBER || !is_a_number(lf->str)) {
819 scan_err2(lf, _("expected an integer number, got %s: %s"),
820 lex_tok_to_str(token), lf->str);
821 token = T_ERROR;
822 break;
823 }
824 errno = 0;
825 lf->int32_val = (int32_t)str_to_int64(lf->str);
826 if (errno != 0) {
827 scan_err2(lf, _("expected an integer number, got %s: %s"),
828 lex_tok_to_str(token), lf->str);
829 token = T_ERROR;
830 } else {
831 token = T_INT32;
832 }
833 break;
834
835 case T_INT64:
836 Dmsg2(dbglvl, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL));
837 if (token != T_NUMBER || !is_a_number(lf->str)) {
838 scan_err2(lf, _("expected an integer number, got %s: %s"),
839 lex_tok_to_str(token), lf->str);
840 token = T_ERROR;
841 break;
842 }
843 errno = 0;
844 lf->int64_val = str_to_int64(lf->str);
845 if (errno != 0) {
846 scan_err2(lf, _("expected an integer number, got %s: %s"),
847 lex_tok_to_str(token), lf->str);
848 token = T_ERROR;
849 } else {
850 token = T_INT64;
851 }
852 break;
853
854 case T_PINT64_RANGE:
855 if (token == T_NUMBER) {
856 lf->pint64_val = scan_pint64(lf, lf->str);
857 lf->pint64_val2 = lf->pint64_val;
858 token = T_PINT64;
859 } else {
860 char *p = strchr(lf->str, '-');
861 if (!p) {
862 scan_err2(lf, _("expected an integer or a range, got %s: %s"),
863 lex_tok_to_str(token), lf->str);
864 token = T_ERROR;
865 break;
866 }
867 *p++ = 0; /* terminate first half of range */
868 lf->pint64_val = scan_pint64(lf, lf->str);
869 lf->pint64_val2 = scan_pint64(lf, p);
870 token = T_PINT64_RANGE;
871 }
872 break;
873
874 case T_NAME:
875 if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
876 scan_err2(lf, _("expected a name, got %s: %s"),
877 lex_tok_to_str(token), lf->str);
878 token = T_ERROR;
879 } else if (lf->str_len > MAX_RES_NAME_LENGTH) {
880 scan_err3(lf, _("name %s length %d too long, max is %d\n"), lf->str,
881 lf->str_len, MAX_RES_NAME_LENGTH);
882 token = T_ERROR;
883 }
884 break;
885
886 case T_STRING:
887 if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
888 scan_err2(lf, _("expected a string, got %s: %s"),
889 lex_tok_to_str(token), lf->str);
890 token = T_ERROR;
891 } else {
892 token = T_STRING;
893 }
894 break;
895
896
897 default:
898 break; /* no expectation given */
899 }
900 lf->token = token; /* set possible new token */
901 return token;
902 }
903