Coverage Report

Created: 2024-02-29 06:05

/src/strongswan/src/libstrongswan/utils/parser_helper.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2014 Tobias Brunner
3
 *
4
 * Copyright (C) secunet Security Networks AG
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License as published by the
8
 * Free Software Foundation; either version 2 of the License, or (at your
9
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
10
 *
11
 * This program is distributed in the hope that it will be useful, but
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14
 * for more details.
15
 */
16
17
#include <limits.h>
18
#include <ctype.h>
19
#include <stdarg.h>
20
#include <sys/types.h>
21
#include <sys/stat.h>
22
23
#include "parser_helper.h"
24
25
#include <collections/array.h>
26
27
typedef struct private_parser_helper_t private_parser_helper_t;
28
typedef struct parser_helper_file_t parser_helper_file_t;
29
30
struct private_parser_helper_t {
31
32
  /**
33
   * Public interface.
34
   */
35
  parser_helper_t public;
36
37
  /**
38
   * Stack of included files, as parser_helper_file_t.
39
   */
40
  array_t *files;
41
42
  /**
43
   * Helper for parsing strings.
44
   */
45
  bio_writer_t *writer;
46
};
47
48
struct parser_helper_file_t {
49
50
  /**
51
   * File name
52
   */
53
  char *name;
54
55
  /**
56
   * File stream
57
   */
58
  FILE *file;
59
60
  /**
61
   * Enumerator of paths matching the most recent inclusion pattern.
62
   */
63
  enumerator_t *matches;
64
};
65
66
/**
67
 * Destroy the given file data.
68
 */
69
static void parser_helper_file_destroy(parser_helper_file_t *this)
70
3.92k
{
71
3.92k
  if (this->file)
72
0
  {
73
0
    fclose(this->file);
74
0
  }
75
3.92k
  free(this->name);
76
3.92k
  DESTROY_IF(this->matches);
77
3.92k
  free(this);
78
3.92k
}
79
80
/**
81
 * Returns the current file, if any.
82
 */
83
static parser_helper_file_t *current_file(private_parser_helper_t *this)
84
0
{
85
0
  parser_helper_file_t *file;
86
87
0
  array_get(this->files, ARRAY_TAIL, &file);
88
0
  if (file->name)
89
0
  {
90
0
    return file;
91
0
  }
92
0
  return NULL;
93
0
}
94
95
METHOD(parser_helper_t, file_next, FILE*,
96
  private_parser_helper_t *this)
97
3.92k
{
98
3.92k
  parser_helper_file_t *file, *next;
99
3.92k
  struct stat st;
100
3.92k
  char *name;
101
102
3.92k
  array_get(this->files, ARRAY_TAIL, &file);
103
3.92k
  if (!file->matches && file->name)
104
0
  {
105
0
    array_remove(this->files, ARRAY_TAIL, NULL);
106
0
    parser_helper_file_destroy(file);
107
    /* continue with previous includes, if any */
108
0
    array_get(this->files, ARRAY_TAIL, &file);
109
0
  }
110
3.92k
  if (file->matches)
111
3.92k
  {
112
3.92k
    while (file->matches->enumerate(file->matches, &name, NULL))
113
0
    {
114
0
      INIT(next,
115
0
        .name = strdup(name),
116
0
        .file = fopen(name, "r"),
117
0
      );
118
119
0
      if (next->file && fstat(fileno(next->file), &st) == 0 &&
120
0
        S_ISREG(st.st_mode))
121
0
      {
122
0
        array_insert(this->files, ARRAY_TAIL, next);
123
0
        return next->file;
124
0
      }
125
0
      PARSER_DBG2(&this->public, "unable to open '%s'", name);
126
0
      parser_helper_file_destroy(next);
127
0
    }
128
3.92k
    file->matches->destroy(file->matches);
129
3.92k
    file->matches = NULL;
130
3.92k
  }
131
3.92k
  return NULL;
132
3.92k
}
133
134
METHOD(parser_helper_t, file_include, void,
135
  private_parser_helper_t *this, char *pattern)
136
3.92k
{
137
3.92k
  parser_helper_file_t *file;
138
3.92k
  char pat[PATH_MAX];
139
140
3.92k
  array_get(this->files, ARRAY_TAIL, &file);
141
3.92k
  if (!pattern || !*pattern)
142
0
  {
143
0
    PARSER_DBG1(&this->public, "no include pattern specified, ignored");
144
0
    file->matches = enumerator_create_empty();
145
0
    return;
146
0
  }
147
148
3.92k
  if (!file->name || path_absolute(pattern))
149
3.92k
  { /* absolute path */
150
3.92k
    if (snprintf(pat, sizeof(pat), "%s", pattern) >= sizeof(pat))
151
0
    {
152
0
      PARSER_DBG1(&this->public, "include pattern too long, ignored");
153
0
      file->matches = enumerator_create_empty();
154
0
      return;
155
0
    }
156
3.92k
  }
157
0
  else
158
0
  { /* base relative paths to the directory of the current file */
159
0
    char *dir = path_dirname(file->name);
160
0
    if (snprintf(pat, sizeof(pat), "%s%s%s", dir, DIRECTORY_SEPARATOR,
161
0
           pattern) >= sizeof(pat))
162
0
    {
163
0
      PARSER_DBG1(&this->public, "include pattern too long, ignored");
164
0
      free(dir);
165
0
      file->matches = enumerator_create_empty();
166
0
      return;
167
0
    }
168
0
    free(dir);
169
0
  }
170
171
3.92k
  file->matches = enumerator_create_glob(pat);
172
3.92k
  if (!file->matches)
173
0
  { /* if glob(3) is not available, try to load pattern directly */
174
0
    file->matches = enumerator_create_single(strdup(pat), free);
175
0
  }
176
3.92k
}
177
178
METHOD(parser_helper_t, string_init, void,
179
  private_parser_helper_t *this)
180
0
{
181
0
  chunk_t data;
182
183
0
  data = this->writer->extract_buf(this->writer);
184
0
  chunk_free(&data);
185
0
}
186
187
METHOD(parser_helper_t, string_add, void,
188
  private_parser_helper_t *this, char *str)
189
0
{
190
0
  this->writer->write_data(this->writer, chunk_from_str(str));
191
0
}
192
193
METHOD(parser_helper_t, string_get, char*,
194
  private_parser_helper_t *this)
195
0
{
196
0
  chunk_t data;
197
198
0
  this->writer->write_data(this->writer, chunk_from_chars('\0'));
199
0
  data = this->writer->extract_buf(this->writer);
200
0
  return data.ptr;
201
0
}
202
203
METHOD(parser_helper_t, destroy, void,
204
  private_parser_helper_t *this)
205
3.92k
{
206
3.92k
  array_destroy_function(this->files, (void*)parser_helper_file_destroy, NULL);
207
3.92k
  this->writer->destroy(this->writer);
208
3.92k
  free(this);
209
3.92k
}
210
211
/**
212
 * Described in header
213
 */
214
void parser_helper_log(int level, parser_helper_t *ctx, char *fmt, ...)
215
0
{
216
0
  private_parser_helper_t *this = (private_parser_helper_t*)ctx;
217
0
  parser_helper_file_t *file;
218
0
  char msg[8192];
219
0
  va_list args;
220
0
  int line;
221
222
0
  va_start(args, fmt);
223
0
  vsnprintf(msg, sizeof(msg), fmt, args);
224
0
  va_end(args);
225
226
0
  file = current_file(this);
227
0
  line = ctx->get_lineno ? ctx->get_lineno(ctx->scanner) : 0;
228
0
  if (file)
229
0
  {
230
0
    dbg(DBG_CFG, level, "%s:%d: %s", file->name, line, msg);
231
0
  }
232
0
  else
233
0
  {
234
0
    dbg(DBG_CFG, level, "%s", msg);
235
0
  }
236
0
}
237
238
/**
239
 * Described in header
240
 */
241
parser_helper_t *parser_helper_create(void *context)
242
3.92k
{
243
3.92k
  private_parser_helper_t *this;
244
3.92k
  parser_helper_file_t *sentinel;
245
246
3.92k
  INIT(this,
247
3.92k
    .public = {
248
3.92k
      .context = context,
249
3.92k
      .file_include = _file_include,
250
3.92k
      .file_next = _file_next,
251
3.92k
      .string_init = _string_init,
252
3.92k
      .string_add = _string_add,
253
3.92k
      .string_get = _string_get,
254
3.92k
      .destroy = _destroy,
255
3.92k
    },
256
3.92k
    .files = array_create(0, 0),
257
3.92k
    .writer = bio_writer_create(0),
258
3.92k
  );
259
260
3.92k
  INIT(sentinel,
261
3.92k
    .name = NULL,
262
3.92k
  );
263
3.92k
  array_insert(this->files, ARRAY_TAIL, sentinel);
264
265
3.92k
  return &this->public;
266
3.92k
}