Cleanup logging system so it can be used by the config parser
[olsrd.git] / src / olsr_cfg.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include <arpa/inet.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <assert.h>
46 #include <errno.h>
47 #include <getopt.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <unistd.h>
51
52 #include "olsr_cfg.h"
53 #include "olsr_cfg_data.h"
54 #include "olsr_logging.h"
55
56 #include "olsr.h"
57 #include "parser.h"
58 #include "net_olsr.h"
59 #include "olsr_ip_prefix_list.h"
60 #include "olsr_protocol.h"
61 #include "common/string.h"
62 #include "olsr_clock.h"
63 #include "os_net.h"
64 #include "os_system.h"
65
66 /* options that have no short command line variant */
67 enum cfg_long_options {
68   CFG_LOG_DEBUG = 256,
69   CFG_LOG_INFO,
70   CFG_LOG_WARN,
71   CFG_LOG_ERROR,
72   CFG_LOG_STDERR,
73   CFG_LOG_SYSLOG,
74   CFG_LOG_FILE,
75
76   CFG_OLSRPORT,
77   CFG_DLPATH,
78
79   CFG_HTTPPORT,
80   CFG_HTTPLIMIT,
81   CFG_TXTPORT,
82   CFG_TXTLIMIT,
83
84   CFG_HNA_HTIME,
85   CFG_HNA_VTIME,
86   CFG_MID_HTIME,
87   CFG_MID_VTIME,
88   CFG_TC_HTIME,
89   CFG_TC_VTIME,
90 };
91
92 /* remember which log severities have been explicitly set */
93 static bool cfg_has_log[LOG_SEVERITY_COUNT];
94
95 /*
96  * Special strcat for reading the config file and
97  * joining a longer section { ... } to one string
98  */
99 static void
100 read_cfg_cat(char **pdest, const char *src)
101 {
102   char *tmp = *pdest;
103   if (*src) {
104     size_t size = 1 + (tmp ? strlen(tmp) : 0) + strlen(src);
105     *pdest = olsr_malloc(size, "read_cfg_cat");
106     assert(0 == **pdest);
107     if (tmp) {
108       strscpy(*pdest, tmp, size);
109       free(tmp);
110     }
111     strscat(*pdest, src, size);
112   }
113 }
114
115 /*
116  * Read the olsrd.conf file and replace/insert found
117  * options into the argv[] array at the position of
118  * the original -f filename parameters. Note, that
119  * longer sections { ... } are joined to one string
120  */
121 static int
122 read_cfg(const char *filename, int *pargc, char ***pargv, int **pline)
123 {
124   FILE *f = fopen(filename, "r");
125   if (f) {
126     int bopen = 0, optind_tmp = optind, line_lst = 0, line = 0;
127     char sbuf[512], *pbuf = NULL, *p;
128
129     while ((p = fgets(sbuf, sizeof(sbuf), f)) || pbuf) {
130       line++;
131       if (!p) {
132         *sbuf = 0;
133         goto eof;
134       }
135       while (*p && '#' != *p) {
136         if ('"' == *p || '\'' == *p) {
137           char sep = *p;
138           while (*++p && sep != *p);
139         }
140         p++;
141       }
142       *p = 0;
143       while (sbuf <= --p && ' ' >= *p);
144       *(p + 1) = 0;
145       if (*sbuf) {
146         if (bopen) {
147           read_cfg_cat(&pbuf, sbuf);
148           if ('}' == *p) {
149             bopen = 0;
150           }
151         } else if (p == sbuf && '{' == *p) {
152           read_cfg_cat(&pbuf, " ");
153           read_cfg_cat(&pbuf, sbuf);
154           bopen = 1;
155         } else {
156           if ('{' == *p) {
157             bopen = 1;
158           }
159         eof:
160           if (pbuf) {
161             int i, *line_tmp;
162             char **argv_tmp;
163             int argc_tmp = *pargc + 2;
164             char *q = pbuf, *n;
165             size_t size;
166
167             while (*q && ' ' >= *q)
168               q++;
169             p = q;
170             while (' ' < *p)
171               p++;
172             size = p - q + 3;
173             n = olsr_malloc(size, "config arg0");
174             strscpy(n, "--", size);
175             strscat(n, q, size);
176             while (*q && ' ' >= *p)
177               p++;
178
179             line_tmp = olsr_malloc((argc_tmp+1) * sizeof(line_tmp[0]), "config line");
180             argv_tmp = olsr_malloc((argc_tmp+1) * sizeof(argv_tmp[0]), "config args");
181             for (i = 0; i < argc_tmp; i++) {
182               if (i < optind_tmp) {
183                 line_tmp[i] = (*pline)[i];
184                 argv_tmp[i] = (*pargv)[i];
185               } else if (i == optind_tmp) {
186                 line_tmp[i] = line_lst;
187                 argv_tmp[i] = n;
188               } else if (i == 1 + optind_tmp) {
189                 line_tmp[i] = line_lst;
190                 argv_tmp[i] = olsr_strdup(p);
191               } else {
192                 line_tmp[i] = (*pline)[i - 2];
193                 argv_tmp[i] = (*pargv)[i - 2];
194               }
195             }
196             optind_tmp += 2;
197             *pargc = argc_tmp;
198             free(*pargv);
199             *pargv = argv_tmp;
200             free(*pline);
201             *pline = line_tmp;
202             line_lst = line;
203             free(pbuf);
204             pbuf = NULL;
205           }
206           read_cfg_cat(&pbuf, sbuf);
207         }
208       }
209     }
210     fclose(f);
211     return 0;
212   }
213   return -1;
214 }
215
216 /*
217  * Free an array of string tokens
218  */
219 static void
220 parse_tok_free(char **s)
221 {
222   if (s) {
223     char **p = s;
224     while (*p) {
225       free(*p);
226       p++;
227     }
228     free(s);
229   }
230 }
231
232 /*
233  * Test for end-of-string or { ... } section
234  */
235 static inline bool
236 parse_tok_delim(const char *p)
237 {
238   switch (*p) {
239   case 0:
240   case '{':
241   case '}':
242     return true;
243   }
244   return false;
245 }
246
247 /*
248  * Slit the src string into tokens and return
249  * an array of token strings. May return NULL
250  * if no token found, otherwise you need to
251  * free the strings using parse_tok_free()
252  */
253 static char **
254 parse_tok(const char *s, const char **snext)
255 {
256   char **tmp, **ret = NULL;
257   int i, count = 0;
258   const char *p = s;
259
260   while (!parse_tok_delim(p)) {
261     while (!parse_tok_delim(p) && ' ' >= *p)
262       p++;
263     if (!parse_tok_delim(p)) {
264       char c = 0;
265       const char *q = p;
266       if ('"' == *p || '\'' == *p) {
267         c = *q++;
268         while (!parse_tok_delim(++p) && c != *p);
269       } else {
270         while (!parse_tok_delim(p) && ' ' < *p)
271           p++;
272       }
273       tmp = ret;
274       ret = olsr_malloc((2 + count) * sizeof(ret[0]), "parse_tok");
275       for (i = 0; i < count; i++) {
276         ret[i] = tmp[i];
277       }
278       if (tmp)
279         free(tmp);
280       ret[count++] = olsr_strndup(q, p - q);
281       ret[count] = NULL;
282       if (c)
283         p++;
284     }
285   }
286   if (snext)
287     *snext = p;
288   return ret;
289 }
290
291 /*
292  * Returns default interface options
293  */
294 struct olsr_if_options *
295 olsr_get_default_if_options(void)
296 {
297   struct olsr_if_options *new_io = olsr_malloc(sizeof(*new_io), "default_if_config");
298
299   /* No memset because olsr_malloc uses calloc() */
300   /* memset(&new_io->ipv4_broadcast, 0, sizeof(new_io->ipv4_broadcast)); */
301   new_io->ipv6_addrtype = OLSR_IP6T_AUTO;
302   inet_pton(AF_INET6, OLSR_IPV6_MCAST_SITE_LOCAL, &new_io->ipv6_multi_site.v6);
303   inet_pton(AF_INET6, OLSR_IPV6_MCAST_GLOBAL, &new_io->ipv6_multi_glbl.v6);
304   /* new_io->weight.fixed = false; */
305   /* new_io->weight.value = 0; */
306   new_io->hello_params.emission_interval = HELLO_INTERVAL;
307   new_io->hello_params.validity_time = NEIGHB_HOLD_TIME;
308   /* new_io->lq_mult = NULL; */
309   new_io->autodetect_chg = true;
310   new_io->mode = IF_MODE_MESH;
311   return new_io;
312 }
313
314 /**
315  * Create a new interf_name struct using a given
316  * name and insert it into the interface list.
317  */
318 static struct olsr_if_config *
319 queue_if(const char *name, struct olsr_config *cfg)
320 {
321   struct olsr_if_config *new_if;
322
323   /* check if the interface already exists */
324   for (new_if = cfg->if_configs; new_if != NULL; new_if = new_if->next) {
325     if (0 == strcasecmp(new_if->name, name)) {
326       fprintf(stderr, "Duplicate interfaces defined... not adding %s\n", name);
327       return NULL;
328     }
329   }
330
331   new_if = olsr_malloc(sizeof(*new_if), "queue interface");
332   new_if->name = olsr_strdup(name);
333   /* new_if->config = NULL; */
334   /* memset(&new_if->hemu_ip, 0, sizeof(new_if->hemu_ip)); */
335   /* new_if->interf = NULL; */
336   new_if->cnf = olsr_get_default_if_options();
337   new_if->next = cfg->if_configs;
338   cfg->if_configs = new_if;
339
340   return new_if;
341 }
342
343 /*
344  * Parses a single hna option block
345  * @argstr:     arguments string
346  * @ip_version: AF_INET of AF_INET6
347  * @rcfg:       config struct to write/change values into
348  * @rmsg:       a buf[FILENAME_MAX + 256] to sprint err msgs
349  * @returns configuration status as defined in olsr_parse_cfg_result
350  */
351 static void
352 parse_cfg_hna(char *argstr, const int ip_version, struct olsr_config *rcfg)
353 {
354   char **tok;
355 #ifdef DEBUG
356   struct ipaddr_str buf;
357 #endif
358   if ('{' != *argstr) {
359     OLSR_ERROR(LOG_CONFIG, "No {}\n");
360     olsr_exit(1);
361   }
362   if (NULL != (tok = parse_tok(argstr + 1, NULL))) {
363     char **p = tok;
364     if (ip_version != rcfg->ip_version) {
365       OLSR_ERROR(LOG_CONFIG, "IPv%d addresses can only be used if \"IpVersion\" == %d\n",
366               AF_INET == ip_version ? 4 : 6, AF_INET == ip_version ? 4 : 6);
367       parse_tok_free(tok);
368       olsr_exit(1);
369     }
370     while (p[0]) {
371       union olsr_ip_addr ipaddr;
372       if (!p[1]) {
373         OLSR_ERROR(LOG_CONFIG, "Odd args in %s\n", argstr);
374         parse_tok_free(tok);
375         olsr_exit(1);
376       }
377       if (inet_pton(ip_version, p[0], &ipaddr) <= 0) {
378         OLSR_ERROR(LOG_CONFIG, "Failed converting IP address %s\n", p[0]);
379         parse_tok_free(tok);
380         olsr_exit(1);
381       }
382       if (AF_INET == ip_version) {
383         union olsr_ip_addr netmask;
384         if (inet_pton(AF_INET, p[1], &netmask) <= 0) {
385           OLSR_ERROR(LOG_CONFIG, "Failed converting IP address %s\n", p[1]);
386           parse_tok_free(tok);
387           olsr_exit(1);
388         }
389         if ((ipaddr.v4.s_addr & ~netmask.v4.s_addr) != 0) {
390           OLSR_ERROR(LOG_CONFIG, "The IP address %s/%s is not a network address!\n", p[0], p[1]);
391           parse_tok_free(tok);
392           olsr_exit(1);
393         }
394         ip_prefix_list_add(&rcfg->hna_entries, &ipaddr, netmask_to_prefix((uint8_t *) & netmask, rcfg->ipsize));
395         OLSR_INFO_NH(LOG_CONFIG, "Hna4 %s/%d\n", ip_to_string(rcfg->ip_version, &buf, &ipaddr),
396                             netmask_to_prefix((uint8_t *) & netmask, rcfg->ipsize));
397       } else {
398         int prefix = -1;
399         sscanf('/' == *p[1] ? p[1] + 1 : p[1], "%d", &prefix);
400         if (0 > prefix || 128 < prefix) {
401           OLSR_ERROR(LOG_CONFIG, "Illegal IPv6 prefix %s\n", p[1]);
402           parse_tok_free(tok);
403           olsr_exit(1);
404         }
405         ip_prefix_list_add(&rcfg->hna_entries, &ipaddr, prefix);
406         OLSR_INFO_NH(LOG_CONFIG, "Hna6 %s/%d\n", ip_to_string(rcfg->ip_version, &buf, &ipaddr), prefix);
407       }
408       p += 2;
409     }
410     parse_tok_free(tok);
411   }
412 }
413
414 /*
415  * Parses a single interface option block
416  * @argstr:     arguments string
417  * @rcfg:       config struct to write/change values into
418  * @rmsg:   a buf[FILENAME_MAX + 256] to sprint err msgs
419  * @returns configuration status as defined in olsr_parse_cfg_result
420  */
421 static void
422 parse_cfg_interface(char *argstr, struct olsr_config *rcfg)
423 {
424   char **tok;
425   const char *nxt;
426 #ifdef DEBUG
427   struct ipaddr_str buf;
428 #endif
429   if (NULL != (tok = parse_tok(argstr, &nxt))) {
430     if ('{' != *nxt) {
431       OLSR_ERROR(LOG_CONFIG, "No {}\n");
432       parse_tok_free(tok);
433       olsr_exit(1);
434     } else {
435       char **tok_next = parse_tok(nxt + 1, NULL);
436       char **p = tok;
437       while (p[0]) {
438         char **p_next = tok_next;
439         struct olsr_if_config *new_if = queue_if(p[0], rcfg);
440         OLSR_INFO_NH(LOG_CONFIG, "Interface %s\n", p[0]);
441         while (new_if && p_next && p_next[0]) {
442           if (!p_next[1]) {
443             OLSR_ERROR(LOG_CONFIG, "Odd args in %s\n", nxt);
444             parse_tok_free(tok_next);
445             parse_tok_free(tok);
446             olsr_exit(1);
447           }
448           if (0 == strcasecmp("Mode", p_next[0])) {
449             if (0 == strcasecmp("Ether", p_next[1])) {
450               new_if->cnf->mode = IF_MODE_ETHER;
451             } else {
452               new_if->cnf->mode = IF_MODE_MESH;
453             }
454             OLSR_INFO_NH(LOG_CONFIG, "\tMode: %s\n", INTERFACE_MODE_NAMES[new_if->cnf->mode]);
455           } else if (0 == strcasecmp("AutoDetectChanges", p_next[0])) {
456             new_if->cnf->autodetect_chg = (0 == strcasecmp("yes", p_next[1]));
457             OLSR_INFO_NH(LOG_CONFIG, "\tAutodetect changes: %d\n", new_if->cnf->autodetect_chg);
458           } else if (0 == strcasecmp("Ip4Broadcast", p_next[0])) {
459             union olsr_ip_addr ipaddr;
460             if (inet_pton(AF_INET, p_next[1], &ipaddr) <= 0) {
461               OLSR_ERROR(LOG_CONFIG, "Failed converting IP address %s\n", p_next[1]);
462               parse_tok_free(tok_next);
463               parse_tok_free(tok);
464               olsr_exit(1);
465             }
466             new_if->cnf->ipv4_broadcast = ipaddr;
467             OLSR_INFO_NH(LOG_CONFIG, "\tIPv4 broadcast: %s\n", ip4_to_string(&buf, new_if->cnf->ipv4_broadcast.v4));
468           } else if (0 == strcasecmp("Ip6AddrType", p_next[0])) {
469             if (0 == strcasecmp("site-local", p_next[1])) {
470               new_if->cnf->ipv6_addrtype = OLSR_IP6T_SITELOCAL;
471             } else if (0 == strcasecmp("unique-local", p_next[1])) {
472               new_if->cnf->ipv6_addrtype = OLSR_IP6T_UNIQUELOCAL;
473             } else if (0 == strcasecmp("global", p_next[1])) {
474               new_if->cnf->ipv6_addrtype = OLSR_IP6T_GLOBAL;
475             } else {
476               new_if->cnf->ipv6_addrtype = OLSR_IP6T_AUTO;
477             }
478             OLSR_INFO_NH(LOG_CONFIG, "\tIPv6 addrtype: %d\n", new_if->cnf->ipv6_addrtype);
479           } else if (0 == strcasecmp("Ip6MulticastSite", p_next[0])) {
480             union olsr_ip_addr ipaddr;
481             if (inet_pton(AF_INET6, p_next[1], &ipaddr) <= 0) {
482               OLSR_ERROR(LOG_CONFIG, "Failed converting IP address %s\n", p_next[1]);
483               parse_tok_free(tok_next);
484               parse_tok_free(tok);
485               olsr_exit(1);
486             }
487             new_if->cnf->ipv6_multi_site = ipaddr;
488             OLSR_INFO_NH(LOG_CONFIG, "\tIPv6 site-local multicast: %s\n", ip6_to_string(&buf, &new_if->cnf->ipv6_multi_site.v6));
489           } else if (0 == strcasecmp("Ip6MulticastGlobal", p_next[0])) {
490             union olsr_ip_addr ipaddr;
491             if (inet_pton(AF_INET6, p_next[1], &ipaddr) <= 0) {
492               OLSR_ERROR(LOG_CONFIG, "Failed converting IP address %s\n", p_next[1]);
493               parse_tok_free(tok_next);
494               parse_tok_free(tok);
495               olsr_exit(1);
496             }
497             new_if->cnf->ipv6_multi_glbl = ipaddr;
498             OLSR_INFO_NH(LOG_CONFIG, "\tIPv6 global multicast: %s\n", ip6_to_string(&buf, &new_if->cnf->ipv6_multi_glbl.v6));
499           } else if (0 == strcasecmp("HelloInterval", p_next[0])) {
500             new_if->cnf->hello_params.emission_interval = olsr_clock_parse_string(p_next[1]);
501             OLSR_INFO_NH(LOG_CONFIG, "\tHELLO interval1: %u ms\n", new_if->cnf->hello_params.emission_interval);
502           } else if (0 == strcasecmp("HelloValidityTime", p_next[0])) {
503             new_if->cnf->hello_params.validity_time = olsr_clock_parse_string(p_next[1]);
504             OLSR_INFO_NH(LOG_CONFIG, "\tHELLO validity: %u ms\n", new_if->cnf->hello_params.validity_time);
505           } else if ((0 == strcasecmp("Tcinterval", p_next[0])) || (0 == strcasecmp("TcValidityTime", p_next[0])) ||
506                      (0 == strcasecmp("Midinterval", p_next[0])) || (0 == strcasecmp("MidValidityTime", p_next[0])) ||
507                      (0 == strcasecmp("Hnainterval", p_next[0])) || (0 == strcasecmp("HnaValidityTime", p_next[0]))) {
508             OLSR_ERROR(LOG_CONFIG, "ERROR: %s is deprecated within the interface section. All message intervals/validities except Hellos are global!\n",p_next[0]);
509             parse_tok_free(tok_next);
510             parse_tok_free(tok);
511             olsr_exit(1);
512           } else if (0 == strcasecmp("Weight", p_next[0])) {
513             new_if->cnf->weight.fixed = true;
514             OLSR_INFO_NH(LOG_CONFIG, "\tFixed willingness: %d\n", new_if->cnf->weight.value);
515           } else if (0 == strcasecmp("LinkQualityMult", p_next[0])) {
516             float f;
517             struct olsr_lq_mult *mult = olsr_malloc(sizeof(*mult), "lqmult");
518             if (!p_next[2]) {
519               OLSR_ERROR(LOG_CONFIG, "Odd args in %s\n", nxt);
520               parse_tok_free(tok_next);
521               parse_tok_free(tok);
522               olsr_exit(1);
523             }
524             memset(&mult->addr, 0, sizeof(mult->addr));
525             if (0 != strcasecmp("default", p_next[1])) {
526               if (inet_pton(rcfg->ip_version, p_next[1], &mult->addr) <= 0) {
527                 OLSR_ERROR(LOG_CONFIG, "Failed converting IP address %s\n", p_next[1]);
528                 parse_tok_free(tok_next);
529                 parse_tok_free(tok);
530                 olsr_exit(1);
531               }
532             }
533             f = 0;
534             sscanf(p_next[2], "%f", &f);
535             mult->value = (uint32_t) (f * LINK_LOSS_MULTIPLIER);
536             mult->next = new_if->cnf->lq_mult;
537             new_if->cnf->lq_mult = mult;
538             OLSR_INFO_NH(LOG_CONFIG, "\tLinkQualityMult %s %0.2f\n", ip_to_string(rcfg->ip_version, &buf, &mult->addr),
539                                 (float)mult->value / LINK_LOSS_MULTIPLIER);
540             p_next++;
541           } else {
542             OLSR_ERROR(LOG_CONFIG, "Unknown arg: %s %s\n", p_next[0], p_next[1]);
543             parse_tok_free(tok_next);
544             parse_tok_free(tok);
545             olsr_exit(1);
546           }
547           p_next += 2;
548         }
549         p++;
550       }
551       parse_tok_free(tok_next);
552     }
553     parse_tok_free(tok);
554   } else {
555     OLSR_ERROR(LOG_CONFIG, "Error in %s\n", argstr);
556     olsr_exit(1);
557   }
558 }
559
560 /*
561  * Parses a single loadplugin option block
562  * @argstr:     arguments string
563  * @rcfg:       config struct to write/change values into
564  * @rmsg:   a buf[FILENAME_MAX + 256] to sprint err msgs
565  * @returns configuration status as defined in olsr_parse_cfg_result
566  */
567 static void
568 parse_cfg_loadplugin(char *argstr, struct olsr_config *rcfg)
569 {
570   char **tok;
571   const char *nxt;
572   if (NULL != (tok = parse_tok(argstr, &nxt))) {
573     if ('{' != *nxt) {
574       OLSR_ERROR(LOG_CONFIG, "No {}\n");
575       parse_tok_free(tok);
576       olsr_exit(1);
577     } else {
578       char **tok_next = parse_tok(nxt + 1, NULL);
579       struct plugin_entry *pe = olsr_malloc(sizeof(*pe), "plugin");
580       pe->name = olsr_strdup(*tok);
581       pe->params = NULL;
582       pe->next = rcfg->plugins;
583       rcfg->plugins = pe;
584       OLSR_INFO_NH(LOG_CONFIG, "Plugin: %s\n", pe->name);
585       if (tok_next) {
586         char **p_next = tok_next;
587         while (p_next[0]) {
588           struct plugin_param *pp = olsr_malloc(sizeof(*pp), "plparam");
589           if (0 != strcasecmp("PlParam", p_next[0]) || !p_next[1] || !p_next[2]) {
590             OLSR_ERROR(LOG_CONFIG, "Odd args in %s\n", nxt);
591             parse_tok_free(tok_next);
592             parse_tok_free(tok);
593             olsr_exit(1);
594           }
595           pp->key = olsr_strdup(p_next[1]);
596           pp->value = olsr_strdup(p_next[2]);
597           pp->next = pe->params;
598           pe->params = pp;
599           OLSR_INFO_NH(LOG_CONFIG, "\tPlParam: %s %s\n", pp->key, pp->value);
600           p_next += 3;
601         }
602         parse_tok_free(tok_next);
603       }
604     }
605     parse_tok_free(tok);
606   } else {
607     OLSR_ERROR(LOG_CONFIG, "Error in %s\n", argstr);
608     olsr_exit(1);
609   }
610 }
611
612 /*
613  * Parses a the parameter string of --log(debug|info|warn|error)
614  * @argstr:     arguments string
615  * @rcfg:       config struct to write/change values into
616  * @rmsg:   a buf[FILENAME_MAX + 256] to sprint err msgs
617  * @returns configuration status as defined in olsr_parse_cfg_result
618  */
619 static void
620 parse_cfg_debug(char *argstr, struct olsr_config *rcfg)
621 {
622   int dlevel, i;
623   dlevel = atoi(argstr);
624
625   if (dlevel < MIN_DEBUGLVL || dlevel > MAX_DEBUGLVL) {
626     OLSR_ERROR(LOG_CONFIG, "Error, debug level must be between -2 and 3\n");
627     olsr_exit(1);
628   }
629
630   switch (dlevel) {
631   case 3:
632     /* all logging */
633     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
634       rcfg->log_event[SEVERITY_DEBUG][i] = true;
635     }
636   case 2:
637     /* all info, warnings and errors */
638     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
639       rcfg->log_event[SEVERITY_INFO][i] = true;
640     }
641   case 1:
642     /* some INFO level output, plus all warnings and errors */
643     rcfg->log_event[SEVERITY_INFO][LOG_2NEIGH] = true;
644     rcfg->log_event[SEVERITY_INFO][LOG_LINKS] = true;
645     rcfg->log_event[SEVERITY_INFO][LOG_MAIN] = true;
646     rcfg->log_event[SEVERITY_INFO][LOG_NEIGHTABLE] = true;
647     rcfg->log_event[SEVERITY_INFO][LOG_PLUGINS] = true;
648     rcfg->log_event[SEVERITY_INFO][LOG_ROUTING] = true;
649     rcfg->log_event[SEVERITY_INFO][LOG_TC] = true;
650   case 0:
651     /* errors and warnings */
652     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
653       rcfg->log_event[SEVERITY_WARN][i] = true;
654     }
655   case -1:
656     /* only error messages */
657     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
658       rcfg->log_event[SEVERITY_ERR][i] = true;
659     }
660   default:                     /* no logging at all ! */
661     break;
662   }
663
664   OLSR_INFO_NH(LOG_CONFIG, "Debug level: %d\n", dlevel);
665
666   if (dlevel > 0) {
667     rcfg->no_fork = 1;
668   }
669
670   /* prevent fallback to default 0 */
671   cfg_has_log[SEVERITY_ERR] = true;
672 }
673
674 /*
675  * Parses a the parameter string of --log(debug|info|warn|error)
676  * @argstr:     arguments string
677  * @rcfg:       config struct to write/change values into
678  * @rmsg:   a buf[FILENAME_MAX + 256] to sprint err msgs
679  * @returns configuration status as defined in olsr_parse_cfg_result
680  */
681 static void
682 parse_cfg_log(char *argstr, struct olsr_config *rcfg, enum log_severity sev)
683 {
684   char *p = (char *)argstr, *next;
685   int i;
686
687   while (p != NULL) {
688     /* split at ',' */
689     next = strchr(p, ',');
690     if (next) {
691       *next++ = 0;
692     }
693
694     for (i = 0; i < LOG_SOURCE_COUNT; i++) {
695       if (strcasecmp(p, LOG_SOURCE_NAMES[i]) == 0) {
696         break;
697       }
698     }
699
700     if (i == LOG_SOURCE_COUNT) {
701       OLSR_ERROR(LOG_CONFIG, "Error, unknown logging source: %s\n", p);
702       olsr_exit(1);
703     }
704
705     /* handle "all" keyword */
706     if (i == LOG_ALL) {
707       for (i = 0; i < LOG_SOURCE_COUNT; i++) {
708         rcfg->log_event[sev][i] = true;
709       }
710     }
711     else {
712       rcfg->log_event[sev][i] = true;
713     }
714     p = next;
715   }
716
717
718   for (i = 0; i < LOG_SOURCE_COUNT; i++) {
719     if (rcfg->log_event[sev][i]) {
720       OLSR_INFO_NH(LOG_CONFIG, "Log_%s %s", LOG_SEVERITY_NAMES[sev], LOG_SOURCE_NAMES[i]);
721     }
722   }
723   cfg_has_log[sev] = true;
724 }
725
726 /*
727  * Parses a single option found on the command line.
728  * @optint: return value of previous getopt_long()
729  * @argstr: argument string provided by getopt_long()
730  * @line:   line number (if option is read from file)
731  * @rcfg:   config struct to write/change values into
732  * @rmsg:   a buf[FILENAME_MAX + 256] to sprint err msgs
733  * @returns configuration status as defined in olsr_parse_cfg_result
734  */
735 static void
736 parse_cfg_option(const int optint, char *argstr, const int line, struct olsr_config *rcfg)
737 {
738   switch (optint) {
739   case 'i':                    /* iface */
740     /* Ignored */
741     break;
742   case 'n':                    /* nofork */
743     rcfg->no_fork = true;
744     OLSR_INFO_NH(LOG_CONFIG, "no_fork set to %d\n", rcfg->no_fork);
745     break;
746   case 'A':                    /* AllowNoInt (yes/no) */
747     rcfg->allow_no_interfaces = (0 == strcasecmp("yes", argstr));
748     OLSR_INFO_NH(LOG_CONFIG, "Noint set to %d\n", rcfg->allow_no_interfaces);
749     break;
750   case 'C':                    /* ClearScreen (yes/no) */
751     rcfg->clear_screen = (0 == strcasecmp("yes", argstr));
752     OLSR_INFO_NH(LOG_CONFIG, "Clear screen %s\n", rcfg->clear_screen ? "enabled" : "disabled");
753     break;
754   case 'd':                    /* DebugLevel (i) */
755     return parse_cfg_debug(argstr, rcfg);
756     break;
757   case 'F':                    /* FIBMetric (str) */
758     {
759       char **tok;
760       if (NULL != (tok = parse_tok(argstr, NULL))) {
761         if (strcasecmp(*tok, CFG_FIBM_FLAT) == 0) {
762           rcfg->fib_metric = FIBM_FLAT;
763         } else if (strcasecmp(*tok, CFG_FIBM_CORRECT) == 0) {
764           rcfg->fib_metric = FIBM_CORRECT;
765         } else if (strcasecmp(*tok, CFG_FIBM_APPROX) == 0) {
766           rcfg->fib_metric = FIBM_APPROX;
767         } else {
768           OLSR_ERROR(LOG_CONFIG, "FIBMetric must be \"%s\", \"%s\", or \"%s\"!\n", CFG_FIBM_FLAT, CFG_FIBM_CORRECT, CFG_FIBM_APPROX);
769           olsr_exit(1);
770         }
771         parse_tok_free(tok);
772       } else {
773         OLSR_ERROR(LOG_CONFIG, "Error in %s\n", argstr);
774         olsr_exit(1);
775       }
776       OLSR_INFO_NH(LOG_CONFIG, "FIBMetric: %d=%s\n", rcfg->fib_metric, argstr);
777     }
778     break;
779   case '4':                    /* Hna4 (4body) */
780     return parse_cfg_hna(argstr, AF_INET, rcfg);
781     break;
782   case '6':                    /* Hna6 (6body) */
783     return parse_cfg_hna(argstr, AF_INET6, rcfg);
784     break;
785   case 'I':                    /* Interface if1 if2 { ifbody } */
786     return parse_cfg_interface(argstr, rcfg);
787     break;
788   case 'V':                    /* IpVersion (i) */
789     {
790       int ver = -1;
791       sscanf(argstr, "%d", &ver);
792       if (ver == 4) {
793         rcfg->ip_version = AF_INET;
794         rcfg->ipsize = sizeof(struct in_addr);
795       } else if (ver == 6) {
796         rcfg->ip_version = AF_INET6;
797         rcfg->ipsize = sizeof(struct in6_addr);
798       } else {
799         OLSR_ERROR(LOG_CONFIG, "IpVersion must be 4 or 6!\n");
800         olsr_exit(1);
801       }
802     }
803     OLSR_INFO_NH(LOG_CONFIG, "IpVersion: %d\n", rcfg->ip_version);
804     break;
805   case 'E':                    /* LinkQualityFishEye (i) */
806     {
807       int arg = -1;
808       sscanf(argstr, "%d", &arg);
809       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->lq_fish))))
810         rcfg->lq_fish = arg;
811       OLSR_INFO_NH(LOG_CONFIG, "Link quality fish eye %d\n", rcfg->lq_fish);
812     }
813     break;
814   case 'p':                    /* LoadPlugin (soname {PlParams}) */
815     return parse_cfg_loadplugin(argstr, rcfg);
816     break;
817   case 'M':                    /* MprCoverage (i) */
818     {
819       int arg = -1;
820       sscanf(argstr, "%d", &arg);
821       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->mpr_coverage))))
822         rcfg->mpr_coverage = arg;
823       OLSR_INFO_NH(LOG_CONFIG, "MPR coverage %d\n", rcfg->mpr_coverage);
824     }
825     break;
826   case 'N':                    /* NatThreshold (f) */
827     {
828 #ifdef DEBUG
829       struct millitxt_buf tbuf;
830 #endif
831
832       rcfg->lq_nat_thresh = olsr_clock_parse_string(argstr);
833       OLSR_INFO_NH(LOG_CONFIG, "NAT threshold %s\n", olsr_clock_to_string(&tbuf, rcfg->lq_nat_thresh));
834     }
835     break;
836   case 'Y':                    /* NicChgsPollInt (f) */
837     rcfg->nic_chgs_pollrate = olsr_clock_parse_string(argstr);
838     OLSR_INFO_NH(LOG_CONFIG, "NIC Changes Pollrate %u ms\n", rcfg->nic_chgs_pollrate);
839     break;
840   case 'T':                    /* Pollrate (f) */
841     {
842       rcfg->pollrate = olsr_clock_parse_string(argstr);
843       OLSR_INFO_NH(LOG_CONFIG, "Pollrate %u ms\n", rcfg->pollrate);
844     }
845     break;
846   case 'q':                    /* RtProto (i) */
847     {
848       int arg = -1;
849       sscanf(argstr, "%d", &arg);
850       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->rt_proto))))
851         rcfg->rt_proto = arg;
852       OLSR_INFO_NH(LOG_CONFIG, "RtProto: %d\n", rcfg->rt_proto);
853     }
854     break;
855   case 'R':                    /* RtTableDefault (i) */
856     {
857       int arg = -1;
858       sscanf(argstr, "%d", &arg);
859       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->rt_table_default))))
860         rcfg->rt_table_default = arg;
861       OLSR_INFO_NH(LOG_CONFIG, "RtTableDefault: %d\n", rcfg->rt_table_default);
862     }
863     break;
864   case 'r':                    /* RtTable (i) */
865     {
866       int arg = -1;
867       sscanf(argstr, "%d", &arg);
868       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->rt_table))))
869         rcfg->rt_table = arg;
870       OLSR_INFO_NH(LOG_CONFIG, "RtTable: %d\n", rcfg->rt_table);
871     }
872     break;
873   case 't':                    /* TcRedundancy (i) */
874     {
875       int arg = -1;
876       sscanf(argstr, "%d", &arg);
877       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->tc_redundancy))))
878         rcfg->tc_redundancy = arg;
879       OLSR_INFO_NH(LOG_CONFIG, "TC redundancy %d\n", rcfg->tc_redundancy);
880     }
881     break;
882   case 'Z':                    /* TosValue (i) */
883     {
884       int arg = -1;
885       sscanf(argstr, "%d", &arg);
886       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->tos))))
887         rcfg->tos = arg;
888       OLSR_INFO_NH(LOG_CONFIG, "TOS: %d\n", rcfg->tos);
889     }
890     break;
891   case 'w':                    /* Willingness (i) */
892     {
893       int arg = -1;
894       sscanf(argstr, "%d", &arg);
895       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->willingness))))
896         rcfg->willingness = arg;
897       rcfg->willingness_auto = false;
898       OLSR_INFO_NH(LOG_CONFIG, "Willingness: %d (no auto)\n", rcfg->willingness);
899     }
900     break;
901   case CFG_LOG_DEBUG:          /* Log (string) */
902     return parse_cfg_log(argstr, rcfg, SEVERITY_DEBUG);
903     break;
904   case CFG_LOG_INFO:           /* Log (string) */
905     return parse_cfg_log(argstr, rcfg, SEVERITY_INFO);
906     break;
907   case CFG_LOG_WARN:           /* Log (string) */
908     return parse_cfg_log(argstr, rcfg, SEVERITY_WARN);
909     break;
910   case CFG_LOG_ERROR:          /* Log (string) */
911     return parse_cfg_log(argstr, rcfg, SEVERITY_ERR);
912     break;
913   case CFG_LOG_STDERR:
914     rcfg->log_target_stderr = true;
915     break;
916   case CFG_LOG_SYSLOG:
917     rcfg->log_target_syslog = true;
918     break;
919   case CFG_LOG_FILE:
920     rcfg->log_target_file = strdup(argstr);
921     break;
922
923   case 's':                    /* SourceIpMode (string) */
924     rcfg->source_ip_mode = (0 == strcasecmp("yes", argstr)) ? 1 : 0;
925     OLSR_INFO_NH(LOG_CONFIG, "Source IP mode %s\n", rcfg->source_ip_mode ? "enabled" : "disabled");
926     break;
927   case 'o':                    /* Originator Address (ip) */
928     if (inet_pton(AF_INET, argstr, &rcfg->router_id) <= 0) {
929       OLSR_ERROR(LOG_CONFIG, "Failed converting IP address %s for originator address\n", argstr);
930       olsr_exit(1);
931     }
932     break;
933   case CFG_OLSRPORT:           /* port (i) */
934     {
935       int arg = -1;
936       sscanf(argstr, "%d", &arg);
937       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->olsr_port))))
938         rcfg->olsr_port = arg;
939       OLSR_INFO_NH(LOG_CONFIG, "OLSR port: %d\n", rcfg->olsr_port);
940     }
941     break;
942   case CFG_DLPATH:
943     rcfg->dlPath = strdup(argstr);
944     OLSR_INFO_NH(LOG_CONFIG, "Dynamic library path: %s\n", rcfg->dlPath);
945     break;
946   case CFG_HTTPPORT:
947     {
948       int arg = -1;
949       sscanf(argstr, "%d", &arg);
950       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->comport_http))))
951         rcfg->comport_http = arg;
952       OLSR_INFO_NH(LOG_CONFIG, "HTTP port: %d\n", rcfg->comport_http);
953     }
954     break;
955   case CFG_HTTPLIMIT:
956     {
957       int arg = -1;
958       sscanf(argstr, "%d", &arg);
959       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->comport_http_limit))))
960         rcfg->comport_http_limit = arg;
961       OLSR_INFO_NH(LOG_CONFIG, "HTTP connection limit: %d\n", rcfg->comport_http_limit);
962     }
963     break;
964   case CFG_TXTPORT:
965     {
966       int arg = -1;
967       sscanf(argstr, "%d", &arg);
968       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->comport_txt))))
969         rcfg->comport_txt = arg;
970       OLSR_INFO_NH(LOG_CONFIG, "TXT port: %d\n", rcfg->comport_txt);
971     }
972     break;
973   case CFG_TXTLIMIT:
974     {
975       int arg = -1;
976       sscanf(argstr, "%d", &arg);
977       if (0 <= arg && arg < (1 << (8 * sizeof(rcfg->comport_txt_limit))))
978         rcfg->comport_txt_limit = arg;
979       OLSR_INFO_NH(LOG_CONFIG, "TXT connection limit: %d\n", rcfg->comport_txt_limit);
980     }
981     break;
982   case CFG_HNA_HTIME:
983     rcfg->hna_params.emission_interval = olsr_clock_parse_string(argstr);
984     OLSR_INFO_NH(LOG_CONFIG, "HNA interval1: %u ms\n", rcfg->hna_params.emission_interval);
985     break;
986   case CFG_HNA_VTIME:
987     rcfg->hna_params.validity_time = olsr_clock_parse_string(argstr);
988     OLSR_INFO_NH(LOG_CONFIG, "HNA validity: %u ms\n", rcfg->hna_params.validity_time);
989     break;
990   case CFG_MID_HTIME:
991     rcfg->mid_params.emission_interval = olsr_clock_parse_string(argstr);
992     OLSR_INFO_NH(LOG_CONFIG, "MID interval1: %u ms\n", rcfg->mid_params.emission_interval);
993     break;
994   case CFG_MID_VTIME:
995     rcfg->mid_params.validity_time = olsr_clock_parse_string(argstr);
996     OLSR_INFO_NH(LOG_CONFIG, "MID validity: %u ms\n", rcfg->mid_params.validity_time);
997     break;
998   case CFG_TC_HTIME:
999     rcfg->tc_params.emission_interval = olsr_clock_parse_string(argstr);
1000     OLSR_INFO_NH(LOG_CONFIG, "TC interval1: %u ms\n", rcfg->tc_params.emission_interval);
1001     break;
1002   case CFG_TC_VTIME:
1003     rcfg->tc_params.validity_time = olsr_clock_parse_string(argstr);
1004     OLSR_INFO_NH(LOG_CONFIG, "TC validity: %u ms\n", rcfg->tc_params.validity_time);
1005     break;
1006
1007   default:
1008     OLSR_ERROR(LOG_CONFIG, "Unknown arg in line %d.\n", line);
1009     olsr_exit(1);
1010   }                             /* switch */
1011 }
1012
1013 /*
1014  * Parses command line options using the getopt() runtime
1015  * function. May also replace a "-f filename" combination
1016  * with options read in from a config file.
1017  *
1018  * @argc: the argv count from main() - or zero if no argv
1019  * @argv: the array of strings provided from the enviroment
1020  * @file: the default config file name (used if argc <= 1)
1021  * @rmsg: to provide buf[FILENAME_MAX + 256] to sprint err msgs
1022  * @rcfg: returns a valid config pointer, clean with olsr_free_cfg()
1023  * @returns a parsing status result code
1024  */
1025 void
1026 olsr_parse_cfg(int argc, char *argv[], const char *file, struct olsr_config ** rcfg)
1027 {
1028   int opt;
1029   int opt_idx = 0;
1030   char *opt_str = 0;
1031   int opt_argc = 0;
1032   char **opt_argv = olsr_malloc(argc * sizeof(opt_argv[0]), "opt_argv");
1033   int *opt_line = olsr_malloc(argc * sizeof(opt_line[0]), "opt_line");
1034
1035   /*
1036    * Original cmd line params
1037    *
1038    * -bcast                   (removed)
1039    * -delgw                   (-> --delgw)
1040    * -dispin                  (-> --dispin)
1041    * -dispout                 (-> --dispout)
1042    * -d (level)               (preserved)
1043    * -f (config)              (preserved)
1044    * -hemu (queue_if(hcif01)) (-> --hemu)
1045    * -hint                    (removed)
1046    * -hnaint                  (removed)
1047    * -i if0 if1...            (see comment below)
1048    * -int (WIN32)             (preserved)
1049    * -ipc (ipc conn = 1)      (-> --ipc)
1050    * -ipv6                    (-> -V or --IpVersion)
1051    * -lqa (lq aging)          (removed)
1052    * -lql (lq lev)            (removed)
1053    * -lqnt (lq nat)           (removed)
1054    * -midint                  (removed)
1055    * -multi (ipv6 mcast)      (removed)
1056    * -nofork                  (preserved)
1057    * -tcint                   (removed)
1058    * -T (pollrate)            (preserved)
1059    *
1060    * Note: Remaining args are interpreted as list of
1061    * interfaces. For this reason, '-i' is ignored which
1062    * adds the following non-minus args to the list.
1063    */
1064
1065   /* *INDENT-OFF* */
1066   static struct option long_options[] = {
1067     {"config",                   required_argument, 0, 'f'}, /* (filename) */
1068     {"delgw",                    no_argument,       0, 'D'},
1069     {"help",                     optional_argument, 0, 'h'},
1070     {"iface",                    no_argument,       0, 'i'}, /* if0 if1... */
1071 #ifdef WIN32
1072     {"int",                      no_argument,       0, 'l'},
1073 #endif
1074     {"ipc",                      no_argument,       0, 'P'},
1075     {"log_debug",                required_argument, 0, CFG_LOG_DEBUG}, /* src1,src2,... */
1076     {"log_info",                 required_argument, 0, CFG_LOG_INFO}, /* src1,src2,... */
1077     {"log_warn",                 required_argument, 0, CFG_LOG_WARN}, /* src1,src2,... */
1078     {"log_error",                required_argument, 0, CFG_LOG_ERROR}, /* src1,src2,... */
1079     {"log_stderr",               no_argument,       0, CFG_LOG_STDERR},
1080     {"log_syslog",               no_argument,       0, CFG_LOG_SYSLOG},
1081     {"log_file",                 required_argument, 0, CFG_LOG_FILE}, /* (filename) */
1082     {"nofork",                   no_argument,       0, 'n'},
1083     {"version",                  no_argument,       0, 'v'},
1084     {"AllowNoInt",               required_argument, 0, 'A'}, /* (yes/no) */
1085     {"ClearScreen",              required_argument, 0, 'C'}, /* (yes/no) */
1086     {"DebugLevel",               required_argument, 0, 'd'}, /* (i) */
1087     {"FIBMetric",                required_argument, 0, 'F'}, /* (str) */
1088     {"Hna4",                     required_argument, 0, '4'}, /* (4body) */
1089     {"Hna6",                     required_argument, 0, '6'}, /* (6body) */
1090     {"Interface",                required_argument, 0, 'I'}, /* (if1 if2 {ifbody}) */
1091     {"IpVersion",                required_argument, 0, 'V'}, /* (i) */
1092     {"LinkQualityDijkstraLimit", required_argument, 0, 'J'}, /* (i,f) */
1093     {"LinkQualityFishEye",       required_argument, 0, 'E'}, /* (i) */
1094     {"LoadPlugin",               required_argument, 0, 'p'}, /* (soname {PlParams}) */
1095     {"MprCoverage",              required_argument, 0, 'M'}, /* (i) */
1096     {"NatThreshold",             required_argument, 0, 'N'}, /* (f) */
1097     {"NicChgsPollInt",           required_argument, 0, 'Y'}, /* (f) */
1098     {"Pollrate",                 required_argument, 0, 'T'}, /* (f) */
1099     {"RtProto",                  required_argument, 0, 'q'}, /* (i) */
1100     {"RtTableDefault",           required_argument, 0, 'R'}, /* (i) */
1101     {"RtTable",                  required_argument, 0, 'r'}, /* (i) */
1102     {"TcRedundancy",             required_argument, 0, 't'}, /* (i) */
1103     {"TosValue",                 required_argument, 0, 'Z'}, /* (i) */
1104     {"Willingness",              required_argument, 0, 'w'}, /* (i) */
1105     {"RouterId",                 required_argument, 0, 'o'}, /* (ip) */
1106     {"SourceIpMode",             required_argument, 0, 's'}, /* (yes/no) */
1107     {"OlsrPort",                 required_argument, 0, CFG_OLSRPORT},  /* (i) */
1108     {"dlPath",                   required_argument, 0, CFG_DLPATH},    /* (path) */
1109     {"HttpPort",                 required_argument, 0, CFG_HTTPPORT},  /* (i) */
1110     {"HttpLimit",                required_argument, 0, CFG_HTTPLIMIT}, /* (i) */
1111     {"TxtPort",                  required_argument, 0, CFG_TXTPORT},   /* (i) */
1112     {"TxtLimit",                 required_argument, 0, CFG_TXTLIMIT},  /* (i) */
1113     {"TcInterval",               required_argument, 0, CFG_TC_HTIME},  /* (f) */
1114     {"TcValidityTime",           required_argument, 0, CFG_TC_VTIME},  /* (f) */
1115     {"MidInterval",              required_argument, 0, CFG_MID_HTIME},  /* (f) */
1116     {"MidValidityTime",          required_argument, 0, CFG_MID_VTIME},  /* (f) */
1117     {"HnaInterval",              required_argument, 0, CFG_HNA_HTIME},  /* (f) */
1118     {"HnaValidityTime",          required_argument, 0, CFG_HNA_VTIME},  /* (f) */
1119
1120     {"IpcConnect",               required_argument, 0,  0 }, /* ignored */
1121     {"UseHysteresis",            required_argument, 0,  0 }, /* ignored */
1122     {"HystScaling",              required_argument, 0,  0 }, /* ignored */
1123     {"HystThrHigh",              required_argument, 0,  0 }, /* ignored */
1124     {"HystThrLow",               required_argument, 0,  0 }, /* ignored */
1125     {"LinkQualityLevel",         required_argument, 0,  0 }, /* ignored */
1126     {"LinkQualityWinsize",       required_argument, 0,  0 }, /* ignored */
1127     {"LinkQualityAlgorithm",     required_argument, 0,  0 }, /* ignored */
1128     {"LinkQualityAging",         required_argument, 0,  0 }, /* ignored */
1129     {"dispout",                  no_argument,       0,  0 }, /* ignored */
1130     {"dispin",                   no_argument,       0,  0 }, /* ignored */
1131     {0, 0, 0, 0}
1132   }, *popt = long_options;
1133   /* *INDENT-ON* */
1134
1135   /*
1136    * olsr_malloc() uses calloc, so opt_line is already filled
1137    * memset(opt_line, 0, argc * sizeof(opt_line[0]));
1138    */
1139
1140   /* cleanup static logsource flags */
1141   cfg_has_log[SEVERITY_DEBUG] = false;
1142   cfg_has_log[SEVERITY_INFO] = false;
1143   cfg_has_log[SEVERITY_WARN] = false;
1144   cfg_has_log[SEVERITY_ERR] = false;
1145
1146   /* Copy argv array for safe free'ing later on */
1147   while (opt_argc < argc) {
1148     const char *p = argv[opt_argc];
1149     if (0 == strcasecmp(p, "-nofork"))
1150       p = "-n";
1151 #ifdef WIN32
1152     else if (0 == strcasecmp(p, "-int"))
1153       p = "-l";
1154 #endif
1155     opt_argv[opt_argc] = olsr_strdup(p);
1156     opt_argc++;
1157   }
1158
1159   /* get option count */
1160   for (opt_idx = 0; long_options[opt_idx].name; opt_idx++);
1161
1162   /* Calculate short option string */
1163   opt_str = olsr_malloc(opt_idx * 3, "create short opt_string");
1164   opt_idx = 0;
1165   while (popt->name) {
1166     if (popt->val > 0 && popt->val < 128) {
1167       opt_str[opt_idx++] = popt->val;
1168
1169       switch (popt->has_arg) {
1170       case optional_argument:
1171         opt_str[opt_idx++] = ':';
1172         /* Fall through */
1173       case required_argument:
1174         opt_str[opt_idx++] = ':';
1175         break;
1176       }
1177     }
1178     popt++;
1179   }
1180
1181   /*
1182    * If no arguments, revert to default behaviour
1183    */
1184
1185   if (1 >= opt_argc) {
1186     char *argv0_tmp = opt_argv[0];
1187     free(opt_argv);
1188     opt_argv = olsr_malloc(3 * sizeof(opt_argv[0]), "default argv");
1189     opt_argv[0] = argv0_tmp;
1190     opt_argv[1] = olsr_strdup("-f");
1191     opt_argv[2] = olsr_strdup(file);
1192     opt_argc = 3;
1193   }
1194
1195   *rcfg = olsr_get_default_cfg();
1196
1197   while (0 <= (opt = getopt_long(opt_argc, opt_argv, opt_str, long_options, &opt_idx))) {
1198     switch (opt) {
1199     case 0:
1200       OLSR_WARN(LOG_CONFIG, "Ignored deprecated %s\n", long_options[opt_idx].name);
1201       break;
1202     case 'f':                  /* config (filename) */
1203       OLSR_INFO_NH(LOG_CONFIG, "Read config from %s\n", optarg);
1204       if (0 > read_cfg(optarg, &opt_argc, &opt_argv, &opt_line)) {
1205         OLSR_ERROR(LOG_CONFIG, "Could not read specified config file %s!\n%s", optarg, strerror(errno));
1206         olsr_exit(1);
1207       }
1208       break;
1209 #ifdef WIN32
1210     case 'l':                  /* win32: list ifaces */
1211       ListInterfaces();
1212       olsr_exit(1);
1213       break;
1214 #endif
1215     case 'v':                  /* version */
1216       fprintf(stderr,  "*** %s ***\n Build date: %s on %s\n http://www.olsr.org\n\n", olsrd_version, build_date, build_host);
1217       olsr_exit(0);
1218       break;
1219     case 'h':                  /* help */
1220       popt = long_options;
1221       fprintf(stderr, "Usage: olsrd [OPTIONS]... [interfaces]...\n");
1222       while (popt->name) {
1223         if (popt->val) {
1224           if (popt->val > 0 && popt->val < 128) {
1225             fprintf(stderr, "-%c or --%s ", popt->val, popt->name);
1226           } else {
1227             fprintf(stderr, "      --%s ", popt->name);
1228           }
1229           switch (popt->has_arg) {
1230           case required_argument:
1231             fprintf(stderr, "arg");
1232             break;
1233           case optional_argument:
1234             fprintf(stderr, "[arg]");
1235             break;
1236           }
1237           fprintf(stderr, "\n");
1238         }
1239         popt++;
1240       }
1241       if (optarg == NULL) {
1242         fprintf(stderr, "Use '--help=log'for help about the available logging sources\n");
1243       } else if (strcasecmp(optarg, "log") == 0) {
1244         int i;
1245
1246         fprintf(stderr, "Log sources for --log_debug, --log_info, --log_warn and --log_error:\n");
1247         for (i = 0; i < LOG_SOURCE_COUNT; i++) {
1248           fprintf(stderr, "\t%s\n", LOG_SOURCE_NAMES[i]);
1249         }
1250       }
1251       olsr_exit(0);
1252       break;
1253     default:
1254       parse_cfg_option(opt, optarg, opt_line[optind], *rcfg);
1255     }                           /* switch(opt) */
1256   }                             /* while getopt_long() */
1257
1258   while (optind < opt_argc) {
1259     OLSR_INFO_NH(LOG_CONFIG, "new interface %s\n", opt_argv[optind]);
1260     queue_if(opt_argv[optind++], *rcfg);
1261   }
1262
1263   /* Some cleanup */
1264   while (0 < opt_argc) {
1265     free(opt_argv[--opt_argc]);
1266   }
1267   free(opt_argv);
1268   free(opt_line);
1269   free(opt_str);
1270
1271   /* logging option post processing */
1272   if (!((*rcfg)->log_target_syslog || (*rcfg)->log_target_syslog || (*rcfg)->log_target_file != NULL)) {
1273     (*rcfg)->log_target_stderr = true;
1274     OLSR_INFO_NH(LOG_CONFIG, "Log: activate default logging target stderr\n");
1275   }
1276   for (opt = SEVERITY_INFO; opt < LOG_SEVERITY_COUNT; opt++) {
1277     if (!cfg_has_log[opt] && cfg_has_log[opt - 1]) {
1278       int i;
1279
1280       OLSR_INFO_NH(LOG_CONFIG, "Log: copy log level %s to %s\n", LOG_SEVERITY_NAMES[opt - 1], LOG_SEVERITY_NAMES[opt]);
1281
1282       /* copy debug to info, info to warning, warning to error (if neccessary) */
1283       for (i = 0; i < LOG_SOURCE_COUNT; i++) {
1284         (*rcfg)->log_event[opt][i] = (*rcfg)->log_event[opt - 1][i];
1285       }
1286       cfg_has_log[opt] = true;
1287     }
1288   }
1289   if (!cfg_has_log[SEVERITY_ERR]) {
1290     /* no logging at all defined ? fall back to default */
1291     char def[10] = DEF_DEBUGLVL;
1292     parse_cfg_debug(def, *rcfg);
1293   }
1294 }
1295
1296 /*
1297  * Checks a given config for illegal values
1298  */
1299 int
1300 olsr_sanity_check_cfg(struct olsr_config *cfg)
1301 {
1302   struct olsr_if_config *in = cfg->if_configs;
1303   struct olsr_if_options *io;
1304   struct millitxt_buf tbuf;
1305
1306   /* rttable */
1307   if (cfg->rt_table == 0) cfg->rt_table = 254;
1308
1309   /* rttable_default */
1310   if (cfg->rt_table_default == 0) cfg->rt_table_default = cfg->rt_table;
1311
1312   /* IP version */
1313   if (cfg->ip_version != AF_INET && cfg->ip_version != AF_INET6) {
1314     fprintf(stderr, "Ipversion %d not allowed!\n", cfg->ip_version);
1315     return -1;
1316   }
1317
1318   /* TOS */
1319   if (cfg->tos > MAX_TOS) {
1320     fprintf(stderr, "TOS %d is not allowed\n", cfg->tos);
1321     return -1;
1322   }
1323
1324   /* Willingness */
1325   if (cfg->willingness_auto == false && (cfg->willingness > MAX_WILLINGNESS)) {
1326     fprintf(stderr, "Willingness %d is not allowed\n", cfg->willingness);
1327     return -1;
1328   }
1329
1330   /* NIC Changes Pollrate */
1331   if (cfg->nic_chgs_pollrate < MIN_NICCHGPOLLRT || cfg->nic_chgs_pollrate > MAX_NICCHGPOLLRT) {
1332     fprintf(stderr, "NIC Changes Pollrate %u ms is not allowed\n", cfg->nic_chgs_pollrate);
1333     return -1;
1334   }
1335
1336   /* TC redundancy */
1337   if (cfg->tc_redundancy > MAX_TC_REDUNDANCY) {
1338     fprintf(stderr, "TC redundancy %d is not allowed\n", cfg->tc_redundancy);
1339     return -1;
1340   }
1341
1342   /* MPR coverage */
1343   if (cfg->mpr_coverage < MIN_MPR_COVERAGE || cfg->mpr_coverage > MAX_MPR_COVERAGE) {
1344     fprintf(stderr, "MPR coverage %d is not allowed\n", cfg->mpr_coverage);
1345     return -1;
1346   }
1347
1348   /* NAT threshold value */
1349   if (cfg->lq_nat_thresh < 100 || cfg->lq_nat_thresh > 1000) {
1350     fprintf(stderr, "NAT threshold %s is not allowed\n", olsr_clock_to_string(&tbuf, cfg->lq_nat_thresh));
1351     return -1;
1352   }
1353
1354   /* Source ip mode need fixed router id */
1355   if (0 == memcmp(&all_zero, &cfg->router_id, sizeof(cfg->router_id)) && cfg->source_ip_mode) {
1356     fprintf(stderr, "You cannot use source ip routing without setting a fixed router id\n");
1357     return -1;
1358   }
1359
1360   /* check OLSR port */
1361   if (cfg->olsr_port == 0) {
1362     fprintf(stderr, "0 is not a valid UDP port\n");
1363     return -1;
1364   }
1365
1366   /* TC interval */
1367   if (cfg->tc_params.emission_interval < cfg->pollrate ||
1368       cfg->tc_params.emission_interval > cfg->tc_params.validity_time) {
1369     fprintf(stderr, "Bad TC parameters! (em: %u ms, vt: %u ms)\n",
1370         cfg->tc_params.emission_interval,
1371         cfg->tc_params.validity_time);
1372     return -1;
1373   }
1374
1375   /* MID interval */
1376   if (cfg->mid_params.emission_interval < cfg->pollrate ||
1377       cfg->mid_params.emission_interval > cfg->mid_params.validity_time) {
1378     fprintf(stderr, "Bad MID parameters! (em: %u ms, vt: %u ms)\n",
1379         cfg->mid_params.emission_interval,
1380         cfg->mid_params.validity_time);
1381     return -1;
1382   }
1383
1384   /* HNA interval */
1385   if (cfg->hna_params.emission_interval < cfg->pollrate ||
1386       cfg->hna_params.emission_interval > cfg->hna_params.validity_time) {
1387     fprintf(stderr, "Bad HNA parameters! (em: %u ms, vt: %u ms)\n",
1388         cfg->hna_params.emission_interval,
1389         cfg->hna_params.validity_time);
1390     return -1;
1391   }
1392
1393   if (in == NULL) {
1394     fprintf(stderr, "No interfaces configured!\n");
1395     return -1;
1396   }
1397
1398   /* Interfaces */
1399   while (in) {
1400     io = in->cnf;
1401
1402     if (in->name == NULL || !strlen(in->name)) {
1403       fprintf(stderr, "Interface has no name!\n");
1404       return -1;
1405     }
1406
1407     if (io == NULL) {
1408       fprintf(stderr, "Interface %s has no configuration!\n", in->name);
1409       return -1;
1410     }
1411
1412     /* HELLO interval */
1413
1414     if (io->hello_params.emission_interval < cfg->pollrate ||
1415         io->hello_params.emission_interval > io->hello_params.validity_time) {
1416       fprintf(stderr, "Bad HELLO parameters! (em: %u ms, vt: %u ms)\n",
1417           io->hello_params.emission_interval,
1418           io->hello_params.validity_time);
1419       return -1;
1420     }
1421     in = in->next;
1422   }
1423
1424   return 0;
1425 }
1426
1427 /*
1428  * Free resources occupied by a configuration
1429  */
1430 void
1431 olsr_free_cfg(struct olsr_config *cfg)
1432 {
1433   struct olsr_if_config *ind, *in = cfg->if_configs;
1434   struct plugin_entry *ped, *pe = cfg->plugins;
1435   struct olsr_lq_mult *mult, *next_mult;
1436
1437   /* free logfile string if necessary */
1438   if (cfg->log_target_file) {
1439     free(cfg->log_target_file);
1440   }
1441
1442   /* free dynamic library path */
1443   if (cfg->dlPath) {
1444     free(cfg->dlPath);
1445   }
1446
1447   /*
1448    * Free HNAs.
1449    */
1450   ip_prefix_list_flush(&cfg->hna_entries);
1451
1452   /*
1453    * Free Interfaces - remove_interface() already called
1454    */
1455   while (in) {
1456     for (mult = in->cnf->lq_mult; mult != NULL; mult = next_mult) {
1457       next_mult = mult->next;
1458       free(mult);
1459     }
1460
1461     free(in->cnf);
1462     ind = in;
1463     in = in->next;
1464     free(ind->name);
1465     if (ind->config)
1466       free(ind->config);
1467     free(ind);
1468   }
1469
1470   /*
1471    * Free Plugins - olsr_close_plugins() allready called
1472    */
1473   while (pe) {
1474     struct plugin_param *pard, *par = pe->params;
1475     while (par) {
1476       pard = par;
1477       par = par->next;
1478       free(pard->key);
1479       free(pard->value);
1480       free(pard);
1481     }
1482     ped = pe;
1483     pe = pe->next;
1484     free(ped->name);
1485     free(ped);
1486   }
1487
1488   free(cfg);
1489
1490   return;
1491 }
1492
1493 /*
1494  * Get a default config
1495  */
1496 struct olsr_config *
1497 olsr_get_default_cfg(void)
1498 {
1499   int i;
1500   struct olsr_config *cfg = olsr_malloc(sizeof(struct olsr_config), "default config");
1501
1502   cfg->ip_version = AF_INET;
1503   cfg->ipsize = sizeof(struct in_addr);
1504
1505   assert(cfg->no_fork == false);
1506   cfg->allow_no_interfaces = DEF_ALLOW_NO_INTS;
1507   cfg->willingness_auto = DEF_WILL_AUTO;
1508   cfg->clear_screen = DEF_CLEAR_SCREEN;
1509
1510   cfg->tos = DEF_TOS;
1511   assert(cfg->rt_proto == 0);
1512   cfg->rt_table = 254;
1513   assert(cfg->rt_table_default == 0); /*does this ever fire!*/
1514   cfg->fib_metric = DEF_FIB_METRIC;
1515
1516   for (i = 0; i < LOG_SOURCE_COUNT; i++) {
1517     assert(cfg->log_event[SEVERITY_DEBUG][i] == false);
1518     assert(cfg->log_event[SEVERITY_INFO][i] == false);
1519     assert(cfg->log_event[SEVERITY_WARN][i] == false);
1520     assert(cfg->log_event[SEVERITY_ERR][i] == false);
1521   }
1522   cfg->log_target_stderr = true;
1523   assert(cfg->log_target_file == NULL);
1524   assert(cfg->log_target_syslog == false);
1525
1526   assert(cfg->plugins == NULL);
1527   list_init_head(&cfg->hna_entries);
1528   assert(cfg->if_configs == NULL);
1529
1530   cfg->pollrate = DEF_POLLRATE;
1531   cfg->nic_chgs_pollrate = DEF_NICCHGPOLLRT;
1532   cfg->lq_nat_thresh = DEF_LQ_NAT_THRESH;
1533   cfg->tc_redundancy = TC_REDUNDANCY;
1534   cfg->mpr_coverage = MPR_COVERAGE;
1535   cfg->lq_fish = DEF_LQ_FISH;
1536   assert(cfg->willingness == 0);
1537
1538   cfg->olsr_port = OLSRPORT;
1539   assert(cfg->dlPath == NULL);
1540
1541   cfg->comport_http       = DEF_HTTPPORT;
1542   cfg->comport_http_limit = DEF_HTTPLIMIT;
1543   cfg->comport_txt        = DEF_TXTPORT;
1544   cfg->comport_txt_limit  = DEF_TXTLIMIT;
1545
1546
1547   cfg->tc_params.emission_interval = TC_INTERVAL;
1548   cfg->tc_params.validity_time = TOP_HOLD_TIME;
1549   cfg->mid_params.emission_interval = MID_INTERVAL;
1550   cfg->mid_params.validity_time = MID_HOLD_TIME;
1551   cfg->hna_params.emission_interval = HNA_INTERVAL;
1552   cfg->hna_params.validity_time = HNA_HOLD_TIME;
1553
1554   assert(0 == memcmp(&all_zero, &cfg->router_id, sizeof(cfg->router_id)));
1555   assert(0 == cfg->source_ip_mode);
1556   cfg->will_int = 10 * HELLO_INTERVAL;
1557   cfg->exit_value = EXIT_SUCCESS;
1558
1559   assert(cfg->ioctl_s == 0);
1560 #if defined linux
1561   assert(cfg->rtnl_s == 0);
1562 #endif
1563 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__
1564   assert(cfg->rts_bsd == 0);
1565 #endif
1566
1567   return cfg;
1568 }
1569
1570 /*
1571  * Local Variables:
1572  * c-basic-offset: 2
1573  * indent-tabs-mode: nil
1574  * End:
1575  */