usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src / router / rp-l2tp / options.c
blob44a778399290bbe89294e10c5c6a747536ff9fcc
1 /***********************************************************************
3 * options.c
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.
12 * LIC: GPL
14 ***********************************************************************/
16 static char const RCSID[] =
17 "$Id: options.c,v 1.1.48.1 2005/08/08 12:05:25 honor Exp $";
19 #include "l2tp.h"
20 #include <string.h>
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <netdb.h>
24 #include <stdio.h>
25 #include <ctype.h>
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);
39 /* Global options */
40 static l2tp_opt_descriptor global_opts[] = {
41 /* name type addr */
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
50 * %ARGUMENTS:
51 * es -- event selector
52 * desc -- option descriptor
53 * value -- name of handler to load
54 * %RETURNS:
55 * 0 on success, -1 on failure
56 * %DESCRIPTION:
57 * Loads a DLL as a handler
58 ***********************************************************************/
59 static int
60 do_load_handler(EventSelector *es,
61 l2tp_opt_descriptor *desc,
62 char const *value)
64 return l2tp_load_handler(es, value);
67 /**********************************************************************
68 * %FUNCTION: set_option
69 * %ARGUMENTS:
70 * es -- event selector
71 * desc -- option descriptor
72 * value -- value string parsed from config file
73 * %RETURNS:
74 * -1 on error, 0 if all is OK
75 * %DESCRIPTION:
76 * Sets an option value.
77 ***********************************************************************/
78 static int
79 set_option(EventSelector *es,
80 l2tp_opt_descriptor *desc,
81 char const *value)
83 long x;
84 char *end;
85 struct hostent *he;
86 int (*fn)(EventSelector *, l2tp_opt_descriptor *, char const *);
88 switch(desc->type) {
89 case OPT_TYPE_BOOL:
90 if (!strcasecmp(value, "true") ||
91 !strcasecmp(value, "yes") ||
92 !strcasecmp(value, "on") ||
93 !strcasecmp(value, "1")) {
94 * (int *) (desc->addr) = 1;
95 return 0;
97 if (!strcasecmp(value, "false") ||
98 !strcasecmp(value, "no") ||
99 !strcasecmp(value, "off") ||
100 !strcasecmp(value, "0")) {
101 * (int *) (desc->addr) = 0;
102 return 0;
104 l2tp_set_errmsg("Expecting boolean value, found '%s'", value);
105 return -1;
107 case OPT_TYPE_INT:
108 case OPT_TYPE_PORT:
109 x = strtol(value, &end, 0);
110 if (*end) {
111 l2tp_set_errmsg("Expecting integer value, found '%s'", value);
112 return -1;
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");
117 return -1;
121 * (int *) desc->addr = (int) x;
122 return 0;
124 case OPT_TYPE_IPADDR:
125 he = gethostbyname(value);
126 if (!he) {
127 l2tp_set_errmsg("Could not resolve %s as IP address: %s",
128 value, strerror(errno));
129 return -1;
132 memcpy(desc->addr, he->h_addr, sizeof(he->h_addr));
133 return 0;
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");
142 return -1;
144 return 0;
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);
151 return -1;
154 /**********************************************************************
155 * %FUNCTION: chomp_word
156 * %ARGUMENTS:
157 * line -- the input line
158 * word -- buffer for storing word
159 * %RETURNS:
160 * Updated value of line
161 * %DESCRIPTION:
162 * Chomps a word from line
163 ***********************************************************************/
164 char const *
165 l2tp_chomp_word(char const *line, char *word)
167 *word = 0;
169 /* Chew up whitespace */
170 while(*line && isspace(*line)) line++;
172 if (*line != '"') {
173 /* Not quoted string */
174 while (*line && !isspace(*line)) {
175 *word++ = *line++;
177 *word = 0;
178 return line;
181 /* Quoted string */
182 line++;
183 while(*line) {
184 if (*line != '\\') {
185 if (*line == '"') {
186 line++;
187 *word = 0;
188 return line;
190 *word++ = *line++;
191 continue;
193 line++;
194 if (*line) *word++ = *line++;
196 *word = 0;
197 return line;
200 /**********************************************************************
201 * %FUNCTION: split_line_into_words
202 * %ARGUMENTS:
203 * line -- the input line
204 * name, value -- buffers which are large enough to contain all chars in line
205 * %RETURNS:
206 * Nothing
207 * %DESCRIPTION:
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 ***********************************************************************/
212 static void
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
221 * %ARGUMENTS:
222 * name, value -- words read from line. Either "global ..ignored.."
223 * or "section context"
224 * %RETURNS:
225 * 0 if context-switch proceeded OK, -1 if not.
226 * %DESCRIPTION:
227 * Switches configuration contexts
228 ***********************************************************************/
229 static int
230 parser_switch_context(EventSelector *es,
231 char const *name,
232 char const *value)
234 int r;
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;
241 if (r < 0) return r;
244 if (!strcasecmp(name, "global")) {
245 return 0;
248 /* Must be "section foo" */
249 handler = option_handlers;
250 while(handler) {
251 if (!strcasecmp(value, handler->section)) {
252 option_context_fn = handler->process_option;
253 option_context_fn(es, "*begin*", "*begin*");
254 return 0;
256 handler = handler->next;
258 l2tp_set_errmsg("No handler for section %s", value);
259 return -1;
262 /**********************************************************************
263 * %FUNCTION: option_set
264 * %ARGUMENTS:
265 * es -- event selector
266 * name -- name of option
267 * value -- value of option
268 * descriptors -- array of option descriptors for this context
269 * %RETURNS:
270 * 0 on success, -1 on failure
271 * %DESCRIPTION:
272 * Sets an option
273 ***********************************************************************/
275 l2tp_option_set(EventSelector *es,
276 char const *name,
277 char const *value,
278 l2tp_opt_descriptor descriptors[])
280 int i;
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",
288 name);
289 return -1;
292 /**********************************************************************
293 * %FUNCTION: option_register_section
294 * %ARGUMENTS:
295 * handler -- an option-handler
296 * %RETURNS:
297 * Nothing
298 * %DESCRIPTION:
299 * Adds handler to linked-list of sections.
300 ***********************************************************************/
301 void
302 l2tp_option_register_section(option_handler *h)
304 h->next = option_handlers;
305 option_handlers = h;
308 /**********************************************************************
309 * %FUNCTION: handle_option
310 * %ARGUMENTS:
311 * es -- event selector
312 * name -- name of option
313 * value -- option's value
314 * %RETURNS:
315 * 0 on success, -1 on failure
316 * %DESCRIPTION:
317 * Handles an option
318 ***********************************************************************/
319 static int
320 handle_option(EventSelector *es,
321 char const *name,
322 char const *value)
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
333 * %ARGUMENTS:
334 * es -- event selector
335 * fname -- filename to parse
336 * %RETURNS:
337 * -1 on error, 0 if all is OK
338 * %DESCRIPTION:
339 * Parses configuration file.
340 ***********************************************************************/
342 l2tp_parse_config_file(EventSelector *es,
343 char const *fname)
345 char buf[512];
346 char name[512];
347 char value[512];
348 int r = 0;
349 size_t l;
350 char *line;
351 FILE *fp;
353 /* Defaults */
354 Settings.listen_port = 1701;
355 Settings.listen_addr.s_addr = htonl(INADDR_ANY);
357 fp = fopen(fname, "r");
358 if (!fp) {
359 l2tp_set_errmsg("Could not open '%s' for reading: %s",
360 fname, strerror(errno));
361 return -1;
364 /* Start in global context */
365 option_context_fn = NULL;
366 while (fgets(buf, sizeof(buf), fp) != NULL) {
367 l = strlen(buf);
368 if (l && (buf[l] == '\n')) {
369 buf[l--] = 0;
372 /* Skip leading whitespace */
373 line = buf;
374 while(*line && isspace(*line)) line++;
376 /* Ignore blank lines and comments */
377 if (!*line || *line == '#') {
378 continue;
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);
388 if (r < 0) break;
389 continue;
392 r = handle_option(es, name, value);
393 if (r < 0) break;
395 fclose(fp);
396 if (r >= 0) {
397 if (option_context_fn) {
398 r = option_context_fn(es, "*end*", "*end*");
399 option_context_fn = NULL;
403 return r;