OLSRd config library Copyright (c) 2011 the olsr.org team The OLSRd config library is a complete config parser/writer API with variable backend and format support. =============================== OLSRd config schema API =============================== (see src/config/cfg_schema.c) Config schemata are an easy was to check the data of a configuration database with predefined formats and limits. It also allows to convert the content of a (un)named section into a C binary struct and compare the changes between two databases. The schema validator supports both read-only checks and removing all entries that could not be validated 1) defining a schema for a section type 2) schema sections 3) schema handling 4) validating a schema 5) conversion into binary data 6) compare two databases 7) defining a new validator 8) defining a new mapper 1) defining a schema for a section type *************************************** A schema is defined by creating an array of cfg_schema_entry structs. To make it easier for the user there are two groups of macros to create The first set of macros defined in cfg_schema.h starts with the prefix CFG_VALIDATE_. Each of them defines one cfg_schema_entry for validating one entry of configuration data. The first two parameters of this macros are always the same, the name of the entry (as a string), the default value for the entry and the help text for it. Some of the macros have other mandatory parameters as the range of values for CFG_VALIDATE_INT_MINMAX() for example. After the mandatory parameters the user can add definitions of other optional fields in the struct. struct cfg_schema_entry test_entries[] = { CFG_VALIDATE_BOOL("enable", "true", "enables feature X"), CFG_VALIDATE_PRINTABLE("logfile", "/tmp/test", "A list of logfile names", .list = true), CFG_VALIDATE_INT_MINMAX("value", "0", "a small random number", 0, 20), }; The second set of macros starts with the prefix CFG_MAP_. They are used to validate the configuration data AND map them into a predefined binary struct. Each CFG_MAP_ macro adds two parameters at the beginning, the type of the struct the data should be mapped for and the name of the field it should be mapped to. After these parameters, the macros use the same parameters as the CFG_VALIDATE_ ones. struct bin_data { bool enable_me; char *log; int int_value; }; struct cfg_schema_section test_section = { .type = "plugin", .mode = CFG_SSMODE_NAMED }; struct cfg_schema_entry test_entries[] = { CFG_MAP_BOOL(bin_data, enable_me, "enable", "true", "enables feature X"), CFG_MAP_PRINTABLE(bin_data, log, "logfile", "/tmp/test", "A list of logfile names", .list = true), CFG_MAP_INT_MINMAX(bin_data, int_value, "value", "0", "a small random number", 0, 20), }; The primary optional field of cfg_schema_entry a user might want to set is a boolean with the field name 'list'. If true, the configuration entry supports a list of elements instead of only one, each of them must be unique and is validated by the schema. 2) schema sections ****************** Each schema section can only be initialized by a single piece of code. To allow other parts of the code to contribute schema entries to an existing section, it has to provide a pointer to its initialized cfg_schema_section. struct cfg_schema_section test_section = { .type = "plugin", .mode = CFG_SSMODE_UNNAMED }; 3) schema handling ****************** The schema sections have to be aggregated into a single cfg_schema to use them for validation or mapping. An unused cfg_schema has to be initialized with the cfg_schema_add() call. At the end of its lifetime, all allocated resources should be freed with the cfg_schema_remove() call. The cfg_schema_add_section() call adds a section to a schema, the cfg_schema_remove_section() removes it again. Multiple overlapping schema sections can be added to a cfg_schema. 4) validating a schema ********************** To validate a configuration database, it first has to be linked to a schema with the cfg_db_link_schema() call (see config_db.txt). After this the function cfg_schema_validate() can be used to validate the database or remove all non-validated entries. The cfg_schema_validate() call needs four parameters. The first one is a pointer to the configuration database, the second one 'cleanup' should be true if the api call should remove non-validated. If the third one 'ignore_unknown_sections' is true, the validation ignores all database sections that have no corresponding schema_section. The last parameter is a pointer to an autobuf to get the output of the validation. 5) conversion into binary data ****************************** The cfg_schema_tobin() call allows to automatically map a number of configuration entries into a binary struct. It requires a pointer to the target struct, a pointer to the (un)named section that should be converted, a pointer to an array of cfg_schema_entry objects and the number of this objects. The api call will then convert all entries with a corresponding mapper in the cfg_schema_entry into the struct. Its good practice to validate a set of configuration before its written into a binary struct. If one of the conversion fails, the struct will be partly overwritten. 6) compare two databases ************************ Each cfg_schema_section has the cb_delta_handler() callback pointer for comparing databases and trigger the callbacks of the sections for the changes between them. When the user calls the cfg_schema_handle_db_changes() functions with the old and the new database, the function will loop through all sections of both databases. For each section that has been added, changed or removed it will initialize the pre/post variable in the corresponding cfg_schema_section and the pre/post/delta_changed variable of each of its cfg_schema_entry objects. After this the cb_delta_handler() callback is called. 7) defining a new validator *************************** 8) defining a new mapper ************************