/* * cfgfile.c: * * Copyright (c) 2003 DecisionSoft Ltd. * */ #include #include #include #include "stringmap.h" #include "iftop.h" #include "options.h" #include "cfgfile.h" #define CONFIG_TYPE_STRING 0 #define CONFIG_TYPE_BOOL 1 #define CONFIG_TYPE_INT 2 #define MAX_CONFIG_LINE 2048 char * config_directives[] = { "interface", "dns-resolution", "port-resolution", "filter-code", "show-bars", "promiscuous", "hide-source", "hide-destination", "use-bytes", "sort", "line-display", "show-totals", "log-scale", "max-bandwidth", "net-filter", "net-filter6", "link-local", "port-display", NULL }; stringmap config; extern options_t options ; int is_cfgdirective_valid(const char *s) { int t; for (t = 0; config_directives[t] != NULL; t++) if (strcmp(s, config_directives[t]) == 0) return 1; return 0; } int config_init() { config = stringmap_new(); return config != NULL; } /* read_config_file: * Read a configuration file consisting of key: value tuples, returning a * stringmap of the results. Prints errors to stderr, rather than using * syslog, since this file is called at program startup. Returns 1 on success * or 0 on failure. */ int read_config_file(const char *f, int whinge) { int ret = 0; FILE *fp; char *line; int i = 1; line = xmalloc(MAX_CONFIG_LINE); fp = fopen(f, "rt"); if (!fp) { if(whinge) fprintf(stderr, "%s: %s\n", f, strerror(errno)); goto fail; } while (fgets(line, MAX_CONFIG_LINE, fp)) { char *key, *value, *r; for (r = line + strlen(line) - 1; r > line && *r == '\n'; *(r--) = 0); /* Get continuation lines. Ugly. */ while (*(line + strlen(line) - 1) == '\\') { if (!fgets(line + strlen(line) - 1, MAX_CONFIG_LINE - strlen(line), fp)) break; for (r = line + strlen(line) - 1; r > line && *r == '\n'; *(r--) = 0); } /* Strip comment. */ key = strpbrk(line, "#\n"); if (key) *key = 0; /* foo : bar baz quux * key^ ^value */ key = line + strspn(line, " \t"); value = strchr(line, ':'); if (value) { /* foo : bar baz quux * key^ ^r ^value */ ++value; r = key + strcspn(key, " \t:"); if (r != key) { item *I; *r = 0; /* foo\0: bar baz quux * key^ ^value ^r */ value += strspn(value, " \t"); r = value + strlen(value) - 1; while (strchr(" \t", *r) && r > value) --r; *(r + 1) = 0; /* (Removed check for zero length value.) */ /* Check that this is a valid key. */ if (!is_cfgdirective_valid(key)) fprintf(stderr, "%s:%d: warning: unknown directive \"%s\"\n", f, i, key); else if ((I = stringmap_insert(config, key, item_ptr(xstrdup(value))))) /* Don't warn of repeated directives, because they * may have been specified via the command line * Previous option takes precedence. */ fprintf(stderr, "%s:%d: warning: repeated directive \"%s\"\n", f, i, key); } } memset(line, 0, MAX_CONFIG_LINE); /* security paranoia */ ++i; } ret = 1; fail: if (fp) fclose(fp); if (line) xfree(line); return ret; } int config_get_int(const char *directive, int *value) { stringmap S; char *s, *t; if (!value) return -1; S = stringmap_find(config, directive); if (!S) return 0; s = (char*)S->d.v; if (!*s) return -1; errno = 0; *value = strtol(s, &t, 10); if (*t) return -1; return errno == ERANGE ? -1 : 1; } /* config_get_float: * Get an integer value from a config string. Returns 1 on success, -1 on * failure, or 0 if no value was found. */ int config_get_float(const char *directive, float *value) { stringmap S; item *I; char *s, *t; if (!value) return -1; if (!(S = stringmap_find(config, directive))) return 0; s = (char*)S->d.v; if (!*s) return -1; errno = 0; *value = strtod(s, &t); if (*t) return -1; return errno == ERANGE ? -1 : 1; } /* config_get_string; * Get a string value from the config file. Returns NULL if it is not * present. */ char *config_get_string(const char *directive) { stringmap S; S = stringmap_find(config, directive); if (S) return (char*)S->d.v; else return NULL; } /* config_get_bool: * Get a boolean value from the config file. Returns false if not present. */ int config_get_bool(const char *directive) { char *s; s = config_get_string(directive); if (s && (strcmp(s, "yes") == 0 || strcmp(s, "true") == 0)) return 1; else return 0; } /* config_get_enum: * Get an enumeration value from the config file. Returns false if not * present or an invalid value is found. */ int config_get_enum(const char *directive, config_enumeration_type *enumeration, int *value) { char *s; config_enumeration_type *t; s = config_get_string(directive); if(s) { for(t = enumeration; t->name; t++) { if(strcmp(s,t->name) == 0) { *value = t->value; return 1; } } fprintf(stderr,"Invalid enumeration value \"%s\" for directive \"%s\"\n", s, directive); } return 0; } /* config_set_string; Sets a value in the config, possibly overriding * an existing value */ void config_set_string(const char *directive, const char* s) { stringmap S; S = stringmap_find(config, directive); if (S) { xfree(S->d.v); S->d = item_ptr(xstrdup(s)); } else { stringmap_insert(config, directive, item_ptr(xstrdup(s))); } } int read_config(char *file, int whinge_on_error) { void* o; return read_config_file(file, whinge_on_error); }