2 cfg.c -- cfguration code
4 Copyright (C) 1998 Robert van der Meulen
5 1998-2004 Ivo Timmermans <ivo@tinc-vpn.org>
6 2000-2004 Guus Sliepen <guus@tinc-vpn.org>
7 2000 Cris van Pelt <tribbel@arise.dhs.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include "support/avl.h"
30 #include "support/xalloc.h"
32 static int cfg_compare(const cfg_t *a, const cfg_t *b) {
33 return strcasecmp(a->variable, b->variable) ?: (a->line - b->line) ?: strcmp(a->file, b->file);
36 avl_tree_t *cfg_tree_new(void) {
37 return avl_tree_new((avl_compare_t)cfg_compare, (avl_action_t)cfg_free);
40 void cfg_tree_del(avl_tree_t *cfgs) {
44 cfg_t *cfg_new(void) {
47 return clear(new(cfg));
50 void cfg_free(cfg_t *cfg) {
51 replace(cfg->variable, NULL);
52 replace(cfg->value, NULL);
53 replace(cfg->file, NULL);
57 void cfg_add(avl_tree_t *cfgs, cfg_t *cfg) {
61 cfg_t *cfg_get(const avl_tree_t *cfgs, char *variable) {
64 search.variable = variable;
68 cfg = avl_get_closest_greater(cfgs, &search);
70 if(!cfg || strcasecmp(cfg->variable, variable))
76 cfg_t *cfg_get_next(const avl_tree_t *cfgs, const cfg_t *cfg) {
80 avl = avl_get_node(cfgs, cfg);
82 if(avl && avl->next) {
83 next = avl->next->data;
85 if(!strcasecmp(next->variable, cfg->variable))
92 bool cfg_bool(const cfg_t *cfg, const bool def, bool *result) {
98 if(!strcasecmp(cfg->value, "yes")) {
101 } else if(!strcasecmp(cfg->value, "no")) {
106 logger(LOG_ERR, _("cfg: \"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
107 cfg->variable, cfg->file, cfg->line);
112 bool cfg_int(const cfg_t *cfg, const int def, int *result) {
118 if(sscanf(cfg->value, "%d", result) == 1)
121 logger(LOG_ERR, _("cfg: integer expected for configuration variable %s in %s line %d"),
122 cfg->variable, cfg->file, cfg->line);
127 bool cfg_string(const cfg_t *cfg, const char *def, char **result) {
129 *result = def ? xstrdup(def) : NULL;
133 *result = xstrdup(cfg->value);
138 bool cfg_choice(const cfg_t *cfg, const cfg_choice_t *choice, const int def, int *result) {
146 for(i = 0; choice[i].key; i++) {
147 if(!strcasecmp(cfg->variable, choice[i].key)) {
148 *result = choice[i].value;
153 logger(LOG_ERR, _("cfg: invalid choice for configuration variable %s in %s line %d"),
154 cfg->variable, cfg->file, cfg->line);
159 bool cfg_period(const cfg_t *cfg, const int def, int *result) {
167 if(sscanf(cfg->value, "%d%c", result, &unit) == 2) {
178 *result *= 60 * 60 * 24;
181 *result *= 60 * 60 * 24 * 7;
184 *result *= 60 * 60 * 24 * 30;
187 *result *= 60 * 60 * 24 * 365;
190 logger(LOG_ERR, _("cfg: invalid period for configuration variable %s in %s line %d"),
191 cfg->variable, cfg->file, cfg->line);
197 if(sscanf(cfg->value, "%d", result) == 1)
200 logger(LOG_ERR, _("cfg: period expected for configuration variable %s in %s line %d"),
201 cfg->variable, cfg->file, cfg->line);
206 static char *readline(FILE *fp, char **buf, size_t *buflen) {
207 char *newline = NULL;
209 char *line; /* The array that contains everything that has been read so far */
210 char *idx; /* Read into this pointer, which points to an offset within line */
211 size_t size, newsize; /* The size of the current array pointed to by line */
212 size_t maxlen; /* Maximum number of characters that may be read with fgets. This is newsize - oldsize. */
221 dim(line, size = 100);
230 p = fgets(idx, maxlen, fp);
236 logger(LOG_ERR, _("cfg: error while reading: %s"), strerror(errno));
241 newline = strchr(p, '\n');
244 idx = &line[size - 1];
246 redim(line, size *= 2);
261 bool cfg_read_file(avl_tree_t *cfgs, const char *fname) {
264 char *variable, *value;
272 fp = fopen(fname, "r");
275 logger(LOG_ERR, _("cfg: error opening %s: %s"), fname, strerror(errno));
279 dim(buffer, bufsize = 100);
282 line = readline(fp, &buffer, &bufsize);
294 if(!*line || *line == '#')
298 if(!strncmp(line, "-----END", 8))
303 if(!strncmp(line, "-----BEGIN", 10)) {
308 variable = value = line;
310 len = strcspn(value, "\t =");
312 value += strspn(value, "\t ");
315 value += strspn(value, "\t ");
317 variable[len] = '\0';
320 logger(LOG_ERR, _("cfg: no value for variable %s on line %d while reading cfg file %s"),
321 variable, lineno, fname);
326 replace(cfg->variable, variable);
327 replace(cfg->value, value);
328 replace(cfg->file, fname);