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