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, "rb")) == NULL) {
244 free(fname);
245 return NULL;
246 }
247 fd = bpipe->rfd;
248 } else if ((fd = fopen(fname, "rb")) == NULL) {
249 free(fname);
250 return NULL;
251 }
252 Dmsg1(400, "Open config file: %s\n", fname);
253 nf = (LEX *)malloc(sizeof(LEX));
254 if (lf) {
255 memcpy(nf, lf, sizeof(LEX));
256 memset(lf, 0, sizeof(LEX));
257 lf->next = nf; /* if have lf, push it behind new one */
258 lf->options = nf->options; /* preserve user options */
259 /*
260 * preserve err_type to prevent bacula exiting on 'reload'
261 * if config is invalid. Fixes bug #877
262 */
263 lf->err_type = nf->err_type;
264 } else {
265 lf = nf; /* start new packet */
266 memset(lf, 0, sizeof(LEX));
267 lex_set_error_handler_error_type(lf, M_ERROR_TERM);
268 }
269 if (scan_error) {
270 lf->scan_error = scan_error;
271 } else {
272 lex_set_default_error_handler(lf);
273 }
274 lf->fd = fd;
275 lf->bpipe = bpipe;
276 lf->fname = fname;
277 lf->line = get_memory(5000);
278 lf->state = lex_none;
279 lf->ch = L_EOL;
280 lf->str = get_memory(5000);
281 Dmsg1(dbglvl, "Return lex=%x\n", lf);
282 return lf;
283 }
284
285 /*
286 * Get the next character from the input.
287 * Returns the character or
288 * L_EOF if end of file
289 * L_EOL if end of line
290 */
lex_get_char(LEX * lf)291 int lex_get_char(LEX *lf)
292 {
293 if (lf->ch == L_EOF) {
294 Emsg0(M_ABORT, 0, _("get_char: called after EOF."
295 " You may have a open double quote without the closing double quote.\n"));
296 }
297 if (lf->fd && lf->ch == L_EOL) {
298 if (bfgets(lf->line, lf->fd) == NULL) {
299 lf->ch = L_EOF;
300 if (lf->next) {
301 lex_close_file(lf);
302 }
303 return lf->ch;
304 }
305 lf->line_no++;
306 lf->col_no = 0;
307 Dmsg2(1000, "fget line=%d %s", lf->line_no, lf->line);
308 } else if (lf->ch == L_EOL) {
309 lf->line_no++;
310 lf->col_no++;
311 }
312 lf->ch = (uint8_t)lf->line[lf->col_no];
313 if (lf->fd) {
314 if (lf->ch == 0) {
315 lf->ch = L_EOL; /* reached end of line, force bfgets */
316 } else {
317 lf->col_no++;
318 }
319 } else {
320 if (lf->ch == 0) { /* End of buffer, stop scan */
321 lf->ch = L_EOF;
322 if (lf->next) {
323 lex_close_file(lf);
324 }
325 return lf->ch;
326 } else if (lf->ch == '\n') { /* End of line */
327 Dmsg0(dbglvl, "Found newline return L_EOL\n");
328 lf->ch = L_EOL;
329 } else {
330 lf->col_no++;
331 }
332 }
333 Dmsg3(dbglvl, "lex_get_char: %c %d col=%d\n", lf->ch, lf->ch, lf->col_no);
334 return lf->ch;
335 }
336
lex_unget_char(LEX * lf)337 void lex_unget_char(LEX *lf)
338 {
339 if (lf->ch == L_EOL) {
340 lf->ch = 0; /* End of line, force read of next one */
341 } else {
342 lf->col_no--; /* Backup to re-read char */
343 }
344 }
345
346
347 /*
348 * Add a character to the current string
349 */
add_str(LEX * lf,int ch)350 static void add_str(LEX *lf, int ch)
351 {
352 if (lf->str_len >= sizeof_pool_memory(lf->str)) {
353 Emsg3(M_ERROR_TERM, 0, _(
354 _("Config token too long, file: %s, line %d, begins at line %d\n")),
355 lf->fname, lf->line_no, lf->begin_line_no);
356 }
357 lf->str[lf->str_len++] = ch;
358 lf->str[lf->str_len] = 0;
359 }
360
361 /*
362 * Begin the string
363 */
begin_str(LEX * lf,int ch)364 static void begin_str(LEX *lf, int ch)
365 {
366 lf->str_len = 0;
367 lf->str[0] = 0;
368 if (ch != 0) {
369 add_str(lf, ch);
370 }
371 lf->begin_line_no = lf->line_no; /* save start string line no */
372 }
373
374 #ifdef DEBUG
lex_state_to_str(int state)375 static const char *lex_state_to_str(int state)
376 {
377 switch (state) {
378 case lex_none: return _("none");
379 case lex_comment: return _("comment");
380 case lex_number: return _("number");
381 case lex_ip_addr: return _("ip_addr");
382 case lex_identifier: return _("identifier");
383 case lex_string: return _("string");
384 case lex_quoted_string: return _("quoted_string");
385 case lex_include: return _("include");
386 case lex_include_quoted_string: return _("include_quoted_string");
387 case lex_utf8_bom: return _("UTF-8 Byte Order Mark");
388 case lex_utf16_le_bom: return _("UTF-16le Byte Order Mark");
389 default: return "??????";
390 }
391 }
392 #endif
393
394 /*
395 * Convert a lex token to a string
396 * used for debug/error printing.
397 */
lex_tok_to_str(int token)398 const char *lex_tok_to_str(int token)
399 {
400 switch(token) {
401 case L_EOF: return "L_EOF";
402 case L_EOL: return "L_EOL";
403 case T_NONE: return "T_NONE";
404 case T_NUMBER: return "T_NUMBER";
405 case T_IPADDR: return "T_IPADDR";
406 case T_IDENTIFIER: return "T_IDENTIFIER";
407 case T_UNQUOTED_STRING: return "T_UNQUOTED_STRING";
408 case T_QUOTED_STRING: return "T_QUOTED_STRING";
409 case T_BOB: return "T_BOB";
410 case T_EOB: return "T_EOB";
411 case T_EQUALS: return "T_EQUALS";
412 case T_ERROR: return "T_ERROR";
413 case T_EOF: return "T_EOF";
414 case T_COMMA: return "T_COMMA";
415 case T_EOL: return "T_EOL";
416 case T_UTF8_BOM: return "T_UTF8_BOM";
417 case T_UTF16_BOM: return "T_UTF16_BOM";
418 default: return "??????";
419 }
420 }
421
scan_pint(LEX * lf,char * str)422 static uint32_t scan_pint(LEX *lf, char *str)
423 {
424 int64_t val = 0;
425 if (!is_a_number(str)) {
426 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
427 /* NOT REACHED */
428 } else {
429 errno = 0;
430 val = str_to_int64(str);
431 if (errno != 0 || val < 0) {
432 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
433 /* NOT REACHED */
434 }
435 }
436 return (uint32_t)val;
437 }
438
scan_pint64(LEX * lf,char * str)439 static uint64_t scan_pint64(LEX *lf, char *str)
440 {
441 uint64_t val = 0;
442 if (!is_a_number(str)) {
443 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
444 /* NOT REACHED */
445 } else {
446 errno = 0;
447 val = str_to_uint64(str);
448 if (errno != 0) {
449 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
450 /* NOT REACHED */
451 }
452 }
453 return val;
454 }
455
456 /*
457 *
458 * Get the next token from the input
459 *
460 */
461 int
lex_get_token(LEX * lf,int expect)462 lex_get_token(LEX *lf, int expect)
463 {
464 int ch, nch;
465 int token = T_NONE;
466 bool esc_next = false;
467 /* Unicode files, especially on Win32, may begin with a "Byte Order Mark"
468 to indicate which transmission format the file is in. The codepoint for
469 this mark is U+FEFF and is represented as the octets EF-BB-BF in UTF-8
470 and as FF-FE in UTF-16le(little endian) and FE-FF in UTF-16(big endian).
471 We use a distinct state for UTF-8 and UTF-16le, and use bom_bytes_seen
472 to tell which byte we are expecting. */
473 int bom_bytes_seen = 0;
474
475 Dmsg1(dbglvl, "enter lex_get_token state=%s\n", lex_state_to_str(lf->state));
476 while (token == T_NONE) {
477 ch = lex_get_char(lf);
478 switch (lf->state) {
479 case lex_none:
480 Dmsg2(dbglvl, "Lex state lex_none ch=%c,%d\n", ch, ch);
481 if (B_ISSPACE(ch))
482 break;
483 if (B_ISALPHA(ch)) {
484 if (lf->options & LOPT_NO_IDENT || lf->options & LOPT_STRING) {
485 lf->state = lex_string;
486 } else {
487 lf->state = lex_identifier;
488 }
489 begin_str(lf, ch);
490 break;
491 }
492 if (B_ISDIGIT(ch)) {
493 if (lf->options & LOPT_STRING) {
494 lf->state = lex_string;
495 } else {
496 lf->state = lex_number;
497 }
498 begin_str(lf, ch);
499 break;
500 }
501 Dmsg0(dbglvl, "Enter lex_none switch\n");
502 switch (ch) {
503 case L_EOF:
504 token = T_EOF;
505 Dmsg0(dbglvl, "got L_EOF set token=T_EOF\n");
506 break;
507 case '\\':
508 nch = lex_get_char(lf);
509 if (nch == ' ' || nch == '\n' || nch == '\r' || nch == L_EOL) {
510 lf->ch = L_EOL; /* force end of line */
511 }
512 break;
513 case '#':
514 lf->state = lex_comment;
515 break;
516 case '{':
517 token = T_BOB;
518 begin_str(lf, ch);
519 break;
520 case '}':
521 token = T_EOB;
522 begin_str(lf, ch);
523 break;
524 case '"':
525 lf->state = lex_quoted_string;
526 begin_str(lf, 0);
527 break;
528 case '=':
529 token = T_EQUALS;
530 begin_str(lf, ch);
531 break;
532 case ',':
533 token = T_COMMA;
534 begin_str(lf, ch);
535 break;
536 case ';':
537 if (expect != T_SKIP_EOL) {
538 token = T_EOL; /* treat ; like EOL */
539 }
540 break;
541 case L_EOL:
542 Dmsg0(dbglvl, "got L_EOL set token=T_EOL\n");
543 if (expect != T_SKIP_EOL) {
544 token = T_EOL;
545 }
546 break;
547 case '@':
548 /* In NO_EXTERN mode, @ is part of a string */
549 if (lf->options & LOPT_NO_EXTERN) {
550 lf->state = lex_string;
551 begin_str(lf, ch);
552 } else {
553 lf->state = lex_include;
554 begin_str(lf, 0);
555 }
556 break;
557 case 0xEF: /* probably a UTF-8 BOM */
558 case 0xFF: /* probably a UTF-16le BOM */
559 case 0xFE: /* probably a UTF-16be BOM (error)*/
560 if (lf->line_no != 1 || lf->col_no != 1)
561 {
562 lf->state = lex_string;
563 begin_str(lf, ch);
564 } else {
565 bom_bytes_seen = 1;
566 if (ch == 0xEF) {
567 lf->state = lex_utf8_bom;
568 } else if (ch == 0xFF) {
569 lf->state = lex_utf16_le_bom;
570 } else {
571 scan_err0(lf, _("This config file appears to be in an "
572 "unsupported Unicode format (UTF-16be). Please resave as UTF-8\n"));
573 return T_ERROR;
574 }
575 }
576 break;
577 default:
578 lf->state = lex_string;
579 begin_str(lf, ch);
580 break;
581 }
582 break;
583 case lex_comment:
584 Dmsg1(dbglvl, "Lex state lex_comment ch=%x\n", ch);
585 if (ch == L_EOL) {
586 lf->state = lex_none;
587 if (expect != T_SKIP_EOL) {
588 token = T_EOL;
589 }
590 } else if (ch == L_EOF) {
591 token = T_ERROR;
592 }
593 break;
594 case lex_number:
595 Dmsg2(dbglvl, "Lex state lex_number ch=%x %c\n", ch, ch);
596 if (ch == L_EOF) {
597 token = T_ERROR;
598 break;
599 }
600 /* Might want to allow trailing specifications here */
601 if (B_ISDIGIT(ch)) {
602 add_str(lf, ch);
603 break;
604 }
605
606 /* A valid number can be terminated by the following */
607 if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
608 token = T_NUMBER;
609 lf->state = lex_none;
610 } else {
611 lf->state = lex_string;
612 }
613 lex_unget_char(lf);
614 break;
615 case lex_ip_addr:
616 if (ch == L_EOF) {
617 token = T_ERROR;
618 break;
619 }
620 Dmsg1(dbglvl, "Lex state lex_ip_addr ch=%x\n", ch);
621 break;
622 case lex_string:
623 Dmsg1(dbglvl, "Lex state lex_string ch=%x\n", ch);
624 if (ch == L_EOF) {
625 token = T_ERROR;
626 break;
627 }
628 if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
629 ch == '\r' || ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) {
630 lex_unget_char(lf);
631 token = T_UNQUOTED_STRING;
632 lf->state = lex_none;
633 break;
634 }
635 add_str(lf, ch);
636 break;
637 case lex_identifier:
638 Dmsg2(dbglvl, "Lex state lex_identifier ch=%x %c\n", ch, ch);
639 if (B_ISALPHA(ch)) {
640 add_str(lf, ch);
641 break;
642 } else if (B_ISSPACE(ch)) {
643 break;
644 } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' ||
645 ch == '\r' || ch == ';' || ch == ',' || ch == '"' || ch == '#') {
646 lex_unget_char(lf);
647 token = T_IDENTIFIER;
648 lf->state = lex_none;
649 break;
650 } else if (ch == L_EOF) {
651 token = T_ERROR;
652 lf->state = lex_none;
653 begin_str(lf, ch);
654 break;
655 }
656 /* Some non-alpha character => string */
657 lf->state = lex_string;
658 add_str(lf, ch);
659 break;
660 case lex_quoted_string:
661 Dmsg2(dbglvl, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
662 if (ch == L_EOF) {
663 token = T_ERROR;
664 break;
665 }
666 if (ch == L_EOL) {
667 esc_next = false;
668 break;
669 }
670 if (esc_next) {
671 add_str(lf, ch);
672 esc_next = false;
673 break;
674 }
675 if (ch == '\\') {
676 esc_next = true;
677 break;
678 }
679 if (ch == '"') {
680 token = T_QUOTED_STRING;
681 /*
682 * Since we may be scanning a quoted list of names,
683 * we get the next character (a comma indicates another
684 * one), then we put it back for rescanning.
685 */
686 lex_get_char(lf);
687 lex_unget_char(lf);
688 lf->state = lex_none;
689 break;
690 }
691 add_str(lf, ch);
692 break;
693 case lex_include_quoted_string:
694 if (ch == L_EOF) {
695 token = T_ERROR;
696 break;
697 }
698 if (esc_next) {
699 add_str(lf, ch);
700 esc_next = false;
701 break;
702 }
703 if (ch == '\\') {
704 esc_next = true;
705 break;
706 }
707 if (ch == '"') {
708 /* Keep the original LEX so we can print an error if the included file can't be opened. */
709 LEX* lfori = lf;
710 /* Skip the double quote when restarting parsing */
711 lex_get_char(lf);
712
713 lf->state = lex_none;
714 lf = lex_open_file(lf, lf->str, lf->scan_error);
715 if (lf == NULL) {
716 berrno be;
717 scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
718 lfori->str, be.bstrerror());
719 return T_ERROR;
720 }
721 break;
722 }
723 add_str(lf, ch);
724 break;
725 case lex_include: /* scanning a filename */
726 if (ch == L_EOF) {
727 token = T_ERROR;
728 break;
729 }
730 if (ch == '"') {
731 lf->state = lex_include_quoted_string;
732 break;
733 }
734
735
736 if (B_ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' ||
737 ch == ';' || ch == ',' || ch == '"' || ch == '#') {
738 /* Keep the original LEX so we can print an error if the included file can't be opened. */
739 LEX* lfori = lf;
740
741 lf->state = lex_none;
742 lf = lex_open_file(lf, lf->str, lf->scan_error);
743 if (lf == NULL) {
744 berrno be;
745 scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
746 lfori->str, be.bstrerror());
747 return T_ERROR;
748 }
749 break;
750 }
751 add_str(lf, ch);
752 break;
753 case lex_utf8_bom:
754 /* we only end up in this state if we have read an 0xEF
755 as the first byte of the file, indicating we are probably
756 reading a UTF-8 file */
757 if (ch == 0xBB && bom_bytes_seen == 1) {
758 bom_bytes_seen++;
759 } else if (ch == 0xBF && bom_bytes_seen == 2) {
760 token = T_UTF8_BOM;
761 lf->state = lex_none;
762 } else {
763 token = T_ERROR;
764 }
765 break;
766 case lex_utf16_le_bom:
767 /* we only end up in this state if we have read an 0xFF
768 as the first byte of the file -- indicating that we are
769 probably dealing with an Intel based (little endian) UTF-16 file*/
770 if (ch == 0xFE) {
771 token = T_UTF16_BOM;
772 lf->state = lex_none;
773 } else {
774 token = T_ERROR;
775 }
776 break;
777 }
778 Dmsg4(dbglvl, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state),
779 lex_tok_to_str(token), ch);
780 }
781 Dmsg2(dbglvl, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
782 lf->token = token;
783
784 /*
785 * Here is where we check to see if the user has set certain
786 * expectations (e.g. 32 bit integer). If so, we do type checking
787 * and possible additional scanning (e.g. for range).
788 */
789 switch (expect) {
790 case T_PINT32:
791 lf->pint32_val = scan_pint(lf, lf->str);
792 lf->pint32_val2 = lf->pint32_val;
793 token = T_PINT32;
794 break;
795
796 case T_PINT32_RANGE:
797 if (token == T_NUMBER) {
798 lf->pint32_val = scan_pint(lf, lf->str);
799 lf->pint32_val2 = lf->pint32_val;
800 token = T_PINT32;
801 } else {
802 char *p = strchr(lf->str, '-');
803 if (!p) {
804 scan_err2(lf, _("expected an integer or a range, got %s: %s"),
805 lex_tok_to_str(token), lf->str);
806 token = T_ERROR;
807 break;
808 }
809 *p++ = 0; /* terminate first half of range */
810 lf->pint32_val = scan_pint(lf, lf->str);
811 lf->pint32_val2 = scan_pint(lf, p);
812 token = T_PINT32_RANGE;
813 }
814 break;
815
816 case T_INT32:
817 if (token != T_NUMBER || !is_a_number(lf->str)) {
818 scan_err2(lf, _("expected an integer number, got %s: %s"),
819 lex_tok_to_str(token), lf->str);
820 token = T_ERROR;
821 break;
822 }
823 errno = 0;
824 lf->int32_val = (int32_t)str_to_int64(lf->str);
825 if (errno != 0) {
826 scan_err2(lf, _("expected an integer number, got %s: %s"),
827 lex_tok_to_str(token), lf->str);
828 token = T_ERROR;
829 } else {
830 token = T_INT32;
831 }
832 break;
833
834 case T_INT64:
835 Dmsg2(dbglvl, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL));
836 if (token != T_NUMBER || !is_a_number(lf->str)) {
837 scan_err2(lf, _("expected an integer number, got %s: %s"),
838 lex_tok_to_str(token), lf->str);
839 token = T_ERROR;
840 break;
841 }
842 errno = 0;
843 lf->int64_val = str_to_int64(lf->str);
844 if (errno != 0) {
845 scan_err2(lf, _("expected an integer number, got %s: %s"),
846 lex_tok_to_str(token), lf->str);
847 token = T_ERROR;
848 } else {
849 token = T_INT64;
850 }
851 break;
852
853 case T_PINT64_RANGE:
854 if (token == T_NUMBER) {
855 lf->pint64_val = scan_pint64(lf, lf->str);
856 lf->pint64_val2 = lf->pint64_val;
857 token = T_PINT64;
858 } else {
859 char *p = strchr(lf->str, '-');
860 if (!p) {
861 scan_err2(lf, _("expected an integer or a range, got %s: %s"),
862 lex_tok_to_str(token), lf->str);
863 token = T_ERROR;
864 break;
865 }
866 *p++ = 0; /* terminate first half of range */
867 lf->pint64_val = scan_pint64(lf, lf->str);
868 lf->pint64_val2 = scan_pint64(lf, p);
869 token = T_PINT64_RANGE;
870 }
871 break;
872
873 case T_NAME:
874 if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
875 scan_err2(lf, _("expected a name, got %s: %s"),
876 lex_tok_to_str(token), lf->str);
877 token = T_ERROR;
878 } else if (lf->str_len > MAX_RES_NAME_LENGTH) {
879 scan_err3(lf, _("name %s length %d too long, max is %d\n"), lf->str,
880 lf->str_len, MAX_RES_NAME_LENGTH);
881 token = T_ERROR;
882 }
883 break;
884
885 case T_STRING:
886 if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) {
887 scan_err2(lf, _("expected a string, got %s: %s"),
888 lex_tok_to_str(token), lf->str);
889 token = T_ERROR;
890 } else {
891 token = T_STRING;
892 }
893 break;
894
895
896 default:
897 break; /* no expectation given */
898 }
899 lf->token = token; /* set possible new token */
900 return token;
901 }
902