1 /***********************************************************************
5 * Code for parsing options out of configuration file.
7 * Copyright (C) 2002 by Roaring Penguin Software Inc.
9 * This software may be distributed under the terms of the GNU General
10 * Public License, Version 2, or (at your option) any later version.
14 ***********************************************************************/
16 static char const RCSID
[] =
17 "$Id: options.c,v 1.1.48.1 2005/08/08 12:05:25 honor Exp $";
27 l2tp_settings Settings
;
29 static option_handler
*option_handlers
= NULL
;
31 /* Function for currently-active option context */
32 static int (*option_context_fn
)(EventSelector
*es
,
33 char const *name
, char const *value
);
34 static int do_load_handler(EventSelector
*es
,
35 l2tp_opt_descriptor
*desc
, char const *value
);
36 static int set_option(EventSelector
*es
,
37 l2tp_opt_descriptor
*desc
, char const *value
);
40 static l2tp_opt_descriptor global_opts
[] = {
42 { "load-handler", OPT_TYPE_CALLFUNC
, (void *) do_load_handler
},
43 { "listen-port", OPT_TYPE_PORT
, &Settings
.listen_port
},
44 { "listen-addr", OPT_TYPE_IPADDR
, &Settings
.listen_addr
},
45 { NULL
, OPT_TYPE_BOOL
, NULL
}
48 /**********************************************************************
49 * %FUNCTION: do_load_handler
51 * es -- event selector
52 * desc -- option descriptor
53 * value -- name of handler to load
55 * 0 on success, -1 on failure
57 * Loads a DLL as a handler
58 ***********************************************************************/
60 do_load_handler(EventSelector
*es
,
61 l2tp_opt_descriptor
*desc
,
64 return l2tp_load_handler(es
, value
);
67 /**********************************************************************
68 * %FUNCTION: set_option
70 * es -- event selector
71 * desc -- option descriptor
72 * value -- value string parsed from config file
74 * -1 on error, 0 if all is OK
76 * Sets an option value.
77 ***********************************************************************/
79 set_option(EventSelector
*es
,
80 l2tp_opt_descriptor
*desc
,
86 int (*fn
)(EventSelector
*, l2tp_opt_descriptor
*, char const *);
90 if (!strcasecmp(value
, "true") ||
91 !strcasecmp(value
, "yes") ||
92 !strcasecmp(value
, "on") ||
93 !strcasecmp(value
, "1")) {
94 * (int *) (desc
->addr
) = 1;
97 if (!strcasecmp(value
, "false") ||
98 !strcasecmp(value
, "no") ||
99 !strcasecmp(value
, "off") ||
100 !strcasecmp(value
, "0")) {
101 * (int *) (desc
->addr
) = 0;
104 l2tp_set_errmsg("Expecting boolean value, found '%s'", value
);
109 x
= strtol(value
, &end
, 0);
111 l2tp_set_errmsg("Expecting integer value, found '%s'", value
);
114 if (desc
->type
== OPT_TYPE_PORT
) {
115 if (x
< 1 || x
> 65535) {
116 l2tp_set_errmsg("Port values must range from 1 to 65535");
121 * (int *) desc
->addr
= (int) x
;
124 case OPT_TYPE_IPADDR
:
125 he
= gethostbyname(value
);
127 l2tp_set_errmsg("Could not resolve %s as IP address: %s",
128 value
, strerror(errno
));
132 memcpy(desc
->addr
, he
->h_addr
, sizeof(he
->h_addr
));
135 case OPT_TYPE_STRING
:
136 if (* (char **) desc
->addr
) {
137 free(* (char **) desc
->addr
);
139 * (char **) desc
->addr
= strdup(value
);
140 if (! * (char *) desc
->addr
) {
141 l2tp_set_errmsg("Out of memory");
146 case OPT_TYPE_CALLFUNC
:
147 fn
= (int (*)(EventSelector
*, l2tp_opt_descriptor
*, char const *)) desc
->addr
;
148 return fn(es
, desc
, value
);
150 l2tp_set_errmsg("Unknown value type %d", desc
->type
);
154 /**********************************************************************
155 * %FUNCTION: chomp_word
157 * line -- the input line
158 * word -- buffer for storing word
160 * Updated value of line
162 * Chomps a word from line
163 ***********************************************************************/
165 l2tp_chomp_word(char const *line
, char *word
)
169 /* Chew up whitespace */
170 while(*line
&& isspace(*line
)) line
++;
173 /* Not quoted string */
174 while (*line
&& !isspace(*line
)) {
194 if (*line
) *word
++ = *line
++;
200 /**********************************************************************
201 * %FUNCTION: split_line_into_words
203 * line -- the input line
204 * name, value -- buffers which are large enough to contain all chars in line
208 * Splits line into two words. A word is:
209 * - Non-whitespace chars: foobarbazblech_3
210 * - Quoted text: "Here is text \"with embedded quotes\""
211 ***********************************************************************/
213 split_line_into_words(char const *line
, char *name
, char *value
)
215 line
= l2tp_chomp_word(line
, name
);
216 line
= l2tp_chomp_word(line
, value
);
219 /**********************************************************************
220 * %FUNCTION: parser_switch_context
222 * name, value -- words read from line. Either "global ..ignored.."
223 * or "section context"
225 * 0 if context-switch proceeded OK, -1 if not.
227 * Switches configuration contexts
228 ***********************************************************************/
230 parser_switch_context(EventSelector
*es
,
235 option_handler
*handler
;
237 /* Switch out of old context */
238 if (option_context_fn
) {
239 r
= option_context_fn(es
, "*end*", "*end*");
240 option_context_fn
= NULL
;
244 if (!strcasecmp(name
, "global")) {
248 /* Must be "section foo" */
249 handler
= option_handlers
;
251 if (!strcasecmp(value
, handler
->section
)) {
252 option_context_fn
= handler
->process_option
;
253 option_context_fn(es
, "*begin*", "*begin*");
256 handler
= handler
->next
;
258 l2tp_set_errmsg("No handler for section %s", value
);
262 /**********************************************************************
263 * %FUNCTION: option_set
265 * es -- event selector
266 * name -- name of option
267 * value -- value of option
268 * descriptors -- array of option descriptors for this context
270 * 0 on success, -1 on failure
273 ***********************************************************************/
275 l2tp_option_set(EventSelector
*es
,
278 l2tp_opt_descriptor descriptors
[])
282 for (i
=0; descriptors
[i
].name
; i
++) {
283 if (!strcasecmp(descriptors
[i
].name
, name
)) {
284 return set_option(es
, &descriptors
[i
], value
);
287 l2tp_set_errmsg("Option %s is not known in this context",
292 /**********************************************************************
293 * %FUNCTION: option_register_section
295 * handler -- an option-handler
299 * Adds handler to linked-list of sections.
300 ***********************************************************************/
302 l2tp_option_register_section(option_handler
*h
)
304 h
->next
= option_handlers
;
308 /**********************************************************************
309 * %FUNCTION: handle_option
311 * es -- event selector
312 * name -- name of option
313 * value -- option's value
315 * 0 on success, -1 on failure
318 ***********************************************************************/
320 handle_option(EventSelector
*es
,
324 if (option_context_fn
) {
325 return option_context_fn(es
, name
, value
);
328 return l2tp_option_set(es
, name
, value
, global_opts
);
331 /**********************************************************************
332 * %FUNCTION: parse_config_file
334 * es -- event selector
335 * fname -- filename to parse
337 * -1 on error, 0 if all is OK
339 * Parses configuration file.
340 ***********************************************************************/
342 l2tp_parse_config_file(EventSelector
*es
,
354 Settings
.listen_port
= 1701;
355 Settings
.listen_addr
.s_addr
= htonl(INADDR_ANY
);
357 fp
= fopen(fname
, "r");
359 l2tp_set_errmsg("Could not open '%s' for reading: %s",
360 fname
, strerror(errno
));
364 /* Start in global context */
365 option_context_fn
= NULL
;
366 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
368 if (l
&& (buf
[l
] == '\n')) {
372 /* Skip leading whitespace */
374 while(*line
&& isspace(*line
)) line
++;
376 /* Ignore blank lines and comments */
377 if (!*line
|| *line
== '#') {
381 /* Split line into two words */
382 split_line_into_words(line
, name
, value
);
384 /* Check for context switch */
385 if (!strcasecmp(name
, "global") ||
386 !strcasecmp(name
, "section")) {
387 r
= parser_switch_context(es
, name
, value
);
392 r
= handle_option(es
, name
, value
);
397 if (option_context_fn
) {
398 r
= option_context_fn(es
, "*end*", "*end*");
399 option_context_fn
= NULL
;