settings: Reduce log verbosity if files can't be opened
[strongswan.git] / src / libstrongswan / settings / settings_parser.y
1 %{
2 /*
3  * Copyright (C) 2014 Tobias Brunner
4  * Hochschule fuer Technik Rapperswil
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 #define _GNU_SOURCE /* for asprintf() */
18 #include <stdio.h>
19
20 #include "settings_parser.h"
21
22 #include <library.h>
23 #include <collections/array.h>
24 #include <settings/settings_types.h>
25 #include <utils/parser_helper.h>
26
27 #define YYDEBUG 1
28
29 /**
30  * Defined by the lexer
31  */
32 int settings_parser_lex(YYSTYPE *lvalp, void *scanner);
33 int settings_parser_lex_init_extra(parser_helper_t *extra, void *scanner);
34 int settings_parser_lex_destroy(void *scanner);
35 int settings_parser_set_in(FILE *in, void *scanner);
36 void settings_parser_set_debug(int debug, void *scanner);
37 char *settings_parser_get_text(void *scanner);
38 int settings_parser_get_leng(void *scanner);
39 int settings_parser_get_lineno(void *scanner);
40 /* Custom functions in lexer */
41 bool settings_parser_open_next_file(parser_helper_t *ctx);
42
43 /**
44  * Forward declarations
45  */
46 static void settings_parser_error(parser_helper_t *ctx, const char *s);
47 static section_t *push_section(parser_helper_t *ctx, char *name);
48 static section_t *pop_section(parser_helper_t *ctx);
49 static void add_section(parser_helper_t *ctx, section_t *section);
50 static void add_setting(parser_helper_t *ctx, kv_t *kv);
51
52 /**
53  * Make sure the generated parser code passes the correct object to the lexer
54  */
55 #define YYLEX_PARAM ctx->scanner
56
57 %}
58 %debug
59
60 /* generate verbose error messages */
61 %error-verbose
62 /* generate a reentrant parser */
63 %define api.pure
64 /* prefix function/variable declarations */
65 %name-prefix "settings_parser_"
66
67 /* interact properly with the reentrant lexer */
68 %lex-param {void *scanner}
69 %parse-param {parser_helper_t *ctx}
70
71 /* types for terminal symbols... (can't use the typedef'd types) */
72 %union {
73         char *s;
74         struct section_t *sec;
75         struct kv_t *kv;
76 }
77 %token <s> NAME STRING
78 %token NEWLINE
79
80 /* ...and other symbols */
81 %type <s> value valuepart
82 %type <sec> section_start section
83 %type <kv> setting
84
85 /* properly destroy string tokens that are strdup()ed on error */
86 %destructor { free($$); } NAME STRING value valuepart
87 /* properly destroy parse results on error */
88 %destructor { pop_section(ctx); settings_section_destroy($$, NULL); } section_start section
89 %destructor { settings_kv_destroy($$, NULL); } setting
90
91 /* there are two shift/reduce conflicts because of the "NAME = NAME" and
92  * "NAME {" ambiguity, and the "NAME =" rule) */
93 %expect 2
94
95 %%
96
97 /**
98  * strongswan.conf grammar rules
99  */
100 statements:
101         /* empty */
102         | statements NEWLINE
103         | statements statement
104         ;
105
106 statement:
107         section
108         {
109                 add_section(ctx, $section);
110         }
111         | setting
112         {
113                 add_setting(ctx, $setting);
114         }
115         ;
116
117 section:
118         section_start statements '}'
119         {
120                 pop_section(ctx);
121                 $$ = $section_start;
122         }
123         ;
124
125 section_start:
126         NAME '{'
127         {
128                 $$ = push_section(ctx, $NAME);
129         }
130         |
131         NAME NEWLINE '{'
132         {
133                 $$ = push_section(ctx, $NAME);
134         }
135         ;
136
137 setting:
138         NAME '=' value
139         {
140                 $$ = settings_kv_create($NAME, $value);
141         }
142         |
143         NAME '='
144         {
145                 $$ = settings_kv_create($NAME, NULL);
146         }
147         ;
148
149 value:
150         valuepart
151         | value valuepart
152         {       /* just put a single space between them, use strings for more */
153                 if (asprintf(&$$, "%s %s", $1, $2) < 0)
154                 {
155                         free($1);
156                         free($2);
157                         YYERROR;
158                 }
159                 free($1);
160                 free($2);
161         }
162         ;
163
164 valuepart:
165         NAME
166         | STRING
167         ;
168
169 %%
170
171 /**
172  * Referenced by the generated parser
173  */
174 static void settings_parser_error(parser_helper_t *ctx, const char *s)
175 {
176         char *text = settings_parser_get_text(ctx->scanner);
177         int len = settings_parser_get_leng(ctx->scanner);
178
179         if (len && text[len-1] == '\n')
180         {       /* cut off newline at the end to avoid muti-line log messages */
181                 len--;
182         }
183         PARSER_DBG1(ctx, "%s [%.*s]", s, len, text);
184 }
185
186 /**
187  * Create a section and push it to the stack (the name is adopted), returns
188  * the created section
189  */
190 static section_t *push_section(parser_helper_t *ctx, char *name)
191 {
192         array_t *sections = (array_t*)ctx->context;
193         section_t *section;
194
195         section = settings_section_create(name);
196         array_insert(sections, ARRAY_TAIL, section);
197         return section;
198 }
199
200 /**
201  * Removes the top section of the stack and returns it
202  */
203 static section_t *pop_section(parser_helper_t *ctx)
204 {
205         array_t *sections = (array_t*)ctx->context;
206         section_t *section;
207
208         array_remove(sections, ARRAY_TAIL, &section);
209         return section;
210 }
211
212 /**
213  * Adds the given section to the section on top of the stack
214  */
215 static void add_section(parser_helper_t *ctx, section_t *section)
216 {
217         array_t *sections = (array_t*)ctx->context;
218         section_t *parent;
219
220         array_get(sections, ARRAY_TAIL, &parent);
221         settings_section_add(parent, section, NULL);
222 }
223
224 /**
225  * Adds the given key/value pair to the section on top of the stack
226  */
227 static void add_setting(parser_helper_t *ctx, kv_t *kv)
228 {
229         array_t *sections = (array_t*)ctx->context;
230         section_t *section;
231
232         array_get(sections, ARRAY_TAIL, &section);
233         settings_kv_add(section, kv, NULL);
234 }
235
236 /**
237  * Parse the given file and add all sections and key/value pairs to the
238  * given section.
239  */
240 bool settings_parser_parse_file(section_t *root, char *name)
241 {
242         parser_helper_t *helper;
243         array_t *sections = NULL;
244         bool success = FALSE;
245
246         array_insert_create(&sections, ARRAY_TAIL, root);
247         helper = parser_helper_create(sections);
248         helper->get_lineno = settings_parser_get_lineno;
249         if (settings_parser_lex_init_extra(helper, &helper->scanner) != 0)
250         {
251                 helper->destroy(helper);
252                 array_destroy(sections);
253                 return FALSE;
254         }
255         helper->file_include(helper, name);
256         if (!settings_parser_open_next_file(helper))
257         {
258 #ifdef STRONGSWAN_CONF
259                 if (streq(name, STRONGSWAN_CONF))
260                 {
261                         DBG2(DBG_CFG, "failed to open config file '%s'", name);
262                 }
263                 else
264 #endif
265                 {
266                         DBG1(DBG_CFG, "failed to open config file '%s'", name);
267                 }
268         }
269         else
270         {
271                 if (getenv("DEBUG_SETTINGS_PARSER"))
272                 {
273                         yydebug = 1;
274                         settings_parser_set_debug(1, helper->scanner);
275                 }
276                 success = yyparse(helper) == 0;
277                 if (!success)
278                 {
279                         DBG1(DBG_CFG, "invalid config file '%s'", name);
280                 }
281         }
282         array_destroy(sections);
283         settings_parser_lex_destroy(helper->scanner);
284         helper->destroy(helper);
285         return success;
286 }