~ubuntu-branches/ubuntu/trusty/syslog-ng/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/cfg-lexer_Fix_glob-based_include_order.patch/lib/cfg-lexer.c

  • Committer: Package Import Robot
  • Author(s): Laszlo Boszormenyi (GCS)
  • Date: 2013-05-26 09:06:21 UTC
  • mfrom: (1.3.11)
  • Revision ID: package-import@ubuntu.com-20130526090621-8z2s0oi21eoljb9x
Tags: 3.3.9-1
* New upstream release.
* Include missed ivykis header (closes: #708793).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (c) 2002-2012 BalaBit IT Ltd, Budapest, Hungary
3
 
 * Copyright (c) 1998-2012 Balázs Scheidler
4
 
 *
5
 
 * This library is free software; you can redistribute it and/or
6
 
 * modify it under the terms of the GNU Lesser General Public
7
 
 * License as published by the Free Software Foundation; either
8
 
 * version 2.1 of the License, or (at your option) any later version.
9
 
 *
10
 
 * This library is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 
 * Lesser General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU Lesser General Public
16
 
 * License along with this library; if not, write to the Free Software
17
 
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 
 *
19
 
 * As an additional exemption you are allowed to compile & link against the
20
 
 * OpenSSL libraries as published by the OpenSSL project. See the file
21
 
 * COPYING for details.
22
 
 *
23
 
 */
24
 
 
25
 
#include "cfg-lexer.h"
26
 
#include "cfg-lex.h"
27
 
#include "cfg-grammar.h"
28
 
#include "block-ref-parser.h"
29
 
#include "pragma-parser.h"
30
 
#include "messages.h"
31
 
#include "misc.h"
32
 
 
33
 
#include <string.h>
34
 
#include <glob.h>
35
 
#include <sys/stat.h>
36
 
 
37
 
struct _CfgArgs
38
 
{
39
 
  GHashTable *args;
40
 
};
41
 
 
42
 
/*
43
 
 * A token block is a series of tokens to be injected into the tokens
44
 
 * fetched by the lexer.  It is assumed to be filled and then depleted, the
45
 
 * two operations cannot be intermixed.
46
 
 */
47
 
struct _CfgTokenBlock
48
 
{
49
 
  gint pos;
50
 
  GArray *tokens;
51
 
};
52
 
 
53
 
/**
54
 
 * CfgBlockGenerator:
55
 
 *
56
 
 * This class describes a block generator, e.g. a function callback
57
 
 * that returns a configuration snippet in a given context. Each
58
 
 * user-defined "block" results in a generator to be registered, but
59
 
 * theoretically this mechanism can be used to write plugins that
60
 
 * generate syslog-ng configuration on the fly, based on system
61
 
 * settings for example.
62
 
 **/
63
 
struct _CfgBlockGenerator
64
 
{
65
 
  gint context;
66
 
  gchar *name;
67
 
  CfgBlockGeneratorFunc generator;
68
 
  gpointer generator_data;
69
 
  GDestroyNotify generator_data_free;
70
 
};
71
 
 
72
 
/**
73
 
 * CfgLexerContext:
74
 
 *
75
 
 * This object tells the lexer in which context it is operating right
76
 
 * now. The context influences the way the lexer works, for example in
77
 
 * LL_CONTEXT_BLOCK_DEF/REF all keyword resolutions are disabled.
78
 
 *
79
 
 * A textual description is also associated with the current context
80
 
 * in order to give better error messages.
81
 
 **/
82
 
typedef struct _CfgLexerContext
83
 
{
84
 
  gint type;
85
 
  CfgLexerKeyword *keywords;
86
 
  gchar desc[0];
87
 
} CfgLexerContext;
88
 
 
89
 
/*
90
 
 * cfg_lexer_push_context:
91
 
 *
92
 
 * This function can be used to push a lexer context to the stack. The top
93
 
 * of the stack determines how an error is reported and can also influence
94
 
 * the lexer.
95
 
 */
96
 
void
97
 
cfg_lexer_push_context(CfgLexer *self, gint type, CfgLexerKeyword *keywords, const gchar *desc)
98
 
{
99
 
  CfgLexerContext *context;
100
 
 
101
 
  context = g_malloc(sizeof(CfgLexerContext) + strlen(desc) + 1);
102
 
  context->type = type ? type : cfg_lexer_get_context_type(self);
103
 
  context->keywords = keywords;
104
 
  memcpy(&context->desc, desc, strlen(desc) + 1);
105
 
  self->context_stack = g_list_prepend(self->context_stack, context);
106
 
}
107
 
 
108
 
/*
109
 
 * cfg_lexer_pop_context:
110
 
 *
111
 
 * Pop the topmost item off the stack.
112
 
 */
113
 
void
114
 
cfg_lexer_pop_context(CfgLexer *self)
115
 
{
116
 
  if (self->context_stack)
117
 
    {
118
 
      g_free((gchar *) self->context_stack->data);
119
 
      self->context_stack = g_list_delete_link(self->context_stack, self->context_stack);
120
 
    }
121
 
}
122
 
 
123
 
/*
124
 
 * cfg_lexer_get_context_type:
125
 
 *
126
 
 * Get the current context type (one of LL_CONTEXT_* values).
127
 
 */
128
 
gint
129
 
cfg_lexer_get_context_type(CfgLexer *self)
130
 
{
131
 
  GList *l;
132
 
 
133
 
  l = self->context_stack;
134
 
  if (l)
135
 
    return ((CfgLexerContext *) l->data)->type;
136
 
  return 0;
137
 
}
138
 
 
139
 
/*
140
 
 * cfg_lexer_get_context_description:
141
 
 *
142
 
 * Get the description of the current context.
143
 
 */
144
 
const gchar *
145
 
cfg_lexer_get_context_description(CfgLexer *self)
146
 
{
147
 
  GList *l;
148
 
 
149
 
  l = self->context_stack;
150
 
  if (l)
151
 
    return ((CfgLexerContext *) l->data)->desc;
152
 
  return "configuration";
153
 
}
154
 
 
155
 
gchar *
156
 
cfg_lexer_subst_args(CfgArgs *globals, CfgArgs *defs, CfgArgs *args, gchar *cptr, gsize *length)
157
 
{
158
 
  gboolean backtick = FALSE;
159
 
  gchar *p, *ref_start = cptr;
160
 
  GString *result = g_string_sized_new(32);
161
 
 
162
 
  p = cptr;
163
 
  while (*p)
164
 
    {
165
 
      if (!backtick && (*p) == '`')
166
 
        {
167
 
          /* start of reference */
168
 
          backtick = TRUE;
169
 
          ref_start = p + 1;
170
 
        }
171
 
      else if (backtick && (*p) == '`')
172
 
        {
173
 
          /* end of reference */
174
 
          backtick = FALSE;
175
 
 
176
 
          if (ref_start == p)
177
 
            {
178
 
              /* empty ref, just include a ` character */
179
 
              g_string_append_c(result, '`');
180
 
            }
181
 
          else
182
 
            {
183
 
              const gchar *arg;
184
 
 
185
 
              *p = 0;
186
 
              if (args && (arg = cfg_args_get(args, ref_start)))
187
 
                ;
188
 
              else if (defs && (arg = cfg_args_get(defs, ref_start)))
189
 
                ;
190
 
              else if (globals && (arg = cfg_args_get(globals, ref_start)))
191
 
                ;
192
 
              else if ((arg = g_getenv(ref_start)))
193
 
                ;
194
 
              else
195
 
                arg = NULL;
196
 
 
197
 
              *p = '`';
198
 
              g_string_append(result, arg ? arg : "");
199
 
            }
200
 
        }
201
 
      else if (!backtick)
202
 
        g_string_append_c(result, *p);
203
 
      p++;
204
 
    }
205
 
 
206
 
  if (backtick)
207
 
    {
208
 
      g_string_free(result, TRUE);
209
 
      return NULL;
210
 
    }
211
 
 
212
 
  *length = result->len;
213
 
  return g_string_free(result, FALSE);
214
 
}
215
 
 
216
 
int
217
 
cfg_lexer_lookup_keyword(CfgLexer *self, YYSTYPE *yylval, YYLTYPE *yylloc, const char *token)
218
 
{
219
 
  GList *l;
220
 
 
221
 
  l = self->context_stack;
222
 
  while (l)
223
 
    {
224
 
      CfgLexerContext *context = ((CfgLexerContext *) l->data);
225
 
      CfgLexerKeyword *keywords = context->keywords;
226
 
 
227
 
      if (keywords)
228
 
        {
229
 
          int i, j;
230
 
 
231
 
          for (i = 0; keywords[i].kw_name; i++)
232
 
            {
233
 
              if (strcmp(keywords[i].kw_name, CFG_KEYWORD_STOP) == 0)
234
 
                {
235
 
                  yylval->cptr = strdup(token);
236
 
                  return LL_IDENTIFIER;
237
 
                }
238
 
 
239
 
              for (j = 0; token[j] && keywords[i].kw_name[j]; j++)
240
 
                {
241
 
                  if (token[j] == '-' || token[j] == '_')
242
 
                    {
243
 
                      if (keywords[i].kw_name[j] != '_')
244
 
                        break;
245
 
                    }
246
 
                  else if (token[j] != keywords[i].kw_name[j])
247
 
                    break;
248
 
                }
249
 
              if (token[j] == 0 && keywords[i].kw_name[j] == 0)
250
 
                {
251
 
                  /* match */
252
 
                  if (keywords[i].kw_req_version > configuration->version)
253
 
                    {
254
 
                      msg_warning("WARNING: Your configuration uses a newly introduced reserved word as identifier, please use a different name or enclose it in quotes",
255
 
                                  evt_tag_str("keyword", keywords[i].kw_name),
256
 
                                  evt_tag_printf("config-version", "%d.%d", configuration->version >> 8, configuration->version & 0xFF),
257
 
                                  evt_tag_printf("version", "%d.%d", (keywords[i].kw_req_version >> 8), keywords[i].kw_req_version & 0xFF),
258
 
                                  yylloc ? evt_tag_str("filename", yylloc->level->name) : NULL,
259
 
                                  yylloc ? evt_tag_printf("line", "%d:%d", yylloc->first_line, yylloc->first_column) : NULL,
260
 
                                  NULL);
261
 
                      break;
262
 
                    }
263
 
                  switch (keywords[i].kw_status)
264
 
                    {
265
 
                    case KWS_OBSOLETE:
266
 
                      msg_warning("Your configuration file uses an obsoleted keyword, please update your configuration",
267
 
                                  evt_tag_str("keyword", keywords[i].kw_name),
268
 
                                  evt_tag_str("change", keywords[i].kw_explain),
269
 
                                  NULL);
270
 
                      break;
271
 
                    default:
272
 
                      break;
273
 
                    }
274
 
                  keywords[i].kw_status = KWS_NORMAL;
275
 
                  yylval->type = LL_TOKEN;
276
 
                  yylval->token = keywords[i].kw_token;
277
 
                  return keywords[i].kw_token;
278
 
                }
279
 
            }
280
 
        }
281
 
      l = l->next;
282
 
    }
283
 
  yylval->cptr = strdup(token);
284
 
  return LL_IDENTIFIER;
285
 
}
286
 
 
287
 
gboolean
288
 
cfg_lexer_start_next_include(CfgLexer *self)
289
 
{
290
 
  CfgIncludeLevel *level = &self->include_stack[self->include_depth];
291
 
  gchar *filename;
292
 
  gboolean buffer_processed = FALSE;
293
 
 
294
 
  if (self->include_depth == 0)
295
 
    {
296
 
      return FALSE;
297
 
    }
298
 
 
299
 
  if (level->yybuf)
300
 
    {
301
 
      msg_debug("Finishing include",
302
 
                evt_tag_str((level->include_type == CFGI_FILE ? "filename" : "content"), level->name),
303
 
                evt_tag_int("depth", self->include_depth),
304
 
                NULL);
305
 
      buffer_processed = TRUE;
306
 
    }
307
 
 
308
 
  /* reset the include state, should also handle initial invocations, in which case everything is NULL */
309
 
  if (level->yybuf)
310
 
    _cfg_lexer__delete_buffer(level->yybuf, self->state);
311
 
 
312
 
  if (level->include_type == CFGI_FILE)
313
 
    {
314
 
      if (level->file.include_file)
315
 
        {
316
 
          fclose(level->file.include_file);
317
 
        }
318
 
    }
319
 
 
320
 
  if ((level->include_type == CFGI_BUFFER && buffer_processed) ||
321
 
      (level->include_type == CFGI_FILE && !level->file.files))
322
 
    {
323
 
      /* we finished with an include statement that included a series of
324
 
       * files (e.g.  directory include). */
325
 
      g_free(level->name);
326
 
 
327
 
      if (level->include_type == CFGI_BUFFER)
328
 
        g_free(level->buffer.content);
329
 
 
330
 
      memset(level, 0, sizeof(*level));
331
 
 
332
 
      self->include_depth--;
333
 
      _cfg_lexer__switch_to_buffer(self->include_stack[self->include_depth].yybuf, self->state);
334
 
 
335
 
      return TRUE;
336
 
    }
337
 
 
338
 
  /* now populate "level" with the new include information */
339
 
  if (level->include_type == CFGI_BUFFER)
340
 
    {
341
 
      level->yybuf = _cfg_lexer__scan_buffer(level->buffer.content, level->buffer.content_length, self->state);
342
 
    }
343
 
  else if (level->include_type == CFGI_FILE)
344
 
    {
345
 
      FILE *include_file;
346
 
 
347
 
      filename = (gchar *) level->file.files->data;
348
 
      level->file.files = g_slist_delete_link(level->file.files, level->file.files);
349
 
 
350
 
      include_file = fopen(filename, "r");
351
 
      if (!include_file)
352
 
        {
353
 
          msg_error("Error opening include file",
354
 
                    evt_tag_str("filename", filename),
355
 
                    evt_tag_int("depth", self->include_depth),
356
 
                    NULL);
357
 
          g_free(filename);
358
 
          return FALSE;
359
 
        }
360
 
      msg_debug("Starting to read include file",
361
 
                evt_tag_str("filename", filename),
362
 
                evt_tag_int("depth", self->include_depth),
363
 
                NULL);
364
 
      g_free(level->name);
365
 
      level->name = filename;
366
 
 
367
 
      level->file.include_file = include_file;
368
 
      level->yybuf = _cfg_lexer__create_buffer(level->file.include_file, YY_BUF_SIZE, self->state);
369
 
    }
370
 
  else
371
 
    {
372
 
      g_assert_not_reached();
373
 
    }
374
 
 
375
 
  level->lloc.first_line = level->lloc.last_line = 1;
376
 
  level->lloc.first_column = level->lloc.last_column = 1;
377
 
  level->lloc.level = level;
378
 
 
379
 
  _cfg_lexer__switch_to_buffer(level->yybuf, self->state);
380
 
  return TRUE;
381
 
}
382
 
 
383
 
static gboolean
384
 
cfg_lexer_include_file_simple(CfgLexer *self, const gchar *filename)
385
 
{
386
 
  CfgIncludeLevel *level;
387
 
  struct stat st;
388
 
 
389
 
  if (stat(filename, &st) < 0)
390
 
    {
391
 
      return FALSE;
392
 
    }
393
 
 
394
 
  self->include_depth++;
395
 
  level = &self->include_stack[self->include_depth];
396
 
  level->include_type = CFGI_FILE;
397
 
  if (S_ISDIR(st.st_mode))
398
 
    {
399
 
      GDir *dir;
400
 
      GError *error = NULL;
401
 
      const gchar *entry;
402
 
 
403
 
      dir = g_dir_open(filename, 0, &error);
404
 
      if (!dir)
405
 
        {
406
 
          msg_error("Error opening directory for reading",
407
 
                evt_tag_str("filename", filename),
408
 
                evt_tag_str("error", error->message),
409
 
                NULL);
410
 
          goto drop_level;
411
 
        }
412
 
      while ((entry = g_dir_read_name(dir)))
413
 
        {
414
 
          const gchar *p;
415
 
          if (entry[0] == '.')
416
 
            {
417
 
              msg_debug("Skipping include file, it cannot begin with .",
418
 
                        evt_tag_str("filename", entry),
419
 
                        NULL);
420
 
              continue;
421
 
            }
422
 
          for (p = entry; *p; p++)
423
 
            {
424
 
              if (!((*p >= 'a' && *p <= 'z') ||
425
 
                   (*p >= 'A' && *p <= 'Z') ||
426
 
                   (*p >= '0' && *p <= '9') ||
427
 
                   (*p == '_') || (*p == '-') || (*p == '.')))
428
 
                {
429
 
                  msg_debug("Skipping include file, does not match pattern [\\-_a-zA-Z0-9]+",
430
 
                            evt_tag_str("filename", entry),
431
 
                            NULL);
432
 
                  p = NULL;
433
 
                  break;
434
 
                }
435
 
            }
436
 
          if (p)
437
 
            {
438
 
              gchar *full_filename = g_build_filename(filename, entry, NULL);
439
 
              if (stat(full_filename, &st) < 0 || S_ISDIR(st.st_mode))
440
 
                {
441
 
                  msg_debug("Skipping include file as it is a directory",
442
 
                            evt_tag_str("filename", entry),
443
 
                            NULL);
444
 
                  g_free(full_filename);
445
 
                  continue;
446
 
                }
447
 
              level->file.files = g_slist_insert_sorted(level->file.files, full_filename, (GCompareFunc) strcmp);
448
 
              msg_debug("Adding include file",
449
 
                        evt_tag_str("filename", entry),
450
 
                        NULL);
451
 
            }
452
 
        }
453
 
      g_dir_close(dir);
454
 
      if (!level->file.files)
455
 
        {
456
 
          /* no include files in the specified directory */
457
 
          msg_debug("No files in this include directory",
458
 
                    evt_tag_str("dir", filename),
459
 
                    NULL);
460
 
          self->include_depth--;
461
 
          return TRUE;
462
 
        }
463
 
    }
464
 
  else
465
 
    {
466
 
      g_assert(level->file.files == NULL);
467
 
      level->file.files = g_slist_prepend(level->file.files, g_strdup(filename));
468
 
    }
469
 
  return cfg_lexer_start_next_include(self);
470
 
 drop_level:
471
 
  g_slist_foreach(level->file.files, (GFunc) g_free, NULL);
472
 
  g_slist_free(level->file.files);
473
 
  level->file.files = NULL;
474
 
 
475
 
  return FALSE;
476
 
}
477
 
 
478
 
static gboolean
479
 
cfg_lexer_include_file_glob_at(CfgLexer *self, const gchar *pattern)
480
 
{
481
 
  glob_t globbuf;
482
 
  size_t i;
483
 
  gboolean status = FALSE;
484
 
  int r;
485
 
 
486
 
  r = glob(pattern, 0, NULL, &globbuf);
487
 
 
488
 
  if (r == GLOB_NOMATCH)
489
 
    return TRUE;
490
 
  if (r != 0)
491
 
    return FALSE;
492
 
 
493
 
  for (i = 0; i < globbuf.gl_pathc; i++)
494
 
    status |= cfg_lexer_include_file(self, globbuf.gl_pathv[i]);
495
 
 
496
 
  globfree(&globbuf);
497
 
 
498
 
  return status;
499
 
}
500
 
 
501
 
static gboolean
502
 
cfg_lexer_include_file_glob(CfgLexer *self, const gchar *filename_)
503
 
{
504
 
  const gchar *path = cfg_args_get(self->globals, "include-path");
505
 
 
506
 
  if (filename_[0] == '/' || !path)
507
 
    return cfg_lexer_include_file_glob_at(self, filename_);
508
 
  else
509
 
    {
510
 
      gchar **dirs;
511
 
      gchar *cf;
512
 
      gint i = 0;
513
 
      gboolean status = FALSE;
514
 
 
515
 
      dirs = g_strsplit(path, G_SEARCHPATH_SEPARATOR_S, 0);
516
 
      while (dirs && dirs[i])
517
 
        {
518
 
          cf = g_build_filename(dirs[i], filename_, NULL);
519
 
          status |= cfg_lexer_include_file_glob_at(self, cf);
520
 
          g_free(cf);
521
 
          i++;
522
 
        }
523
 
      g_strfreev(dirs);
524
 
      return status;
525
 
    }
526
 
}
527
 
 
528
 
gboolean
529
 
cfg_lexer_include_file(CfgLexer *self, const gchar *filename_)
530
 
{
531
 
  struct stat st;
532
 
  gchar *filename;
533
 
 
534
 
  if (self->include_depth >= MAX_INCLUDE_DEPTH - 1)
535
 
    {
536
 
      msg_error("Include file depth is too deep, increase MAX_INCLUDE_DEPTH and recompile",
537
 
                evt_tag_str("filename", filename_),
538
 
                evt_tag_int("depth", self->include_depth),
539
 
                NULL);
540
 
      return FALSE;
541
 
    }
542
 
 
543
 
  filename = find_file_in_path(cfg_args_get(self->globals, "include-path"), filename_, G_FILE_TEST_EXISTS);
544
 
  if (!filename || stat(filename, &st) < 0)
545
 
    {
546
 
      if (cfg_lexer_include_file_glob(self, filename_))
547
 
        return TRUE;
548
 
 
549
 
      msg_error("Include file/directory not found",
550
 
                evt_tag_str("filename", filename_),
551
 
                evt_tag_str("include-path", cfg_args_get(self->globals, "include-path")),
552
 
                evt_tag_errno("error", errno),
553
 
                NULL);
554
 
      return FALSE;
555
 
    }
556
 
  else
557
 
    {
558
 
      gboolean result;
559
 
 
560
 
      result = cfg_lexer_include_file_simple(self, filename);
561
 
      g_free(filename);
562
 
      return result;
563
 
    }
564
 
}
565
 
 
566
 
gboolean
567
 
cfg_lexer_include_buffer(CfgLexer *self, const gchar *name, gchar *buffer, gsize length)
568
 
{
569
 
  CfgIncludeLevel *level;
570
 
 
571
 
  /* lex requires two NUL characters at the end of the input */
572
 
  buffer = g_realloc(buffer, length + 2);
573
 
  buffer[length] = 0;
574
 
  buffer[length + 1] = 0;
575
 
  length += 2;
576
 
 
577
 
  if (self->include_depth >= MAX_INCLUDE_DEPTH - 1)
578
 
    {
579
 
      msg_error("Include file depth is too deep, increase MAX_INCLUDE_DEPTH and recompile",
580
 
                evt_tag_str("buffer", name),
581
 
                evt_tag_int("depth", self->include_depth),
582
 
                NULL);
583
 
      return FALSE;
584
 
    }
585
 
 
586
 
  self->include_depth++;
587
 
  level = &self->include_stack[self->include_depth];
588
 
 
589
 
  level->include_type = CFGI_BUFFER;
590
 
  level->buffer.content = buffer;
591
 
  level->buffer.content_length = length;
592
 
  level->name = g_strdup(name);
593
 
 
594
 
  return cfg_lexer_start_next_include(self);
595
 
}
596
 
 
597
 
void
598
 
cfg_lexer_inject_token_block(CfgLexer *self, CfgTokenBlock *block)
599
 
{
600
 
  self->token_blocks = g_list_append(self->token_blocks, block);
601
 
}
602
 
 
603
 
static CfgBlockGenerator *
604
 
cfg_lexer_find_generator(CfgLexer *self, gint context, const gchar *name)
605
 
{
606
 
  GList *l;
607
 
 
608
 
  for (l = self->generators; l; l = l->next)
609
 
    {
610
 
      CfgBlockGenerator *gen = (CfgBlockGenerator *) l->data;
611
 
 
612
 
      if ((gen->context == 0 || gen->context == context) && strcmp(gen->name, name) == 0)
613
 
        {
614
 
          return gen;
615
 
        }
616
 
    }
617
 
  return NULL;
618
 
}
619
 
 
620
 
gboolean
621
 
cfg_lexer_register_block_generator(CfgLexer *self, gint context, const gchar *name, CfgBlockGeneratorFunc generator, gpointer generator_data, GDestroyNotify generator_data_free)
622
 
{
623
 
  CfgBlockGenerator *gen;
624
 
  gboolean res = FALSE;
625
 
 
626
 
  gen = cfg_lexer_find_generator(self, context, name);
627
 
  if (gen)
628
 
    {
629
 
      gen->generator_data_free(gen->generator_data);
630
 
      g_free(gen->name);
631
 
    }
632
 
  else
633
 
    {
634
 
      gen = g_new0(CfgBlockGenerator, 1);
635
 
      self->generators = g_list_append(self->generators, gen);
636
 
      res = TRUE;
637
 
    }
638
 
 
639
 
  gen->context = context;
640
 
  gen->name = g_strdup(name);
641
 
  gen->generator = generator;
642
 
  gen->generator_data = generator_data;
643
 
  gen->generator_data_free = generator_data_free;
644
 
  return res;
645
 
}
646
 
 
647
 
static gboolean
648
 
cfg_lexer_generate_block(CfgLexer *self, gint context, const gchar *name, CfgBlockGenerator *gen, CfgArgs *args)
649
 
{
650
 
  return gen->generator(self, context, name, args, gen->generator_data);
651
 
}
652
 
 
653
 
void
654
 
cfg_lexer_unput_token(CfgLexer *self, YYSTYPE *yylval)
655
 
{
656
 
  CfgTokenBlock *block;
657
 
 
658
 
  block = cfg_token_block_new();
659
 
  cfg_token_block_add_token(block, yylval);
660
 
  cfg_lexer_inject_token_block(self, block);
661
 
}
662
 
 
663
 
int
664
 
cfg_lexer_lex(CfgLexer *self, YYSTYPE *yylval, YYLTYPE *yylloc)
665
 
{
666
 
  CfgBlockGenerator *gen;
667
 
  CfgTokenBlock *block;
668
 
  YYSTYPE *token;
669
 
  gint tok;
670
 
  gboolean injected;
671
 
 
672
 
 relex:
673
 
 
674
 
  injected = FALSE;
675
 
  while (self->token_blocks)
676
 
    {
677
 
      block = self->token_blocks->data;
678
 
      token = cfg_token_block_get_token(block);
679
 
 
680
 
      if (token)
681
 
        {
682
 
          *yylval = *token;
683
 
          *yylloc = self->include_stack[self->include_depth].lloc;
684
 
          tok = token->type;
685
 
          if (token->type == LL_TOKEN)
686
 
            {
687
 
              tok = token->token;
688
 
              injected = TRUE;
689
 
            }
690
 
          else if (token->type == LL_IDENTIFIER || token->type == LL_STRING)
691
 
            {
692
 
              yylval->cptr = strdup(token->cptr);
693
 
            }
694
 
 
695
 
          goto exit;
696
 
        }
697
 
      else
698
 
        {
699
 
          self->token_blocks = g_list_delete_link(self->token_blocks, self->token_blocks);
700
 
          cfg_token_block_free(block);
701
 
        }
702
 
    }
703
 
 
704
 
  if (cfg_lexer_get_context_type(self) == LL_CONTEXT_BLOCK_CONTENT)
705
 
    _cfg_lexer_force_block_state(self->state);
706
 
 
707
 
  yylval->type = 0;
708
 
 
709
 
  g_string_truncate(self->token_text, 0);
710
 
  g_string_truncate(self->token_pretext, 0);
711
 
 
712
 
  tok = _cfg_lexer_lex(yylval, yylloc, self->state);
713
 
  if (yylval->type == 0)
714
 
    yylval->type = tok;
715
 
 
716
 
  if (self->preprocess_output)
717
 
    fprintf(self->preprocess_output, "%s", self->token_pretext->str);
718
 
 exit:
719
 
  if (tok == LL_PRAGMA)
720
 
    {
721
 
      gpointer dummy;
722
 
 
723
 
      if (self->preprocess_output)
724
 
        fprintf(self->preprocess_output, "@");
725
 
      if (!cfg_parser_parse(&pragma_parser, self, &dummy, NULL))
726
 
        {
727
 
          return LL_ERROR;
728
 
        }
729
 
      goto relex;
730
 
    }
731
 
  else if (tok == KW_INCLUDE && cfg_lexer_get_context_type(self) != LL_CONTEXT_PRAGMA)
732
 
    {
733
 
      gchar *include_file;
734
 
 
735
 
      self->preprocess_suppress_tokens++;
736
 
      tok = cfg_lexer_lex(self, yylval, yylloc);
737
 
      if (tok != LL_STRING && tok != LL_IDENTIFIER)
738
 
        {
739
 
          self->preprocess_suppress_tokens--;
740
 
          return LL_ERROR;
741
 
        }
742
 
 
743
 
      include_file = g_strdup(yylval->cptr);
744
 
      free(yylval->cptr);
745
 
 
746
 
      tok = cfg_lexer_lex(self, yylval, yylloc);
747
 
      if (tok != ';')
748
 
        {
749
 
          self->preprocess_suppress_tokens--;
750
 
          return LL_ERROR;
751
 
        }
752
 
 
753
 
      if (!cfg_lexer_include_file(self, include_file))
754
 
        {
755
 
          self->preprocess_suppress_tokens--;
756
 
          return LL_ERROR;
757
 
        }
758
 
      self->preprocess_suppress_tokens--;
759
 
      goto relex;
760
 
    }
761
 
  else if (tok == LL_IDENTIFIER && (gen = cfg_lexer_find_generator(self, cfg_lexer_get_context_type(self), yylval->cptr)))
762
 
    {
763
 
      CfgArgs *args;
764
 
 
765
 
      self->preprocess_suppress_tokens++;
766
 
      if (cfg_parser_parse(&block_ref_parser, self, (gpointer *) &args, NULL))
767
 
        {
768
 
          gboolean success;
769
 
 
770
 
          self->preprocess_suppress_tokens--;
771
 
          success = cfg_lexer_generate_block(self, cfg_lexer_get_context_type(self), yylval->cptr, gen, args);
772
 
          cfg_args_free(args);
773
 
          if (success)
774
 
            {
775
 
              goto relex;
776
 
            }
777
 
        }
778
 
      else
779
 
        {
780
 
          self->preprocess_suppress_tokens--;
781
 
        }
782
 
      return LL_ERROR;
783
 
    }
784
 
  else if (configuration->version == 0 && configuration->parsed_version != 0)
785
 
    {
786
 
      cfg_set_version(configuration, configuration->parsed_version);
787
 
    }
788
 
  else if (configuration->version == 0 && configuration->parsed_version == 0 && cfg_lexer_get_context_type(self) != LL_CONTEXT_PRAGMA)
789
 
    {
790
 
      /* no version selected yet, and we have a non-pragma token, this
791
 
      * means that the configuration is meant for syslog-ng 2.1 */
792
 
 
793
 
      msg_warning("WARNING: Configuration file has no version number, assuming syslog-ng 2.1 format. Please add @version: maj.min to the beginning of the file",
794
 
                  NULL);
795
 
      cfg_set_version(configuration, 0x0201);
796
 
    }
797
 
 
798
 
  if (!injected)
799
 
    {
800
 
      if (self->preprocess_suppress_tokens == 0)
801
 
        {
802
 
          if (self->preprocess_output)
803
 
            fprintf(self->preprocess_output, "%s", self->token_text->str);
804
 
        }
805
 
    }
806
 
  return tok;
807
 
}
808
 
 
809
 
static void
810
 
cfg_lexer_init(CfgLexer *self)
811
 
{
812
 
  self->globals = cfg_args_new();
813
 
  CfgIncludeLevel *level;
814
 
 
815
 
  _cfg_lexer_lex_init_extra(self, &self->state);
816
 
  self->string_buffer = g_string_sized_new(32);
817
 
  self->token_text = g_string_sized_new(32);
818
 
  self->token_pretext = g_string_sized_new(32);
819
 
 
820
 
  level = &self->include_stack[0];
821
 
  level->lloc.first_line = level->lloc.last_line = 1;
822
 
  level->lloc.first_column = level->lloc.last_column = 1;
823
 
  level->lloc.level = level;
824
 
}
825
 
 
826
 
CfgLexer *
827
 
cfg_lexer_new(FILE *file, const gchar *filename, const gchar *preprocess_into)
828
 
{
829
 
  CfgLexer *self;
830
 
  CfgIncludeLevel *level;
831
 
 
832
 
  self = g_new0(CfgLexer, 1);
833
 
  cfg_lexer_init(self);
834
 
 
835
 
  if (preprocess_into)
836
 
    {
837
 
      self->preprocess_output = fopen(preprocess_into, "w");
838
 
    }
839
 
 
840
 
  level = &self->include_stack[0];
841
 
  level->include_type = CFGI_FILE;
842
 
  level->name = g_strdup(filename);
843
 
  level->yybuf = _cfg_lexer__create_buffer(file, YY_BUF_SIZE, self->state);
844
 
  _cfg_lexer__switch_to_buffer(level->yybuf, self->state);
845
 
 
846
 
  return self;
847
 
}
848
 
 
849
 
CfgLexer *
850
 
cfg_lexer_new_buffer(const gchar *buffer, gsize length)
851
 
{
852
 
  CfgLexer *self;
853
 
  CfgIncludeLevel *level;
854
 
 
855
 
  self = g_new0(CfgLexer, 1);
856
 
  cfg_lexer_init(self);
857
 
 
858
 
  level = &self->include_stack[0];
859
 
  level->include_type = CFGI_BUFFER;
860
 
  level->buffer.content = g_malloc(length + 2);
861
 
  memcpy(level->buffer.content, buffer, length);
862
 
  level->buffer.content[length] = 0;
863
 
  level->buffer.content[length + 1] = 0;
864
 
  level->buffer.content_length = length + 2;
865
 
  level->name = g_strdup("<string>");
866
 
  level->yybuf = _cfg_lexer__scan_buffer(level->buffer.content, level->buffer.content_length, self->state);
867
 
  _cfg_lexer__switch_to_buffer(level->yybuf, self->state);
868
 
 
869
 
  return self;
870
 
}
871
 
 
872
 
void
873
 
cfg_lexer_free(CfgLexer *self)
874
 
{
875
 
  gint i;
876
 
 
877
 
  for (i = 0; i <= self->include_depth; i++)
878
 
    {
879
 
      CfgIncludeLevel *level = &self->include_stack[i];
880
 
 
881
 
      g_free(level->name);
882
 
      if (level->yybuf)
883
 
        _cfg_lexer__delete_buffer(level->yybuf, self->state);
884
 
 
885
 
      if (level->include_type == CFGI_FILE)
886
 
        {
887
 
          if (level->file.include_file)
888
 
            fclose(level->file.include_file);
889
 
          g_slist_foreach(level->file.files, (GFunc) g_free, NULL);
890
 
          g_slist_free(level->file.files);
891
 
        }
892
 
      else if (level->include_type == CFGI_BUFFER)
893
 
        {
894
 
          g_free(level->buffer.content);
895
 
        }
896
 
    }
897
 
  self->include_depth = 0;
898
 
  _cfg_lexer_lex_destroy(self->state);
899
 
  g_string_free(self->string_buffer, TRUE);
900
 
  if (self->token_text)
901
 
    g_string_free(self->token_text, TRUE);
902
 
  if (self->token_pretext)
903
 
    g_string_free(self->token_pretext, TRUE);
904
 
  if (self->preprocess_output)
905
 
    fclose(self->preprocess_output);
906
 
 
907
 
  while (self->context_stack)
908
 
    cfg_lexer_pop_context(self);
909
 
  while (self->generators)
910
 
    {
911
 
      CfgBlockGenerator *gen = self->generators->data;
912
 
 
913
 
      if (gen->generator_data && gen->generator_data_free)
914
 
        gen->generator_data_free(gen->generator_data);
915
 
      g_free(gen->name);
916
 
      g_free(gen);
917
 
      self->generators = g_list_remove_link(self->generators, self->generators);
918
 
    }
919
 
  cfg_args_free(self->globals);
920
 
  g_list_foreach(self->token_blocks, (GFunc) cfg_token_block_free, NULL);
921
 
  g_list_free(self->token_blocks);
922
 
  g_free(self);
923
 
}
924
 
 
925
 
static const gchar *lexer_contexts[] =
926
 
{
927
 
  [LL_CONTEXT_ROOT] = "root",
928
 
  [LL_CONTEXT_DESTINATION] = "destination",
929
 
  [LL_CONTEXT_SOURCE] = "source",
930
 
  [LL_CONTEXT_PARSER] = "parser",
931
 
  [LL_CONTEXT_REWRITE] = "rewrite",
932
 
  [LL_CONTEXT_FILTER] = "filter",
933
 
  [LL_CONTEXT_LOG] = "log",
934
 
  [LL_CONTEXT_BLOCK_DEF] = "block-def",
935
 
  [LL_CONTEXT_BLOCK_REF] = "block-ref",
936
 
  [LL_CONTEXT_BLOCK_CONTENT] = "block-content",
937
 
  [LL_CONTEXT_PRAGMA] = "pragma",
938
 
  [LL_CONTEXT_FORMAT] = "format",
939
 
  [LL_CONTEXT_TEMPLATE_FUNC] = "template-func",
940
 
  [LL_CONTEXT_INNER_DEST] = "inner-dest",
941
 
  [LL_CONTEXT_INNER_SRC] = "inner-src",
942
 
};
943
 
 
944
 
gint
945
 
cfg_lexer_lookup_context_type_by_name(const gchar *name)
946
 
{
947
 
  gint i;
948
 
 
949
 
  for (i = 0; i < G_N_ELEMENTS(lexer_contexts); i++)
950
 
    {
951
 
      if (lexer_contexts[i] && strcmp(lexer_contexts[i], name) == 0)
952
 
        return i;
953
 
    }
954
 
  return 0;
955
 
}
956
 
 
957
 
const gchar *
958
 
cfg_lexer_lookup_context_name_by_type(gint type)
959
 
{
960
 
  g_assert(type < G_N_ELEMENTS(lexer_contexts));
961
 
  return lexer_contexts[type];
962
 
}
963
 
 
964
 
/* token block args */
965
 
 
966
 
static void
967
 
cfg_args_validate_callback(gpointer k, gpointer v, gpointer user_data)
968
 
{
969
 
  CfgArgs *defs = ((gpointer *) user_data)[0];
970
 
  gchar **bad_key = (gchar **) &((gpointer *) user_data)[1];
971
 
  gchar **bad_value = (gchar **) &((gpointer *) user_data)[2];
972
 
 
973
 
  if ((*bad_key == NULL) && (!defs || cfg_args_get(defs, k) == NULL))
974
 
    {
975
 
      *bad_key = k;
976
 
      *bad_value = v;
977
 
    }
978
 
}
979
 
 
980
 
gboolean
981
 
cfg_args_validate(CfgArgs *self, CfgArgs *defs, const gchar *context)
982
 
{
983
 
  gpointer validate_params[] = { defs, NULL, NULL };
984
 
 
985
 
  g_hash_table_foreach(self->args, cfg_args_validate_callback, validate_params);
986
 
 
987
 
  if (validate_params[1])
988
 
    {
989
 
      msg_error("Unknown argument",
990
 
                evt_tag_str("context", context),
991
 
                evt_tag_str("arg", validate_params[1]),
992
 
                evt_tag_str("value", validate_params[2]),
993
 
                NULL);
994
 
      return FALSE;
995
 
    }
996
 
  return TRUE;
997
 
}
998
 
 
999
 
void
1000
 
cfg_args_set(CfgArgs *self, const gchar *name, const gchar *value)
1001
 
{
1002
 
  g_hash_table_insert(self->args, g_strdup(name), g_strdup(value));
1003
 
}
1004
 
 
1005
 
const gchar *
1006
 
cfg_args_get(CfgArgs *self, const gchar *name)
1007
 
{
1008
 
  return g_hash_table_lookup(self->args, name);
1009
 
}
1010
 
 
1011
 
CfgArgs *
1012
 
cfg_args_new(void)
1013
 
{
1014
 
  CfgArgs *self = g_new0(CfgArgs, 1);
1015
 
 
1016
 
  self->args = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
1017
 
  return self;
1018
 
}
1019
 
 
1020
 
void
1021
 
cfg_args_free(CfgArgs *self)
1022
 
{
1023
 
  g_hash_table_destroy(self->args);
1024
 
  g_free(self);
1025
 
}
1026
 
 
1027
 
/* token blocks */
1028
 
 
1029
 
void
1030
 
cfg_token_block_add_token(CfgTokenBlock *self, YYSTYPE *token)
1031
 
{
1032
 
  g_assert(self->pos == 0);
1033
 
  g_array_append_val(self->tokens, *token);
1034
 
}
1035
 
 
1036
 
YYSTYPE *
1037
 
cfg_token_block_get_token(CfgTokenBlock *self)
1038
 
{
1039
 
  if (self->pos < self->tokens->len)
1040
 
    {
1041
 
      YYSTYPE *result;
1042
 
 
1043
 
      result = &g_array_index(self->tokens, YYSTYPE, self->pos);
1044
 
      self->pos++;
1045
 
      return result;
1046
 
    }
1047
 
  return NULL;
1048
 
}
1049
 
 
1050
 
CfgTokenBlock *
1051
 
cfg_token_block_new()
1052
 
{
1053
 
  CfgTokenBlock *self = g_new0(CfgTokenBlock, 1);
1054
 
 
1055
 
  self->tokens = g_array_new(FALSE, TRUE, sizeof(YYSTYPE));
1056
 
  return self;
1057
 
}
1058
 
 
1059
 
void
1060
 
cfg_token_block_free(CfgTokenBlock *self)
1061
 
{
1062
 
  gint i;
1063
 
 
1064
 
  for (i = 0; i < self->tokens->len; i++)
1065
 
    {
1066
 
      YYSTYPE *token = &g_array_index(self->tokens, YYSTYPE, i);
1067
 
 
1068
 
      if (token->type == LL_STRING || token->type == LL_IDENTIFIER)
1069
 
        g_free(token->cptr);
1070
 
 
1071
 
    }
1072
 
  g_array_free(self->tokens, TRUE);
1073
 
  g_free(self);
1074
 
}
1075
 
 
1076
 
/* user defined blocks */
1077
 
 
1078
 
/*
1079
 
 * This class encapsulates a configuration block that the user defined
1080
 
 * via the configuration file. It behaves like a macro, e.g. when
1081
 
 * referenced the content of the block is expanded.
1082
 
 *
1083
 
 * Each block is identified by its name and the context (source,
1084
 
 * destination, etc.) where it is meant to be used.
1085
 
 *
1086
 
 * A block has a set of name-value pairs to allow expansion to be
1087
 
 * parameterized. The set of allowed NV pairs is defined at block
1088
 
 * definition time
1089
 
 */
1090
 
struct _CfgBlock
1091
 
{
1092
 
  gchar *content;
1093
 
  CfgArgs *arg_defs;
1094
 
};
1095
 
 
1096
 
/*
1097
 
 * cfg_block_generate:
1098
 
 *
1099
 
 * This is a CfgBlockGeneratorFunc, which takes a CfgBlock defined by
1100
 
 * the user, substitutes backtick values and generates input tokens
1101
 
 * for the lexer.
1102
 
 */
1103
 
gboolean
1104
 
cfg_block_generate(CfgLexer *lexer, gint context, const gchar *name, CfgArgs *args, gpointer user_data)
1105
 
{
1106
 
  CfgBlock *block = (CfgBlock *) user_data;
1107
 
  gchar *value;
1108
 
  gchar buf[256];
1109
 
  gsize length;
1110
 
 
1111
 
  g_snprintf(buf, sizeof(buf), "%s block %s", cfg_lexer_lookup_context_name_by_type(context), name);
1112
 
  if (!cfg_args_validate(args, block->arg_defs, buf))
1113
 
    {
1114
 
      return FALSE;
1115
 
    }
1116
 
 
1117
 
  value = cfg_lexer_subst_args(lexer->globals, block->arg_defs, args, block->content, &length);
1118
 
 
1119
 
  if (!value)
1120
 
    {
1121
 
      msg_warning("Syntax error while resolving backtick references in block, missing closing '`' character",
1122
 
                  evt_tag_str("context", cfg_lexer_lookup_context_name_by_type(context)),
1123
 
                  evt_tag_str("block", name),
1124
 
                  NULL);
1125
 
      return FALSE;
1126
 
    }
1127
 
 
1128
 
  return cfg_lexer_include_buffer(lexer, buf, value, length);
1129
 
}
1130
 
 
1131
 
/*
1132
 
 * Construct a user defined block.
1133
 
 */
1134
 
CfgBlock *
1135
 
cfg_block_new(const gchar *content, CfgArgs *arg_defs)
1136
 
{
1137
 
  CfgBlock *self = g_new0(CfgBlock, 1);
1138
 
 
1139
 
  self->content = g_strdup(content);
1140
 
  self->arg_defs = arg_defs;
1141
 
  return self;
1142
 
}
1143
 
 
1144
 
/*
1145
 
 * Free a user defined block.
1146
 
 */
1147
 
void
1148
 
cfg_block_free(CfgBlock *self)
1149
 
{
1150
 
  g_free(self->content);
1151
 
  cfg_args_free(self->arg_defs);
1152
 
  g_free(self);
1153
 
}