1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2012 Planets Communications B.V.
6 Copyright (C) 2013-2020 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero 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 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero 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 /*
24 * Lexical scanner for BAREOS configuration file
25 *
26 * Kern Sibbald, 2000
27 */
28
29 #include "include/bareos.h"
30 #include "lex.h"
31 #include "lib/edit.h"
32 #include "lib/parse_conf.h"
33 #include "lib/berrno.h"
34 #include <glob.h>
35
36 extern int debug_level;
37
38 /* Debug level for this source file */
39 static const int debuglevel = 5000;
40
41 /*
42 * Scan to "logical" end of line. I.e. end of line,
43 * or semicolon, but stop on BCT_EOB (same as end of
44 * line except it is not eaten).
45 */
ScanToEol(LEX * lc)46 void ScanToEol(LEX* lc)
47 {
48 int token;
49
50 Dmsg0(debuglevel, "start scan to eof\n");
51 while ((token = LexGetToken(lc, BCT_ALL)) != BCT_EOL) {
52 if (token == BCT_EOB) {
53 LexUngetChar(lc);
54 return;
55 }
56 }
57 }
58
59 /*
60 * Get next token, but skip EOL
61 */
ScanToNextNotEol(LEX * lc)62 int ScanToNextNotEol(LEX* lc)
63 {
64 int token;
65
66 do {
67 token = LexGetToken(lc, BCT_ALL);
68 } while (token == BCT_EOL);
69
70 return token;
71 }
72
73 /*
74 * Format a scanner error message
75 */
s_err(const char * file,int line,LEX * lc,const char * msg,...)76 static void s_err(const char* file, int line, LEX* lc, const char* msg, ...)
77 {
78 va_list ap;
79 int len, maxlen;
80 PoolMem buf(PM_NAME), more(PM_NAME);
81
82 while (1) {
83 maxlen = buf.size() - 1;
84 va_start(ap, msg);
85 len = Bvsnprintf(buf.c_str(), maxlen, msg, ap);
86 va_end(ap);
87
88 if (len < 0 || len >= (maxlen - 5)) {
89 buf.ReallocPm(maxlen + maxlen / 2);
90 continue;
91 }
92
93 break;
94 }
95
96 if (lc->err_type == 0) { /* M_ERROR_TERM by default */
97 lc->err_type = M_ERROR_TERM;
98 }
99
100 if (lc->line_no > lc->begin_line_no) {
101 Mmsg(more, _("Problem probably begins at line %d.\n"), lc->begin_line_no);
102 } else {
103 PmStrcpy(more, "");
104 }
105
106 if (lc->line_no > 0) {
107 e_msg(file, line, lc->err_type, 0,
108 _("Config error: %s\n"
109 " : line %d, col %d of file %s\n%s\n%s"),
110 buf.c_str(), lc->line_no, lc->col_no, lc->fname, lc->line,
111 more.c_str());
112 } else {
113 e_msg(file, line, lc->err_type, 0, _("Config error: %s\n"), buf.c_str());
114 }
115
116 lc->error_counter++;
117 }
118
119 /*
120 * Format a scanner warning message
121 */
s_warn(const char * file,int line,LEX * lc,const char * msg,...)122 static void s_warn(const char* file, int line, LEX* lc, const char* msg, ...)
123 {
124 va_list ap;
125 int len, maxlen;
126 PoolMem buf(PM_NAME), more(PM_NAME);
127
128 while (1) {
129 maxlen = buf.size() - 1;
130 va_start(ap, msg);
131 len = Bvsnprintf(buf.c_str(), maxlen, msg, ap);
132 va_end(ap);
133
134 if (len < 0 || len >= (maxlen - 5)) {
135 buf.ReallocPm(maxlen + maxlen / 2);
136 continue;
137 }
138
139 break;
140 }
141
142 if (lc->line_no > lc->begin_line_no) {
143 Mmsg(more, _("Problem probably begins at line %d.\n"), lc->begin_line_no);
144 } else {
145 PmStrcpy(more, "");
146 }
147
148 if (lc->line_no > 0) {
149 p_msg(file, line, 0,
150 _("Config warning: %s\n"
151 " : line %d, col %d of file %s\n%s\n%s"),
152 buf.c_str(), lc->line_no, lc->col_no, lc->fname, lc->line,
153 more.c_str());
154 } else {
155 p_msg(file, line, 0, _("Config warning: %s\n"), buf.c_str());
156 }
157 }
158
LexSetDefaultErrorHandler(LEX * lf)159 void LexSetDefaultErrorHandler(LEX* lf) { lf->ScanError = s_err; }
160
LexSetDefaultWarningHandler(LEX * lf)161 void LexSetDefaultWarningHandler(LEX* lf) { lf->scan_warning = s_warn; }
162
163 /*
164 * Set err_type used in error_handler
165 */
LexSetErrorHandlerErrorType(LEX * lf,int err_type)166 void LexSetErrorHandlerErrorType(LEX* lf, int err_type)
167 {
168 LEX* lex = lf;
169 while (lex) {
170 lex->err_type = err_type;
171 lex = lex->next;
172 }
173 }
174
175 /*
176 * Free the current file, and retrieve the contents of the previous packet if
177 * any.
178 */
LexCloseFile(LEX * lf)179 LEX* LexCloseFile(LEX* lf)
180 {
181 LEX* of;
182
183 if (lf == NULL) { Emsg0(M_ABORT, 0, _("Close of NULL file\n")); }
184 Dmsg1(debuglevel, "Close lex file: %s\n", lf->fname);
185
186 of = lf->next;
187 if (lf->bpipe) {
188 CloseBpipe(lf->bpipe);
189 lf->bpipe = NULL;
190 } else {
191 fclose(lf->fd);
192 }
193 Dmsg1(debuglevel, "Close cfg file %s\n", lf->fname);
194 free(lf->fname);
195 FreeMemory(lf->line);
196 FreeMemory(lf->str);
197 lf->line = NULL;
198 if (of) {
199 of->options = lf->options; /* preserve options */
200 of->error_counter += lf->error_counter; /* summarize the errors */
201 memcpy(lf, of, sizeof(LEX));
202 Dmsg1(debuglevel, "Restart scan of cfg file %s\n", of->fname);
203 } else {
204 of = lf;
205 lf = NULL;
206 }
207 free(of);
208 return lf;
209 }
210
211 /*
212 * Add lex structure for an included config file.
213 */
lex_add(LEX * lf,const char * filename,FILE * fd,Bpipe * bpipe,LEX_ERROR_HANDLER * ScanError,LEX_WARNING_HANDLER * scan_warning)214 static inline LEX* lex_add(LEX* lf,
215 const char* filename,
216 FILE* fd,
217 Bpipe* bpipe,
218 LEX_ERROR_HANDLER* ScanError,
219 LEX_WARNING_HANDLER* scan_warning)
220 {
221 LEX* nf;
222
223 Dmsg1(100, "open config file: %s\n", filename);
224 nf = (LEX*)malloc(sizeof(LEX));
225 if (lf) {
226 memcpy(nf, lf, sizeof(LEX));
227 memset(lf, 0, sizeof(LEX));
228 lf->next = nf; /* if have lf, push it behind new one */
229 lf->options = nf->options; /* preserve user options */
230 /*
231 * preserve err_type to prevent bareos exiting on 'reload'
232 * if config is invalid.
233 */
234 lf->err_type = nf->err_type;
235 } else {
236 lf = nf; /* start new packet */
237 memset(lf, 0, sizeof(LEX));
238 LexSetErrorHandlerErrorType(lf, M_ERROR_TERM);
239 }
240
241 if (ScanError) {
242 lf->ScanError = ScanError;
243 } else {
244 LexSetDefaultErrorHandler(lf);
245 }
246
247 if (scan_warning) {
248 lf->scan_warning = scan_warning;
249 } else {
250 LexSetDefaultWarningHandler(lf);
251 }
252
253 lf->fd = fd;
254 lf->bpipe = bpipe;
255 lf->fname = strdup(filename ? filename : "");
256 lf->line = GetMemory(1024);
257 lf->str = GetMemory(256);
258 lf->str_max_len = SizeofPoolMemory(lf->str);
259 lf->state = lex_none;
260 lf->ch = L_EOL;
261
262 return lf;
263 }
264
265 #ifdef HAVE_GLOB
IsWildcardString(const char * string)266 static inline bool IsWildcardString(const char* string)
267 {
268 return (strchr(string, '*') || strchr(string, '?'));
269 }
270 #endif
271
272 /*
273 * Open a new configuration file. We push the
274 * state of the current file (lf) so that we
275 * can do includes. This is a bit of a hammer.
276 * Instead of passing back the pointer to the
277 * new packet, I simply replace the contents
278 * of the caller's packet with the new packet,
279 * and link the contents of the old packet into
280 * the next field.
281 */
lex_open_file(LEX * lf,const char * filename,LEX_ERROR_HANDLER * ScanError,LEX_WARNING_HANDLER * scan_warning)282 LEX* lex_open_file(LEX* lf,
283 const char* filename,
284 LEX_ERROR_HANDLER* ScanError,
285 LEX_WARNING_HANDLER* scan_warning)
286 {
287 FILE* fd;
288 Bpipe* bpipe = NULL;
289 char* bpipe_filename = NULL;
290
291 if (filename[0] == '|') {
292 bpipe_filename = strdup(filename);
293 if ((bpipe = OpenBpipe(bpipe_filename + 1, 0, "rb")) == NULL) {
294 free(bpipe_filename);
295 return NULL;
296 }
297 free(bpipe_filename);
298 fd = bpipe->rfd;
299 return lex_add(lf, filename, fd, bpipe, ScanError, scan_warning);
300 } else {
301 #ifdef HAVE_GLOB
302 int globrc;
303 glob_t fileglob;
304 char* filename_expanded = NULL;
305
306 /*
307 * Flag GLOB_NOMAGIC is a GNU extension, therefore manually check if string
308 * is a wildcard string.
309 */
310
311 /*
312 * Clear fileglob at least required for mingw version of glob()
313 */
314 memset(&fileglob, 0, sizeof(fileglob));
315 globrc = glob(filename, 0, NULL, &fileglob);
316
317 if ((globrc == GLOB_NOMATCH) && (IsWildcardString(filename))) {
318 /*
319 * fname is a wildcard string, but no matching files have been found.
320 * Ignore this include statement and continue.
321 */
322 return lf;
323 } else if (globrc != 0) {
324 /*
325 * glob() error has occurred. Giving up.
326 */
327 return NULL;
328 }
329
330 Dmsg2(100, "glob %s: %i files\n", filename, fileglob.gl_pathc);
331 for (size_t i = 0; i < fileglob.gl_pathc; i++) {
332 filename_expanded = fileglob.gl_pathv[i];
333 if ((fd = fopen(filename_expanded, "rb")) == NULL) {
334 globfree(&fileglob);
335 return NULL;
336 }
337 lf = lex_add(lf, filename_expanded, fd, bpipe, ScanError, scan_warning);
338 }
339 globfree(&fileglob);
340 #else
341 if ((fd = fopen(filename, "rb")) == NULL) { return NULL; }
342 lf = lex_add(lf, filename, fd, bpipe, ScanError, scan_warning);
343 #endif
344 return lf;
345 }
346 }
347
lex_new_buffer(LEX * lf,LEX_ERROR_HANDLER * ScanError,LEX_WARNING_HANDLER * scan_warning)348 LEX* lex_new_buffer(LEX* lf,
349 LEX_ERROR_HANDLER* ScanError,
350 LEX_WARNING_HANDLER* scan_warning)
351 {
352 lf = lex_add(lf, NULL, NULL, NULL, ScanError, scan_warning);
353 Dmsg1(debuglevel, "Return lex=%x\n", lf);
354
355 return lf;
356 }
357
358 /*
359 * Get the next character from the input.
360 * Returns the character or
361 * L_EOF if end of file
362 * L_EOL if end of line
363 */
LexGetChar(LEX * lf)364 int LexGetChar(LEX* lf)
365 {
366 if (lf->ch == L_EOF) {
367 Emsg0(M_ABORT, 0,
368 _("get_char: called after EOF."
369 " You may have a open double quote without the closing double "
370 "quote.\n"));
371 }
372
373 if (lf->ch == L_EOL) {
374 /*
375 * See if we are really reading a file otherwise we have reached EndOfFile.
376 */
377 if (!lf->fd || bfgets(lf->line, lf->fd) == NULL) {
378 lf->ch = L_EOF;
379 if (lf->next) {
380 if (lf->fd) { LexCloseFile(lf); }
381 }
382 return lf->ch;
383 }
384 lf->line_no++;
385 lf->col_no = 0;
386 Dmsg2(1000, "fget line=%d %s", lf->line_no, lf->line);
387 }
388
389 lf->ch = (uint8_t)lf->line[lf->col_no];
390 if (lf->ch == 0) {
391 lf->ch = L_EOL;
392 } else if (lf->ch == '\n') {
393 lf->ch = L_EOL;
394 lf->col_no++;
395 } else {
396 lf->col_no++;
397 }
398 Dmsg2(debuglevel, "LexGetChar: %c %d\n", lf->ch, lf->ch);
399
400 return lf->ch;
401 }
402
LexUngetChar(LEX * lf)403 void LexUngetChar(LEX* lf)
404 {
405 if (lf->ch == L_EOL) {
406 lf->ch = 0; /* End of line, force read of next one */
407 } else {
408 lf->col_no--; /* Backup to re-read char */
409 }
410 }
411
412 /*
413 * Add a character to the current string
414 */
add_str(LEX * lf,int ch)415 static void add_str(LEX* lf, int ch)
416 {
417 /*
418 * The default config string is sized to 256 bytes.
419 * If we need longer config strings its increased with 256 bytes each time.
420 */
421 if ((lf->str_len + 3) >= lf->str_max_len) {
422 lf->str = CheckPoolMemorySize(lf->str, lf->str_max_len + 256);
423 lf->str_max_len = SizeofPoolMemory(lf->str);
424 }
425
426 lf->str[lf->str_len++] = ch;
427 lf->str[lf->str_len] = 0;
428 }
429
430 /*
431 * Begin the string
432 */
BeginStr(LEX * lf,int ch)433 static void BeginStr(LEX* lf, int ch)
434 {
435 lf->str_len = 0;
436 lf->str[0] = 0;
437 if (ch != 0) { add_str(lf, ch); }
438 lf->begin_line_no = lf->line_no; /* save start string line no */
439 }
440
lex_state_to_str(int state)441 static const char* lex_state_to_str(int state)
442 {
443 switch (state) {
444 case lex_none:
445 return _("none");
446 case lex_comment:
447 return _("comment");
448 case lex_number:
449 return _("number");
450 case lex_ip_addr:
451 return _("ip_addr");
452 case lex_identifier:
453 return _("identifier");
454 case lex_string:
455 return _("string");
456 case lex_quoted_string:
457 return _("quoted_string");
458 case lex_include:
459 return _("include");
460 case lex_include_quoted_string:
461 return _("include_quoted_string");
462 case lex_utf8_bom:
463 return _("UTF-8 Byte Order Mark");
464 case lex_utf16_le_bom:
465 return _("UTF-16le Byte Order Mark");
466 default:
467 return "??????";
468 }
469 }
470
471 /*
472 * Convert a lex token to a string
473 * used for debug/error printing.
474 */
lex_tok_to_str(int token)475 const char* lex_tok_to_str(int token)
476 {
477 switch (token) {
478 case L_EOF:
479 return "L_EOF";
480 case L_EOL:
481 return "L_EOL";
482 case BCT_NONE:
483 return "BCT_NONE";
484 case BCT_NUMBER:
485 return "BCT_NUMBER";
486 case BCT_IPADDR:
487 return "BCT_IPADDR";
488 case BCT_IDENTIFIER:
489 return "BCT_IDENTIFIER";
490 case BCT_UNQUOTED_STRING:
491 return "BCT_UNQUOTED_STRING";
492 case BCT_QUOTED_STRING:
493 return "BCT_QUOTED_STRING";
494 case BCT_BOB:
495 return "BCT_BOB";
496 case BCT_EOB:
497 return "BCT_EOB";
498 case BCT_EQUALS:
499 return "BCT_EQUALS";
500 case BCT_ERROR:
501 return "BCT_ERROR";
502 case BCT_EOF:
503 return "BCT_EOF";
504 case BCT_COMMA:
505 return "BCT_COMMA";
506 case BCT_EOL:
507 return "BCT_EOL";
508 case BCT_UTF8_BOM:
509 return "BCT_UTF8_BOM";
510 case BCT_UTF16_BOM:
511 return "BCT_UTF16_BOM";
512 default:
513 return "??????";
514 }
515 }
516
scan_pint(LEX * lf,char * str)517 static uint32_t scan_pint(LEX* lf, char* str)
518 {
519 int64_t val = 0;
520
521 if (!Is_a_number(str)) {
522 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
523 } else {
524 errno = 0;
525 val = str_to_int64(str);
526 if (errno != 0 || val < 0) {
527 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
528 }
529 }
530
531 return (uint32_t)(val & 0xffffffff);
532 }
533
scan_pint64(LEX * lf,char * str)534 static uint64_t scan_pint64(LEX* lf, char* str)
535 {
536 uint64_t val = 0;
537
538 if (!Is_a_number(str)) {
539 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
540 } else {
541 errno = 0;
542 val = str_to_uint64(str);
543 if (errno != 0) {
544 scan_err1(lf, _("expected a positive integer number, got: %s"), str);
545 }
546 }
547
548 return val;
549 }
550
551 class TemporaryBuffer {
552 public:
TemporaryBuffer(FILE * fd)553 TemporaryBuffer(FILE* fd) : buf(GetPoolMemory(PM_NAME)), fd_(fd)
554 {
555 pos_ = ftell(fd_);
556 }
~TemporaryBuffer()557 ~TemporaryBuffer()
558 {
559 FreePoolMemory(buf);
560 fseek(fd_, pos_, SEEK_SET);
561 }
562 POOLMEM* buf;
563
564 private:
565 FILE* fd_;
566 long pos_;
567 };
568
NextLineContinuesWithQuotes(LEX * lf)569 static bool NextLineContinuesWithQuotes(LEX* lf)
570 {
571 TemporaryBuffer t(lf->fd);
572
573 if (bfgets(t.buf, lf->fd) != NULL) {
574 int i = 0;
575 while (t.buf[i] != '\0') {
576 if (t.buf[i] == '"') { return true; }
577 if (t.buf[i] != ' ' && t.buf[i] != '\t') { return false; }
578 ++i;
579 };
580 }
581 return false;
582 }
583
CurrentLineContinuesWithQuotes(LEX * lf)584 static bool CurrentLineContinuesWithQuotes(LEX* lf)
585 {
586 int i = lf->col_no;
587 while (lf->line[i] != '\0') {
588 if (lf->line[i] == '"') { return true; }
589 if (lf->line[i] != ' ' && lf->line[i] != '\t') { return false; }
590 ++i;
591 };
592 return false;
593 }
594
595 /*
596 *
597 * Get the next token from the input
598 *
599 */
LexGetToken(LEX * lf,int expect)600 int LexGetToken(LEX* lf, int expect)
601 {
602 int ch;
603 int token = BCT_NONE;
604 bool continue_string = false;
605 bool esc_next = false;
606 /* Unicode files, especially on Win32, may begin with a "Byte Order Mark"
607 to indicate which transmission format the file is in. The codepoint for
608 this mark is U+FEFF and is represented as the octets EF-BB-BF in UTF-8
609 and as FF-FE in UTF-16le(little endian) and FE-FF in UTF-16(big endian).
610 We use a distinct state for UTF-8 and UTF-16le, and use bom_bytes_seen
611 to tell which byte we are expecting. */
612 int bom_bytes_seen = 0;
613
614 Dmsg0(debuglevel, "enter LexGetToken\n");
615 while (token == BCT_NONE) {
616 ch = LexGetChar(lf);
617 switch (lf->state) {
618 case lex_none:
619 Dmsg2(debuglevel, "Lex state lex_none ch=%d,%x\n", ch, ch);
620 if (B_ISSPACE(ch)) break;
621 if (B_ISALPHA(ch)) {
622 if (lf->options & LOPT_NO_IDENT || lf->options & LOPT_STRING) {
623 lf->state = lex_string;
624 } else {
625 lf->state = lex_identifier;
626 }
627 BeginStr(lf, ch);
628 break;
629 }
630 if (B_ISDIGIT(ch)) {
631 if (lf->options & LOPT_STRING) {
632 lf->state = lex_string;
633 } else {
634 lf->state = lex_number;
635 }
636 BeginStr(lf, ch);
637 break;
638 }
639 Dmsg0(debuglevel, "Enter lex_none switch\n");
640 switch (ch) {
641 case L_EOF:
642 token = BCT_EOF;
643 Dmsg0(debuglevel, "got L_EOF set token=T_EOF\n");
644 break;
645 case '#':
646 lf->state = lex_comment;
647 break;
648 case '{':
649 token = BCT_BOB;
650 BeginStr(lf, ch);
651 break;
652 case '}':
653 token = BCT_EOB;
654 BeginStr(lf, ch);
655 break;
656 case ' ':
657 if (continue_string) { continue; }
658 break;
659 case '"':
660 lf->state = lex_quoted_string;
661 if (!continue_string) { BeginStr(lf, 0); }
662 break;
663 case '=':
664 token = BCT_EQUALS;
665 BeginStr(lf, ch);
666 break;
667 case ',':
668 token = BCT_COMMA;
669 BeginStr(lf, ch);
670 break;
671 case ';':
672 if (expect != BCT_SKIP_EOL) {
673 token = BCT_EOL; /* treat ; like EOL */
674 }
675 break;
676 case L_EOL:
677 if (continue_string) {
678 continue;
679 } else {
680 Dmsg0(debuglevel, "got L_EOL set token=BCT_EOL\n");
681 if (expect != BCT_SKIP_EOL) { token = BCT_EOL; }
682 }
683 break;
684 case '@':
685 /* In NO_EXTERN mode, @ is part of a string */
686 if (lf->options & LOPT_NO_EXTERN) {
687 lf->state = lex_string;
688 BeginStr(lf, ch);
689 } else {
690 lf->state = lex_include;
691 BeginStr(lf, 0);
692 }
693 break;
694 case 0xEF: /* probably a UTF-8 BOM */
695 case 0xFF: /* probably a UTF-16le BOM */
696 case 0xFE: /* probably a UTF-16be BOM (error)*/
697 if (lf->line_no != 1 || lf->col_no != 1) {
698 lf->state = lex_string;
699 BeginStr(lf, ch);
700 } else {
701 bom_bytes_seen = 1;
702 if (ch == 0xEF) {
703 lf->state = lex_utf8_bom;
704 } else if (ch == 0xFF) {
705 lf->state = lex_utf16_le_bom;
706 } else {
707 scan_err0(lf, _("This config file appears to be in an "
708 "unsupported Unicode format (UTF-16be). Please "
709 "resave as UTF-8\n"));
710 return BCT_ERROR;
711 }
712 }
713 break;
714 default:
715 lf->state = lex_string;
716 BeginStr(lf, ch);
717 break;
718 }
719 break;
720 case lex_comment:
721 Dmsg1(debuglevel, "Lex state lex_comment ch=%x\n", ch);
722 if (ch == L_EOL) {
723 lf->state = lex_none;
724 if (expect != BCT_SKIP_EOL) { token = BCT_EOL; }
725 } else if (ch == L_EOF) {
726 token = BCT_ERROR;
727 }
728 break;
729 case lex_number:
730 Dmsg2(debuglevel, "Lex state lex_number ch=%x %c\n", ch, ch);
731 if (ch == L_EOF) {
732 token = BCT_ERROR;
733 break;
734 }
735 /* Might want to allow trailing specifications here */
736 if (B_ISDIGIT(ch)) {
737 add_str(lf, ch);
738 break;
739 }
740
741 /* A valid number can be terminated by the following */
742 if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') {
743 token = BCT_NUMBER;
744 lf->state = lex_none;
745 } else {
746 lf->state = lex_string;
747 }
748 LexUngetChar(lf);
749 break;
750 case lex_ip_addr:
751 if (ch == L_EOF) {
752 token = BCT_ERROR;
753 break;
754 }
755 Dmsg1(debuglevel, "Lex state lex_ip_addr ch=%x\n", ch);
756 break;
757 case lex_string:
758 Dmsg1(debuglevel, "Lex state lex_string ch=%x\n", ch);
759 if (ch == L_EOF) {
760 token = BCT_ERROR;
761 break;
762 }
763 if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{'
764 || ch == '\r' || ch == ';' || ch == ',' || ch == '#'
765 || (B_ISSPACE(ch))) {
766 LexUngetChar(lf);
767 token = BCT_UNQUOTED_STRING;
768 lf->state = lex_none;
769 break;
770 }
771 add_str(lf, ch);
772 break;
773 case lex_identifier:
774 Dmsg2(debuglevel, "Lex state lex_identifier ch=%x %c\n", ch, ch);
775 if (B_ISALPHA(ch)) {
776 add_str(lf, ch);
777 break;
778 } else if (B_ISSPACE(ch)) {
779 break;
780 } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}'
781 || ch == '{' || ch == '\r' || ch == ';' || ch == ','
782 || ch == '"' || ch == '#') {
783 LexUngetChar(lf);
784 token = BCT_IDENTIFIER;
785 lf->state = lex_none;
786 break;
787 } else if (ch == L_EOF) {
788 token = BCT_ERROR;
789 lf->state = lex_none;
790 BeginStr(lf, ch);
791 break;
792 }
793 /* Some non-alpha character => string */
794 lf->state = lex_string;
795 add_str(lf, ch);
796 break;
797 case lex_quoted_string:
798 Dmsg2(debuglevel, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
799 if (ch == L_EOF) {
800 token = BCT_ERROR;
801 break;
802 }
803 if (ch == L_EOL) {
804 esc_next = false;
805 break;
806 }
807 if (esc_next) {
808 add_str(lf, ch);
809 esc_next = false;
810 break;
811 }
812 if (ch == '\\') {
813 esc_next = true;
814 break;
815 }
816 if (ch == '"') {
817 if (NextLineContinuesWithQuotes(lf)
818 || CurrentLineContinuesWithQuotes(lf)) {
819 continue_string = true;
820 lf->state = lex_none;
821 continue;
822 } else {
823 token = BCT_QUOTED_STRING;
824 /*
825 * Since we may be scanning a quoted list of names,
826 * we get the next character (a comma indicates another
827 * one), then we put it back for rescanning.
828 */
829 LexGetChar(lf);
830 LexUngetChar(lf);
831 lf->state = lex_none;
832 }
833 break;
834 }
835 continue_string = false;
836 add_str(lf, ch);
837 break;
838 case lex_include_quoted_string:
839 if (ch == L_EOF) {
840 token = BCT_ERROR;
841 break;
842 }
843 if (esc_next) {
844 add_str(lf, ch);
845 esc_next = false;
846 break;
847 }
848 if (ch == '\\') {
849 esc_next = true;
850 break;
851 }
852 if (ch == '"') {
853 /* Keep the original LEX so we can print an error if the included file
854 * can't be opened. */
855 LEX* lfori = lf;
856 /* Skip the double quote when restarting parsing */
857 LexGetChar(lf);
858
859 lf->state = lex_none;
860 lf = lex_open_file(lf, lf->str, lf->ScanError, lf->scan_warning);
861 if (lf == NULL) {
862 BErrNo be;
863 scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
864 lfori->str, be.bstrerror());
865 return BCT_ERROR;
866 }
867 break;
868 }
869 add_str(lf, ch);
870 break;
871 case lex_include: /* scanning a filename */
872 if (ch == L_EOF) {
873 token = BCT_ERROR;
874 break;
875 }
876 if (ch == '"') {
877 lf->state = lex_include_quoted_string;
878 break;
879 }
880
881
882 if (B_ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{'
883 || ch == ';' || ch == ',' || ch == '"' || ch == '#') {
884 /* Keep the original LEX so we can print an error if the included file
885 * can't be opened. */
886 LEX* lfori = lf;
887
888 lf->state = lex_none;
889 lf = lex_open_file(lf, lf->str, lf->ScanError, lf->scan_warning);
890 if (lf == NULL) {
891 BErrNo be;
892 scan_err2(lfori, _("Cannot open included config file %s: %s\n"),
893 lfori->str, be.bstrerror());
894 return BCT_ERROR;
895 }
896 break;
897 }
898 add_str(lf, ch);
899 break;
900 case lex_utf8_bom:
901 /* we only end up in this state if we have read an 0xEF
902 as the first byte of the file, indicating we are probably
903 reading a UTF-8 file */
904 if (ch == 0xBB && bom_bytes_seen == 1) {
905 bom_bytes_seen++;
906 } else if (ch == 0xBF && bom_bytes_seen == 2) {
907 token = BCT_UTF8_BOM;
908 lf->state = lex_none;
909 } else {
910 token = BCT_ERROR;
911 }
912 break;
913 case lex_utf16_le_bom:
914 /* we only end up in this state if we have read an 0xFF
915 as the first byte of the file -- indicating that we are
916 probably dealing with an Intel based (little endian) UTF-16 file*/
917 if (ch == 0xFE) {
918 token = BCT_UTF16_BOM;
919 lf->state = lex_none;
920 } else {
921 token = BCT_ERROR;
922 }
923 break;
924 }
925 Dmsg4(debuglevel, "ch=%d state=%s token=%s %c\n", ch,
926 lex_state_to_str(lf->state), lex_tok_to_str(token), ch);
927 }
928 Dmsg2(debuglevel, "lex returning: line %d token: %s\n", lf->line_no,
929 lex_tok_to_str(token));
930 lf->token = token;
931
932 /*
933 * Here is where we check to see if the user has set certain
934 * expectations (e.g. 32 bit integer). If so, we do type checking
935 * and possible additional scanning (e.g. for range).
936 */
937 switch (expect) {
938 case BCT_PINT16:
939 lf->u.pint16_val = (scan_pint(lf, lf->str) & 0xffff);
940 lf->u2.pint16_val = lf->u.pint16_val;
941 token = BCT_PINT16;
942 break;
943
944 case BCT_PINT32:
945 lf->u.pint32_val = scan_pint(lf, lf->str);
946 lf->u2.pint32_val = lf->u.pint32_val;
947 token = BCT_PINT32;
948 break;
949
950 case BCT_PINT32_RANGE:
951 if (token == BCT_NUMBER) {
952 lf->u.pint32_val = scan_pint(lf, lf->str);
953 lf->u2.pint32_val = lf->u.pint32_val;
954 token = BCT_PINT32;
955 } else {
956 char* p = strchr(lf->str, '-');
957 if (!p) {
958 scan_err2(lf, _("expected an integer or a range, got %s: %s"),
959 lex_tok_to_str(token), lf->str);
960 token = BCT_ERROR;
961 break;
962 }
963 *p++ = 0; /* Terminate first half of range */
964 lf->u.pint32_val = scan_pint(lf, lf->str);
965 lf->u2.pint32_val = scan_pint(lf, p);
966 token = BCT_PINT32_RANGE;
967 }
968 break;
969
970 case BCT_INT16:
971 if (token != BCT_NUMBER || !Is_a_number(lf->str)) {
972 scan_err2(lf, _("expected an integer number, got %s: %s"),
973 lex_tok_to_str(token), lf->str);
974 token = BCT_ERROR;
975 break;
976 }
977 errno = 0;
978 lf->u.int16_val = (int16_t)str_to_int64(lf->str);
979 if (errno != 0) {
980 scan_err2(lf, _("expected an integer number, got %s: %s"),
981 lex_tok_to_str(token), lf->str);
982 token = BCT_ERROR;
983 } else {
984 token = BCT_INT16;
985 }
986 break;
987
988 case BCT_INT32:
989 if (token != BCT_NUMBER || !Is_a_number(lf->str)) {
990 scan_err2(lf, _("expected an integer number, got %s: %s"),
991 lex_tok_to_str(token), lf->str);
992 token = BCT_ERROR;
993 break;
994 }
995 errno = 0;
996 lf->u.int32_val = (int32_t)str_to_int64(lf->str);
997 if (errno != 0) {
998 scan_err2(lf, _("expected an integer number, got %s: %s"),
999 lex_tok_to_str(token), lf->str);
1000 token = BCT_ERROR;
1001 } else {
1002 token = BCT_INT32;
1003 }
1004 break;
1005
1006 case BCT_INT64:
1007 Dmsg2(debuglevel, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL));
1008 if (token != BCT_NUMBER || !Is_a_number(lf->str)) {
1009 scan_err2(lf, _("expected an integer number, got %s: %s"),
1010 lex_tok_to_str(token), lf->str);
1011 token = BCT_ERROR;
1012 break;
1013 }
1014 errno = 0;
1015 lf->u.int64_val = str_to_int64(lf->str);
1016 if (errno != 0) {
1017 scan_err2(lf, _("expected an integer number, got %s: %s"),
1018 lex_tok_to_str(token), lf->str);
1019 token = BCT_ERROR;
1020 } else {
1021 token = BCT_INT64;
1022 }
1023 break;
1024
1025 case BCT_PINT64_RANGE:
1026 if (token == BCT_NUMBER) {
1027 lf->u.pint64_val = scan_pint64(lf, lf->str);
1028 lf->u2.pint64_val = lf->u.pint64_val;
1029 token = BCT_PINT64;
1030 } else {
1031 char* p = strchr(lf->str, '-');
1032 if (!p) {
1033 scan_err2(lf, _("expected an integer or a range, got %s: %s"),
1034 lex_tok_to_str(token), lf->str);
1035 token = BCT_ERROR;
1036 break;
1037 }
1038 *p++ = 0; /* Terminate first half of range */
1039 lf->u.pint64_val = scan_pint64(lf, lf->str);
1040 lf->u2.pint64_val = scan_pint64(lf, p);
1041 token = BCT_PINT64_RANGE;
1042 }
1043 break;
1044
1045 case BCT_NAME:
1046 if (token != BCT_IDENTIFIER && token != BCT_UNQUOTED_STRING
1047 && token != BCT_QUOTED_STRING) {
1048 scan_err2(lf, _("expected a name, got %s: %s"), lex_tok_to_str(token),
1049 lf->str);
1050 token = BCT_ERROR;
1051 } else if (lf->str_len > MAX_RES_NAME_LENGTH) {
1052 scan_err3(lf, _("name %s length %d too long, max is %d\n"), lf->str,
1053 lf->str_len, MAX_RES_NAME_LENGTH);
1054 token = BCT_ERROR;
1055 }
1056 break;
1057
1058 case BCT_STRING:
1059 if (token != BCT_IDENTIFIER && token != BCT_UNQUOTED_STRING
1060 && token != BCT_QUOTED_STRING) {
1061 scan_err2(lf, _("expected a string, got %s: %s"), lex_tok_to_str(token),
1062 lf->str);
1063 token = BCT_ERROR;
1064 } else {
1065 token = BCT_STRING;
1066 }
1067 break;
1068
1069
1070 default:
1071 break; /* no expectation given */
1072 }
1073 lf->token = token; /* set possible new token */
1074 return token;
1075 }
1076