X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Futil%2Fconfiguration.c;h=85c17cb7d2d1f407d6eb119b3bebf99a4531c530;hb=0ea8e006d5f5ef84e31e000607bd24a23f8fc1ed;hp=0ce672dd9bb16ba8397e683be7d7d764c194656f;hpb=3d0444f9e6d64d6bc6b109cb743b9e08abcada0e;p=oweals%2Fgnunet.git diff --git a/src/util/configuration.c b/src/util/configuration.c index 0ce672dd9..85c17cb7d 100644 --- a/src/util/configuration.c +++ b/src/util/configuration.c @@ -33,6 +33,7 @@ #include "gnunet_os_lib.h" #include "gnunet_strings_lib.h" + /** * @brief configuration entry */ @@ -55,6 +56,7 @@ struct ConfigEntry char *val; }; + /** * @brief configuration section */ @@ -76,6 +78,7 @@ struct ConfigSection char *name; }; + /** * @brief configuration data */ @@ -95,8 +98,23 @@ struct GNUNET_CONFIGURATION_Handle }; + +/** + * Used for diffing a configuration object against + * the default one + */ +struct DiffHandle +{ + const struct GNUNET_CONFIGURATION_Handle *cfgDefault; + struct GNUNET_CONFIGURATION_Handle *cfgDiff; +}; + + + /** - * Create a GNUNET_CONFIGURATION_Configuration. + * Create a GNUNET_CONFIGURATION_Handle. + * + * @return fresh configuration object */ struct GNUNET_CONFIGURATION_Handle * GNUNET_CONFIGURATION_create () @@ -104,6 +122,12 @@ GNUNET_CONFIGURATION_create () return GNUNET_malloc (sizeof (struct GNUNET_CONFIGURATION_Handle)); } + +/** + * Destroy configuration object. + * + * @param cfg configuration to destroy + */ void GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg) { @@ -126,6 +150,15 @@ GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg) GNUNET_free (cfg); } + +/** + * Parse a configuration file, add all of the options in the + * file to the configuration environment. + * + * @param cfg configuration to update + * @param filename name of the configuration file + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ int GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename) @@ -143,6 +176,8 @@ GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg, char *fn; fn = GNUNET_STRINGS_filename_expand (filename); + if (fn == NULL) + return GNUNET_SYSERR; dirty = cfg->dirty; /* back up value! */ if (NULL == (fp = FOPEN (fn, "r"))) { @@ -171,12 +206,12 @@ GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg, if (emptyline == 1) continue; /* remove tailing whitespace */ - for (i = strlen (line) - 1; (i >= 0) && (isspace (line[i])); i--) + for (i = strlen (line) - 1; (i >= 0) && (isspace ( (unsigned char) line[i])); i--) line[i] = '\0'; if (1 == sscanf (line, "@INLINE@ %191[^\n]", value)) { /* @INLINE@ value */ - if (0 != GNUNET_CONFIGURATION_parse (cfg, value)) + if (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, value)) ret = GNUNET_SYSERR; /* failed to parse included config */ } else if (1 == sscanf (line, "[%99[^]]]", value)) @@ -190,7 +225,7 @@ GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg, /* tag = value */ /* Strip LF */ i = strlen (value) - 1; - while ((i >= 0) && (isspace (value[i]))) + while ((i >= 0) && (isspace ( (unsigned char) value[i]))) value[i--] = '\0'; /* remove quotes */ i = 0; @@ -234,14 +269,30 @@ GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg, return ret; } + +/** + * Test if there are configuration options that were + * changed since the last save. + * + * @param cfg configuration to inspect + * @return GNUNET_NO if clean, GNUNET_YES if dirty, GNUNET_SYSERR on error (i.e. last save failed) + */ int -GNUNET_CONFIGURATION_test_dirty (const struct GNUNET_CONFIGURATION_Handle *cfg) +GNUNET_CONFIGURATION_is_dirty (const struct GNUNET_CONFIGURATION_Handle *cfg) { return cfg->dirty; } + +/** + * Write configuration file. + * + * @param cfg configuration to write + * @param filename where to write the configuration + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ int -GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *data, +GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename) { struct ConfigSection *sec; @@ -253,6 +304,8 @@ GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *data, char *pos; fn = GNUNET_STRINGS_filename_expand (filename); + if (fn == NULL) + return GNUNET_SYSERR; GNUNET_DISK_directory_create_for_file (fn); if (NULL == (fp = FOPEN (fn, "w"))) { @@ -262,7 +315,7 @@ GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *data, } GNUNET_free (fn); error = 0; - sec = data->sections; + sec = cfg->sections; while (sec != NULL) { if (0 > fprintf (fp, "[%s]\n", sec->name)) @@ -307,17 +360,25 @@ GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *data, GNUNET_assert (0 == fclose (fp)); if (error != 0) { - data->dirty = GNUNET_SYSERR; /* last write failed */ + cfg->dirty = GNUNET_SYSERR; /* last write failed */ return GNUNET_SYSERR; } - data->dirty = GNUNET_NO; /* last write succeeded */ + cfg->dirty = GNUNET_NO; /* last write succeeded */ return GNUNET_OK; } -void GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg, - GNUNET_CONFIGURATION_Iterator iter, - void *iter_cls) +/** + * Iterate over all options in the configuration. + * + * @param cfg configuration to inspect + * @param iter function to call on each option + * @param iter_cls closure for iter + */ +void +GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_CONFIGURATION_Iterator iter, + void *iter_cls) { struct ConfigSection *spos; struct ConfigEntry *epos; @@ -327,26 +388,39 @@ void GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg { epos = spos->entries; while (epos != NULL) - { - iter (iter_cls, spos->name, epos->key, epos->val); - epos = epos->next; - } + { + iter (iter_cls, spos->name, epos->key, epos->val); + epos = epos->next; + } spos = spos->next; } } +/** + * Copy a configuration value to the given target configuration. + * Overwrites existing entries. + * + * @param cls the destination configuration (struct GNUNET_CONFIGURATION_Handle*) + * @param section section for the value + * @param option option name of the value + * @param value value to copy + */ static void copy_entry (void *cls, - const char *section, - const char *option, - const char *value) + const char *section, const char *option, const char *value) { struct GNUNET_CONFIGURATION_Handle *dst = cls; GNUNET_CONFIGURATION_set_value_string (dst, section, option, value); } +/** + * Duplicate an existing configuration object. + * + * @param cfg configuration to duplicate + * @return duplicate configuration + */ struct GNUNET_CONFIGURATION_Handle * GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg) { @@ -358,26 +432,42 @@ GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg) } +/** + * FIXME. + * + * @param cfg FIXME + * @param section FIXME + * @return matching entry, NULL if not found + */ static struct ConfigSection * -findSection (const struct GNUNET_CONFIGURATION_Handle *data, const char *section) +findSection (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section) { struct ConfigSection *pos; - pos = data->sections; + pos = cfg->sections; while ((pos != NULL) && (0 != strcasecmp (section, pos->name))) pos = pos->next; return pos; } +/** + * FIXME. + * + * @param cfg FIXME + * @param section FIXME + * @param key FIXME + * @return matching entry, NULL if not found + */ static struct ConfigEntry * -findEntry (const struct GNUNET_CONFIGURATION_Handle *data, +findEntry (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *key) { struct ConfigSection *sec; struct ConfigEntry *pos; - sec = findSection (data, section); + sec = findSection (cfg, section); if (sec == NULL) return NULL; pos = sec->entries; @@ -386,29 +476,91 @@ findEntry (const struct GNUNET_CONFIGURATION_Handle *data, return pos; } + +/** + * A callback function, compares entries from two configurations + * (default against a new configuration) and write the diffs in a + * diff-configuration object (the callback object). + * + * @param cls the diff configuration (struct DiffHandle*) + * @param section section for the value (of the default conf.) + * @param option option name of the value (of the default conf.) + * @param value value to copy (of the default conf.) + */ +static void +compareEntries (void *cls, + const char *section, const char *option, const char *value) +{ + struct DiffHandle *dh = cls; + struct ConfigEntry *entNew; + + entNew = findEntry (dh->cfgDefault, section, option); + if ( (entNew != NULL) && + (strcmp (entNew->val, value) == 0) ) + return; + GNUNET_CONFIGURATION_set_value_string (dh->cfgDiff, + section, + option, + value); +} + + +/** + * Write only configuration entries that have been changed to configuration file + * @param cfgDefault default configuration + * @param cfgNew new configuration + * @param filename where to write the configuration diff between default and new + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_write_diffs (const struct GNUNET_CONFIGURATION_Handle + *cfgDefault, + const struct GNUNET_CONFIGURATION_Handle *cfgNew, + const char *filename) +{ + int ret; + struct DiffHandle diffHandle; + + diffHandle.cfgDiff = GNUNET_CONFIGURATION_create (); + diffHandle.cfgDefault = cfgDefault; + GNUNET_CONFIGURATION_iterate (cfgNew, compareEntries, &diffHandle); + ret = GNUNET_CONFIGURATION_write (diffHandle.cfgDiff, filename); + GNUNET_CONFIGURATION_destroy (diffHandle.cfgDiff); + return ret; +} + + +/** + * Set a configuration value that should be a string. + * + * @param cfg configuration to update + * @param section section of interest + * @param option option of interest + * @param value value to set + */ void GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle - *data, + *cfg, const char *section, const char *option, const char *value) { struct ConfigSection *sec; struct ConfigEntry *e; - e = findEntry (data, section, option); + e = findEntry (cfg, section, option); if (e != NULL) { GNUNET_free_non_null (e->val); e->val = GNUNET_strdup (value); return; } - sec = findSection (data, section); + sec = findSection (cfg, section); if (sec == NULL) { sec = GNUNET_malloc (sizeof (struct ConfigSection)); sec->name = GNUNET_strdup (section); - sec->next = data->sections; - data->sections = sec; + sec->next = cfg->sections; + cfg->sections = sec; } e = GNUNET_malloc (sizeof (struct ConfigEntry)); e->key = GNUNET_strdup (option); @@ -417,6 +569,15 @@ GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle sec->entries = e; } + +/** + * Set a configuration value that should be a number. + * + * @param cfg configuration to update + * @param section section of interest + * @param option option of interest + * @param number value to set + */ void GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, @@ -428,9 +589,20 @@ GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle GNUNET_CONFIGURATION_set_value_string (cfg, section, option, s); } + +/** + * Get a configuration value that should be a number. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param number where to store the numeric value of the option + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ int -GNUNET_CONFIGURATION_get_value_number (const struct GNUNET_CONFIGURATION_Handle - *cfg, const char *section, +GNUNET_CONFIGURATION_get_value_number (const struct + GNUNET_CONFIGURATION_Handle *cfg, + const char *section, const char *option, unsigned long long *number) { @@ -444,27 +616,46 @@ GNUNET_CONFIGURATION_get_value_number (const struct GNUNET_CONFIGURATION_Handle return GNUNET_OK; } + +/** + * Get a configuration value that should be a relative time. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param time set to the time value stored in the configuration + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ int GNUNET_CONFIGURATION_get_value_time (const struct GNUNET_CONFIGURATION_Handle - *cfg, const char *section, - const char *option, - struct GNUNET_TIME_Relative *time) + *cfg, const char *section, + const char *option, + struct GNUNET_TIME_Relative *time) { unsigned long long num; int ret; - ret = GNUNET_CONFIGURATION_get_value_number (cfg, - section, - option, - &num); + ret = GNUNET_CONFIGURATION_get_value_number (cfg, section, option, &num); if (ret == GNUNET_OK) time->value = (uint64_t) num; return ret; } + +/** + * Get a configuration value that should be a string. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param value will be set to a freshly allocated configuration + * value, or NULL if option is not specified + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ int -GNUNET_CONFIGURATION_get_value_string (const struct GNUNET_CONFIGURATION_Handle - *cfg, const char *section, +GNUNET_CONFIGURATION_get_value_string (const struct + GNUNET_CONFIGURATION_Handle *cfg, + const char *section, const char *option, char **value) { struct ConfigEntry *e; @@ -479,9 +670,23 @@ GNUNET_CONFIGURATION_get_value_string (const struct GNUNET_CONFIGURATION_Handle return GNUNET_OK; } + +/** + * Get a configuration value that should be in a set of + * predefined strings + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param choices NULL-terminated list of legal values + * @param value will be set to an entry in the legal list, + * or NULL if option is not specified and no default given + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ int -GNUNET_CONFIGURATION_get_value_choice (const struct GNUNET_CONFIGURATION_Handle - *cfg, const char *section, +GNUNET_CONFIGURATION_get_value_choice (const struct + GNUNET_CONFIGURATION_Handle *cfg, + const char *section, const char *option, const char **choices, const char **value) @@ -511,13 +716,18 @@ GNUNET_CONFIGURATION_get_value_choice (const struct GNUNET_CONFIGURATION_Handle return GNUNET_OK; } + /** * Test if we have a value for a particular option + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest * @return GNUNET_YES if so, GNUNET_NO if not. */ int -GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *section, const char *option) +GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option) { struct ConfigEntry *e; if ((NULL == (e = findEntry (cfg, section, option))) || (e->val == NULL)) @@ -525,17 +735,19 @@ GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle *cfg, return GNUNET_YES; } + /** * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR" * where either in the "PATHS" section or the environtment * "FOO" is set to "DIRECTORY". * - * @param old string to $-expand (will be freed!) + * @param cfg configuration to use for path expansion + * @param orig string to $-expand (will be freed!) * @return $-expanded string */ char * -GNUNET_CONFIGURATION_expand_dollar (const struct GNUNET_CONFIGURATION_Handle *cfg, - char *orig) +GNUNET_CONFIGURATION_expand_dollar (const struct GNUNET_CONFIGURATION_Handle + *cfg, char *orig) { int i; char *prefix; @@ -557,9 +769,9 @@ GNUNET_CONFIGURATION_expand_dollar (const struct GNUNET_CONFIGURATION_Handle *cf orig[i] = '\0'; post = &orig[i + 1]; } - if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, - "PATHS", - &orig[1], &prefix)) + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, + "PATHS", + &orig[1], &prefix)) { if (NULL == (env = getenv (&orig[1]))) { @@ -579,48 +791,53 @@ GNUNET_CONFIGURATION_expand_dollar (const struct GNUNET_CONFIGURATION_Handle *cf return result; } + /** * Get a configuration value that should be a string. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest * @param value will be set to a freshly allocated configuration * value, or NULL if option is not specified * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int -GNUNET_CONFIGURATION_get_value_filename (const struct GNUNET_CONFIGURATION_Handle - *data, const char *section, +GNUNET_CONFIGURATION_get_value_filename (const struct + GNUNET_CONFIGURATION_Handle *cfg, + const char *section, const char *option, char **value) { - int ret; char *tmp; - tmp = NULL; - ret = GNUNET_CONFIGURATION_get_value_string (data, section, option, &tmp); - if (ret == GNUNET_SYSERR) - return ret; - if (tmp != NULL) - { - tmp = GNUNET_CONFIGURATION_expand_dollar (data, tmp); - *value = GNUNET_STRINGS_filename_expand (tmp); - GNUNET_free (tmp); - if (*value == NULL) - ret = GNUNET_SYSERR; - } - else + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &tmp)) { *value = NULL; + return GNUNET_SYSERR; } - return ret; + tmp = GNUNET_CONFIGURATION_expand_dollar (cfg, tmp); + *value = GNUNET_STRINGS_filename_expand (tmp); + GNUNET_free (tmp); + if (*value == NULL) + return GNUNET_SYSERR; + return GNUNET_OK; } + /** * Get a configuration value that should be in a set of * "GNUNET_YES" or "GNUNET_NO". * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest * @return GNUNET_YES, GNUNET_NO or GNUNET_SYSERR */ int -GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *section, const char *option) +GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option) { static const char *yesno[] = { "YES", "NO", NULL }; const char *val; @@ -639,6 +856,11 @@ GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle * /** * Iterate over the set of filenames stored in a configuration value. * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param cb function to call on each filename + * @param cb_cls closure for cb * @return number of filenames iterated over, -1 on error */ int @@ -647,7 +869,7 @@ GNUNET_CONFIGURATION_iterate_value_filenames (const struct *cfg, const char *section, const char *option, GNUNET_FileNameCallback cb, - void *cls) + void *cb_cls) { char *list; char *pos; @@ -692,7 +914,7 @@ GNUNET_CONFIGURATION_iterate_value_filenames (const struct if (strlen (pos) > 0) { ret++; - if ((cb != NULL) && (GNUNET_OK != cb (cls, pos))) + if ((cb != NULL) && (GNUNET_OK != cb (cb_cls, pos))) { ret = GNUNET_SYSERR; break; @@ -706,6 +928,13 @@ GNUNET_CONFIGURATION_iterate_value_filenames (const struct return ret; } + +/** + * FIXME. + * + * @param value FIXME + * @return FIXME + */ static char * escape_name (const char *value) { @@ -736,6 +965,14 @@ escape_name (const char *value) return escaped; } + +/** + * FIXME. + * + * @param cls string we compare with (const char*) + * @param fn filename we are currently looking at + * @return GNUNET_OK if the names do not match, GNUNET_SYSERR if they do + */ static int test_match (void *cls, const char *fn) { @@ -743,10 +980,14 @@ test_match (void *cls, const char *fn) return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK; } + /** * Append a filename to a configuration value that * represents a list of filenames * + * @param cfg configuration to update + * @param section section of interest + * @param option option of interest * @param value filename to append * @return GNUNET_OK on success, * GNUNET_NO if the filename already in the list @@ -790,6 +1031,9 @@ GNUNET_CONFIGURATION_append_value_filename (struct GNUNET_CONFIGURATION_Handle * Remove a filename from a configuration value that * represents a list of filenames * + * @param cfg configuration to update + * @param section section of interest + * @param option option of interest * @param value filename to remove * @return GNUNET_OK on success, * GNUNET_NO if the filename is not in the list, @@ -807,13 +1051,11 @@ GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle char *end; char *match; char old; - int ret; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list)) return GNUNET_NO; match = escape_name (value); - ret = 0; pos = list; while (1) { @@ -872,10 +1114,14 @@ GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle /** * Load configuration (starts with defaults, then loads * system-specific configuration). + * + * @param cfg configuration to update + * @param filename name of the configuration file + * @return GNUNET_OK on success, GNUNET_SYSERR on error */ int GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg, - const char *cfgfn) + const char *filename) { char *baseconfig; char *ipath; @@ -889,13 +1135,21 @@ GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_free (ipath); if ((GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, baseconfig)) || - (!((cfgfn == NULL) || - (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, cfgfn))))) + (!((filename == NULL) || + (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, filename))))) { GNUNET_free (baseconfig); return GNUNET_SYSERR; } GNUNET_free (baseconfig); + if ( ((GNUNET_YES != GNUNET_CONFIGURATION_have_value (cfg, + "PATHS", + "DEFAULTCONFIG"))) && + (filename != NULL) ) + GNUNET_CONFIGURATION_set_value_string (cfg, + "PATHS", + "DEFAULTCONFIG", + filename); if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg, "TESTING", "WEAKRANDOM")) &&