| /* ---------------------------------------------------------------------------- |
| * Copyright CEA/DAM/DIF (2007) |
| * contributeur : Thomas LEIBOVICI thomas.leibovici@cea.fr |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 3 of the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| * |
| * --------------------------------------- |
| */ |
| #ifndef _CONFIG_PARSING_H |
| #define _CONFIG_PARSING_H |
| |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <stdint.h> |
| #include <stdbool.h> |
| #include <string.h> |
| #include <stdio.h> |
| #include <sys/types.h> |
| |
| /* opaque type */ |
| typedef caddr_t config_file_t; |
| |
| typedef enum { CONFIG_ITEM_BLOCK = 1, CONFIG_ITEM_VAR } config_item_type; |
| |
| /** |
| * @brief Data structures for config parse tree processing |
| */ |
| |
| enum term_type { |
| TERM_TOKEN = 1, |
| TERM_REGEX, |
| TERM_PATH, |
| TERM_STRING, |
| TERM_DQUOTE, |
| TERM_SQUOTE, |
| TERM_TRUE, |
| TERM_FALSE, |
| TERM_DECNUM, |
| TERM_HEXNUM, |
| TERM_OCTNUM, |
| TERM_V4_ANY, |
| TERM_V4ADDR, |
| TERM_V4CIDR, |
| TERM_V6ADDR, |
| TERM_V6CIDR, |
| TERM_FSID, |
| TERM_NETGROUP |
| }; |
| |
| enum config_type { |
| CONFIG_NULL = 0, |
| CONFIG_INT16, |
| CONFIG_UINT16, |
| CONFIG_INT32, |
| CONFIG_UINT32, |
| CONFIG_INT64, |
| CONFIG_UINT64, |
| CONFIG_ANON_ID, |
| CONFIG_FSID, |
| CONFIG_STRING, |
| CONFIG_PATH, |
| CONFIG_LIST, |
| CONFIG_ENUM, |
| CONFIG_TOKEN, |
| CONFIG_BOOL, |
| CONFIG_BOOLBIT, |
| CONFIG_IP_ADDR, |
| CONFIG_INET_PORT, |
| CONFIG_BLOCK, |
| CONFIG_PROC |
| }; |
| |
| #define CONFIG_UNIQUE 0x001 /*< only one instance allowed */ |
| #define CONFIG_MANDATORY 0x002 /*< param must be present */ |
| #define CONFIG_MODE 0x004 /*< this param is octal "mode" */ |
| #define CONFIG_RELAX 0x008 /*< this block has extra params |
| * so don't complain about them */ |
| #define CONFIG_MARK_SET 0x010 /*< Mark this param as set */ |
| |
| /** |
| * @brief Config file processing error type |
| * |
| * This is a better way than a bunch of mask bits... |
| * Examination of the error type lets the calling code decide |
| * just how bad and messed up the config file is. |
| * |
| * NOTE: If you add an error here, update err_type_str() and friends |
| * as well. |
| */ |
| |
| struct config_error_type { |
| bool scan:1; /*< lexer/scanner */ |
| bool parse:1; /*< parser rules */ |
| bool init:1; /*< block initialization */ |
| bool fsal:1; /*< fsal load failure */ |
| bool export_:1; /*< export create failure */ |
| bool resource:1; /*< system resource */ |
| bool unique:1; /*< unique block/param */ |
| bool invalid:1; /*< invalid param value */ |
| bool missing:1; /*< missing mandatory parameter */ |
| bool validate:1; /*< commit param validation */ |
| bool exists:1; /*< block already exists */ |
| bool internal:1; /*< internal error */ |
| bool bogus:1; /*< bogus (deprecated?) param */ |
| bool dispose:1; /*< Not actually an error, but we need to |
| dispose of the config item anyway. */ |
| uint32_t errors; /*< cumulative error count for parse+proc */ |
| char *diag_buf; /*< buffer for scan+parse+processing msgs */ |
| size_t diag_buf_size; /*< size of diag buffer used by memstream */ |
| FILE *fp; /*< FILE * for memstream */ |
| }; |
| |
| /** @brief Error detail decoders |
| */ |
| |
| /** |
| * @brief Test for errors that require us to exit the server |
| */ |
| |
| static inline bool config_error_is_fatal(struct config_error_type *err_type) |
| { |
| return err_type->scan || err_type->parse || err_type->init || |
| err_type->fsal || err_type->resource; |
| } |
| |
| /** |
| * @brief Test for errors that make the processed block unuseable |
| */ |
| |
| static inline bool config_error_is_crit(struct config_error_type *err_type) |
| { |
| return config_error_is_fatal(err_type) || err_type->internal || |
| err_type->invalid || err_type->export_ || err_type->missing; |
| } |
| |
| /** |
| * @brief Test for errors that will not cause problems |
| */ |
| |
| static inline bool config_error_is_harmless(struct config_error_type *err_type) |
| { |
| return !(config_error_is_crit(err_type) || |
| err_type->unique || err_type->exists || err_type->dispose); |
| } |
| |
| /** |
| * @brief Test that there are no errors at all |
| * |
| * NOTE: This is valid so long as sizeof(struct config_error_type) |
| * == sizeof(uint16_t). Use uint32_t if this expands beyond 16 bools. |
| * It could be a union here but that makes for messy code all |
| * over the place. Handle with care and it won't bite you. |
| */ |
| |
| static inline bool config_error_no_error(struct config_error_type *err_type) |
| { |
| return *(uint16_t *)err_type == 0; |
| } |
| |
| /** |
| * @brief Collect/combine errors |
| */ |
| |
| static inline void config_error_comb_errors(struct config_error_type *err_type, |
| struct config_error_type *more_errs) |
| { |
| *(uint16_t *)err_type |= *(uint16_t *)more_errs; |
| } |
| |
| struct config_block; |
| struct config_item; |
| |
| /** |
| * @brief token list for CSV options |
| */ |
| |
| struct config_item_list { |
| const char *token; |
| uint32_t value; |
| }; |
| |
| #define CONFIG_LIST_TOK(_token_, _flags_) \ |
| { .token = _token_, .value = _flags_} |
| |
| #define CONFIG_LIST_EOL { .token = NULL, .value = 0} |
| /** |
| * @brief A config file parameter |
| * |
| * These are structured as an initialized array with |
| * CONFIG_EOL as the last initializer. |
| * |
| * The union wraps up minimum, maximum, and default values. |
| * The type field is used to both validate the node type |
| * and to switch the union. Each type has conversion functions |
| * either inline or as separate functions. |
| * |
| * The CONFIG_BLOCK has special handling because it may have to |
| * allocate memory for the structure and later link it to the |
| * link_mem or other structures. Two functions provide this linkage. |
| * |
| * The following two parameters are opaque pointers to the config |
| * parsing functions. They only make semantic sense to the 'init' |
| * and 'commit' functions. |
| * |
| * link_mem |
| * This is an opaque pointer to the data structure member in the |
| * structure being filled by the enclosing block. This is typically |
| * a glist_head, or in the simpler case, a struct pointer. |
| * |
| * self_struct |
| * This is an opaque pointer the data structure that will be filled |
| * by this block. |
| * |
| * init |
| * The init function takes two void * arguments that are used as |
| * follows: |
| * |
| * link_mem == NULL, self_struct != NULL |
| * This call is during a do_block_init where the members of the |
| * structure are being initialized to their defaults. For a |
| * block, this may mean the initialization of things like glist |
| * heads which can be done only once. The return self_struct on success |
| * and NULL for errors. |
| * |
| * link_mem != NULL, self_struct == NULL |
| * This call can potentially allocate space for the structure defined |
| * by the parameter list. The link_mem argument is passed for reference. |
| * Some data structures are related but not linked. For example, two |
| * structures within an enclosing structure where a container_of the |
| * link_mem references the enclosing which can now be used to dereference |
| * the "self_struct" structure of interest. It should initialize any members |
| * that are NOT initialized by the do_block_init pass. It should not |
| * link the self_struct structure to the link_mem or initialize things like |
| * mutexes or other linked lists. See commit. An example here are |
| * non-settable FSAL parameters. It returns a pointer to the space. |
| * |
| * link_mem != NULL, self_struct != NULL |
| * This call is to free or release any resouces in this allocated |
| * or referenced block. The link_mem argument is passed so that |
| * dereferences as above are possible. It should not attempt to |
| * change the link_mem such as doing glist removes. This is only |
| * called on errors. return NULL; |
| * |
| * link_mem == NULL, self_struct == NULL |
| * This is asserted as not possible. |
| * |
| * commit |
| * The commit function has two functions. First, it (optionally) |
| * validates the completed data structure. If the validation fails, |
| * it returns non-zero error count. If the validation succeeds, it |
| * can then do any structure specific linkage or state setting for |
| * the structure. This state includes other linked lists and system |
| * resources like mutexes. |
| * |
| * The node arg is provided for the case where the commit needs to reference |
| * the parse tree. This is an opaque pointer that only the config_parse |
| * know how to use. The link_mem is provided for cases where the link_mem |
| * has as glist head that the self_struct is added to. It returns 0 to |
| * indicate success. |
| */ |
| |
| struct config_item { |
| char *name; |
| enum config_type type; /* switches union */ |
| int flags; |
| union { |
| struct { /* CONFIG_BOOL */ |
| bool def; |
| } b; |
| struct { /* CONFIG_STRING | CONFIG_PATH */ |
| int minsize; |
| int maxsize; |
| const char *def; |
| } str; |
| struct { /* CONFIG_IP_ADDR */ |
| const char *def; |
| } ip; |
| struct { /* CONFIG_INT16 */ |
| int16_t minval; |
| int16_t maxval; |
| int16_t def; |
| } i16; |
| struct { /* CONFIG_UINT16 */ |
| uint16_t minval; |
| uint16_t maxval; |
| uint16_t def; |
| } ui16; |
| struct { /* CONFIG_INT32 */ |
| int32_t minval; |
| int32_t maxval; |
| int32_t def; |
| uint32_t bit; |
| size_t set_off; |
| } i32; |
| struct { /* CONFIG_UINT32 */ |
| uint32_t minval; |
| uint32_t maxval; |
| uint32_t def; |
| } ui32; |
| struct { /* CONFIG_INT64 */ |
| int64_t minval; |
| int64_t maxval; |
| int64_t def; |
| uint32_t bit; |
| size_t set_off; |
| } i64; |
| struct { /* CONFIG_UINT64 */ |
| uint64_t minval; |
| uint64_t maxval; |
| uint64_t def; |
| uint32_t bit; |
| size_t set_off; |
| } ui64; |
| struct { /* CONFIG_FSID */ |
| int64_t def_maj; |
| int64_t def_min; |
| uint32_t bit; |
| size_t set_off; |
| } fsid; |
| struct { /* CONFIG_LIST | CONFIG_ENUM | CONFIG_ENUM_SET | |
| CONFIG_LIST_BITS | CONFIG_ENUM_BITS */ |
| uint32_t def; |
| uint32_t mask; |
| struct config_item_list *tokens; |
| size_t set_off; |
| } lst; |
| struct { /* CONFIG_BOOLBIT */ |
| bool def; |
| uint32_t bit; |
| size_t set_off; |
| } bit; |
| struct { /* CONFIG_BLOCK */ |
| void *(*init)(void *link_mem, void *self_struct); |
| struct config_item *params; |
| int (*commit)(void *node, void *link_mem, |
| void *self_struct, |
| struct config_error_type *err_type); |
| void (*display)(const char *step, |
| void *node, void *link_mem, |
| void *self_struct); |
| } blk; |
| struct { /* CONFIG_PROC */ |
| size_t set_off; |
| void *(*init)(void *link_mem, void *self_struct); |
| int (*handler)(const char *token, |
| enum term_type type_hint, |
| struct config_item *item, |
| void *param_addr, |
| void *cnode, |
| struct config_error_type *err_type); |
| } proc; |
| } u; |
| size_t off; /* offset into struct pointed to by opaque_dest */ |
| }; |
| |
| /** |
| * @brief Macros for defining arrays of config items. |
| * |
| * A config_item array is defined with one or more of the following |
| * macros with the last entry being CONFIG_EOL which will supply |
| * the necessary NULL pointer to terminate the walk. |
| * |
| * The naming has the form: |
| * CONF_<something special>_<type> |
| * |
| * where "something special" is: |
| * |
| * ITEM - generic entry |
| * |
| * MAND - This is a mandatory entry and will throw an error if there |
| * is no config file entry for it. |
| * |
| * UNIQ - This is a unique entry. Multiple definitions are an error. |
| * |
| * RELAX - a block where unrecognized parameters are not reported errors. |
| * |
| * The "type" field is used for decoding and for storage. These match |
| * the target structure members. This set defines what is currently used. |
| * |
| * NOOP - Used to indicate a parameter name is expected but that it is |
| * used/processed elsewhere. |
| * |
| * FSID - A filesystem id, a uint64_t '.' uint64_t |
| * |
| * LIST - a comma separated list of bit flags |
| * |
| * ENUM - a single token and its enumerated type |
| * |
| * BLOCK - a sub-block. It points to another item list etc. |
| * |
| * BOOLBIT - Similar to a LIST but it is a boolean that sets flag bits |
| * |
| * BOOL - a boolean |
| * |
| * STR - A string that must have a size >= min and <= max size |
| * |
| * PATH - a string defining a filesystem path |
| * |
| * I<size> - A signed integer of 'size' bits |
| * |
| * UI<size> - an unsigned integer of 'size' bits |
| * |
| * MODE - an octal integer used as the 'mode' bits of an inode |
| * |
| * PROC - Calls a function to process the token value |
| * |
| * There are a few specialized item entries |
| * |
| * CONF_ITEM_IP_ADDR processes an IP (both v4 and v6) address specification |
| * |
| * CONF_ITEM_INET_PORT processes an unsigned 16 bit integer in |
| * network byte order. |
| * |
| */ |
| |
| #define CONF_ITEM_NOOP(_name_) \ |
| { .name = _name_, \ |
| .type = CONFIG_NULL, \ |
| } |
| |
| #define CONF_ITEM_FSID(_name_, _def_maj_, _def_min_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_FSID, \ |
| .u.fsid.def_maj = _def_maj_, \ |
| .u.fsid.def_min = _def_min_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| #define CONF_ITEM_FSID_SET(_name_, _def_maj_, _def_min_, _struct_, \ |
| _mem_, _bit_, _set_) \ |
| { .name = _name_, \ |
| .type = CONFIG_FSID, \ |
| .flags = CONFIG_MARK_SET, \ |
| .u.fsid.def_maj = _def_maj_, \ |
| .u.fsid.def_min = _def_min_, \ |
| .u.fsid.bit = _bit_, \ |
| .u.fsid.set_off = offsetof(struct _struct_, _set_), \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| #define CONF_ITEM_BLOCK(_name_, _params_, _init_, _commit_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_BLOCK, \ |
| .u.blk.init = _init_, \ |
| .u.blk.params = _params_, \ |
| .u.blk.commit = _commit_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_RELAX_BLOCK(_name_, _params_, _init_, _commit_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_BLOCK, \ |
| .flags = CONFIG_RELAX, \ |
| .u.blk.init = _init_, \ |
| .u.blk.params = _params_, \ |
| .u.blk.commit = _commit_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_PROC(_name_, _init_, _handler_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_PROC, \ |
| .u.proc.init = _init_, \ |
| .u.proc.handler = _handler_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_LIST(_name_, _def_, _tokens_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_LIST, \ |
| .u.lst.def = _def_, \ |
| .u.lst.mask = UINT32_MAX, \ |
| .u.lst.set_off = UINT32_MAX, \ |
| .u.lst.tokens = _tokens_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_LIST_BITS(_name_, _def_, _mask_, _tokens_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_LIST, \ |
| .u.lst.def = _def_, \ |
| .u.lst.mask = _mask_, \ |
| .u.lst.set_off = UINT32_MAX, \ |
| .u.lst.tokens = _tokens_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_LIST_BITS_SET(_name_, _def_, _mask_, _tokens_, _struct_, \ |
| _mem_, _set_) \ |
| { .name = _name_, \ |
| .type = CONFIG_LIST, \ |
| .flags = CONFIG_MARK_SET, \ |
| .u.lst.def = _def_, \ |
| .u.lst.mask = _mask_, \ |
| .u.lst.set_off = offsetof(struct _struct_, _set_), \ |
| .u.lst.tokens = _tokens_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_BOOLBIT(_name_, _def_, _bit_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_BOOLBIT, \ |
| .u.bit.def = _def_, \ |
| .u.bit.bit = _bit_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_BOOLBIT_SET(_name_, _def_, _bit_, _struct_, _mem_, _set_) \ |
| { .name = _name_, \ |
| .type = CONFIG_BOOLBIT, \ |
| .flags = CONFIG_MARK_SET, \ |
| .u.bit.def = _def_, \ |
| .u.bit.bit = _bit_, \ |
| .u.bit.set_off = offsetof(struct _struct_, _set_), \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_MAND_LIST(_name_, _def_, _tokens_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_LIST, \ |
| .flags = CONFIG_MANDATORY, \ |
| .u.lst.def = _def_, \ |
| .u.lst.tokens = _tokens_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| /* Use CONF_ITEM_TOKEN for a variable that is set to a single enum |
| * value. The CONF_ITEM_ENUM_* macros are for setting one or more |
| * bits within a field (I know, a bit confusing...). |
| */ |
| |
| #define CONF_ITEM_ENUM_BITS(_name_, _def_, _mask_, _tokens_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_ENUM, \ |
| .u.lst.def = _def_, \ |
| .u.lst.mask = _mask_, \ |
| .u.lst.tokens = _tokens_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_ENUM_BITS_SET(_name_, _def_, _mask_, _tokens_, _struct_, \ |
| _mem_, _set_) \ |
| { .name = _name_, \ |
| .type = CONFIG_ENUM, \ |
| .flags = CONFIG_MARK_SET, \ |
| .u.lst.def = _def_, \ |
| .u.lst.mask = _mask_, \ |
| .u.lst.set_off = offsetof(struct _struct_, _set_), \ |
| .u.lst.tokens = _tokens_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_TOKEN(_name_, _def_, _tokens_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_TOKEN, \ |
| .u.lst.def = _def_, \ |
| .u.lst.tokens = _tokens_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_INDEX_TOKEN(_name_, _def_, _tokens_, _idx_, _sizeof_) \ |
| { .name = _name_, \ |
| .type = CONFIG_TOKEN, \ |
| .u.lst.def = _def_, \ |
| .u.lst.tokens = _tokens_, \ |
| .off = (sizeof(_sizeof_) * _idx_) \ |
| } |
| |
| #define CONF_ITEM_BOOL(_name_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_BOOL, \ |
| .u.b.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_STR(_name_, _minsize_, _maxsize_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_STRING, \ |
| .u.str.minsize = _minsize_, \ |
| .u.str.maxsize = _maxsize_, \ |
| .u.str.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| #define CONF_MAND_STR(_name_, _minsize_, _maxsize_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_STRING, \ |
| .flags = CONFIG_UNIQUE|CONFIG_MANDATORY, \ |
| .u.str.minsize = _minsize_, \ |
| .u.str.maxsize = _maxsize_, \ |
| .u.str.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| #define CONF_ITEM_PATH(_name_, _minsize_, _maxsize_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_PATH, \ |
| .u.str.minsize = _minsize_, \ |
| .u.str.maxsize = _maxsize_, \ |
| .u.str.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| #define CONF_MAND_PATH(_name_, _minsize_, _maxsize_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_PATH, \ |
| .flags = CONFIG_UNIQUE|CONFIG_MANDATORY, \ |
| .u.str.minsize = _minsize_, \ |
| .u.str.maxsize = _maxsize_, \ |
| .u.str.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| #define CONF_UNIQ_PATH(_name_, _minsize_, _maxsize_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_PATH, \ |
| .flags = CONFIG_UNIQUE, \ |
| .u.str.minsize = _minsize_, \ |
| .u.str.maxsize = _maxsize_, \ |
| .u.str.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| #define CONF_ITEM_IP_ADDR(_name_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_IP_ADDR, \ |
| .u.ip.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| #define CONF_MAND_IP_ADDR(_name_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_IP_ADDR, \ |
| .flags = CONFIG_UNIQUE|CONFIG_MANDATORY, \ |
| .u.ip.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_INET_PORT(_name_, _min_, _max_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_INET_PORT, \ |
| .u.ui16.minval = _min_, \ |
| .u.ui16.maxval = _max_, \ |
| .u.ui16.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_MAND_INET_PORT(_name_, _min_, _max_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_INET_PORT, \ |
| .flags = CONFIG_UNIQUE|CONFIG_MANDATORY, \ |
| .u.ui16.minval = _min_, \ |
| .u.ui16.maxval = _max_, \ |
| .u.ui16.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_I16(_name_, _min_, _max_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_INT16, \ |
| .u.ui16.minval = _min_, \ |
| .u.ui16.maxval = _max_, \ |
| .u.ui16.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_UI16(_name_, _min_, _max_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_UINT16, \ |
| .u.ui16.minval = _min_, \ |
| .u.ui16.maxval = _max_, \ |
| .u.ui16.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_MAND_UI16(_name_, _min_, _max_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_UINT16, \ |
| .flags = CONFIG_UNIQUE|CONFIG_MANDATORY, \ |
| .u.ui16.minval = _min_, \ |
| .u.ui16.maxval = _max_, \ |
| .u.ui16.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_I32(_name_, _min_, _max_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_INT32, \ |
| .u.i32.minval = _min_, \ |
| .u.i32.maxval = _max_, \ |
| .u.i32.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_I32_SET(_name_, _min_, _max_, _def_, _struct_, _mem_, \ |
| _bit_, _set_) \ |
| { .name = _name_, \ |
| .type = CONFIG_INT32, \ |
| .flags = CONFIG_MARK_SET, \ |
| .u.i32.minval = _min_, \ |
| .u.i32.maxval = _max_, \ |
| .u.i32.def = _def_, \ |
| .u.i32.bit = _bit_, \ |
| .u.i32.set_off = offsetof(struct _struct_, _set_), \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_ANON_ID_SET(_name_, _def_, _struct_, _mem_, \ |
| _bit_, _set_) \ |
| { .name = _name_, \ |
| .type = CONFIG_ANON_ID, \ |
| .flags = CONFIG_MARK_SET, \ |
| .u.i64.minval = INT32_MIN, \ |
| .u.i64.maxval = UINT32_MAX, \ |
| .u.i64.def = _def_, \ |
| .u.i64.bit = _bit_, \ |
| .u.i64.set_off = offsetof(struct _struct_, _set_), \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_UI32(_name_, _min_, _max_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_UINT32, \ |
| .u.ui32.minval = _min_, \ |
| .u.ui32.maxval = _max_, \ |
| .u.ui32.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_MAND_UI32(_name_, _min_, _max_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_UINT32, \ |
| .flags = CONFIG_UNIQUE|CONFIG_MANDATORY, \ |
| .u.ui32.minval = _min_, \ |
| .u.ui32.maxval = _max_, \ |
| .u.ui32.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_MODE(_name_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_UINT32, \ |
| .flags = CONFIG_MODE, \ |
| .u.ui32.minval = 0, \ |
| .u.ui32.maxval = 0777, \ |
| .u.ui32.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_I64(_name_, _min_, _max_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_INT64, \ |
| .u.i64.minval = _min_, \ |
| .u.i64.maxval = _max_, \ |
| .u.i64.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_UI64(_name_, _min_, _max_, _def_, _struct_, _mem_) \ |
| { .name = _name_, \ |
| .type = CONFIG_UINT64, \ |
| .u.ui64.minval = _min_, \ |
| .u.ui64.maxval = _max_, \ |
| .u.ui64.def = _def_, \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONF_ITEM_UI64_SET(_name_, _min_, _max_, _def_, _struct_, \ |
| _mem_, _bit_, _set_) \ |
| { .name = _name_, \ |
| .type = CONFIG_UINT64, \ |
| .flags = CONFIG_MARK_SET, \ |
| .u.ui64.minval = _min_, \ |
| .u.ui64.maxval = _max_, \ |
| .u.ui64.def = _def_, \ |
| .u.ui64.bit = _bit_, \ |
| .u.ui64.set_off = offsetof(struct _struct_, _set_), \ |
| .off = offsetof(struct _struct_, _mem_) \ |
| } |
| |
| #define CONFIG_EOL {.name = NULL, .type = CONFIG_NULL} |
| |
| /** |
| * @brief Configuration Block |
| * |
| * This is used for both config file parse tree processing |
| * and DBus property settings. |
| */ |
| |
| struct config_block { |
| char *dbus_interface_name; |
| struct config_item blk_desc; |
| }; |
| |
| /** |
| * @brief Check whether a given value is prime or not |
| * |
| * @param[in] v A given integer |
| * |
| * @return Whether it's prime or not. |
| */ |
| static inline bool is_prime(int v) |
| { |
| int i, m; |
| |
| if (v <= 1) |
| return false; |
| if (v == 2) |
| return true; |
| if (v % 2 == 0) |
| return false; |
| /* dont link with libm just for this */ |
| #ifdef LINK_LIBM |
| m = (int)sqrt(v); |
| #else |
| m = v - 1; |
| #endif |
| for (i = 3; i <= m; i += 2) { |
| if (v % i == 0) |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * @brief Parse the content of a configuration file into a parse tree. |
| * |
| * @param file_path [IN] local path to the config file |
| * @param err_type [OUT] Error type. Check this for success. |
| * |
| * @return pointer to parse tree. Must be freed if != NULL |
| */ |
| config_file_t config_ParseFile(char *file_path, |
| struct config_error_type *err_type); |
| |
| /** |
| * config_Print: |
| * Print the content of the syntax tree |
| * to a file. |
| */ |
| void config_Print(FILE *output, config_file_t config); |
| |
| /* Free the memory structure that store the configuration. */ |
| void config_Free(config_file_t config); |
| |
| /* Find the root of the parse tree given a TYPE_BLOCK node */ |
| config_file_t get_parse_root(void *node); |
| |
| struct config_node_list { |
| void *tree_node; |
| struct config_node_list *next; |
| }; |
| |
| /* find a node in the parse tree using expression */ |
| int find_config_nodes(config_file_t config, char *expr, |
| struct config_node_list **node_list, |
| struct config_error_type *err_type); |
| |
| /* fill configuration structure from parse tree */ |
| int load_config_from_node(void *tree_node, |
| struct config_block *conf_blk, |
| void *param, |
| bool unique, |
| struct config_error_type *err_type); |
| |
| /* fill configuration structure from parse tree */ |
| int load_config_from_parse(config_file_t config, |
| struct config_block *conf_blk, |
| void *param, |
| bool unique, |
| struct config_error_type *err_type); |
| |
| /* translate err_type values to log/dbus error string*/ |
| const char *config_term_name(enum term_type type); |
| const char *config_term_desc(enum term_type type); |
| |
| char *err_type_str(struct config_error_type *err_type); |
| bool init_error_type(struct config_error_type *err_type); |
| void config_errs_to_log(char *err, void *, |
| struct config_error_type *err_type); |
| void config_proc_error(void *cnode, |
| struct config_error_type *err_type, |
| char *format, ...); |
| void report_config_errors(struct config_error_type *err_type, void *dest, |
| void (*logger)(char *msg, void *dest, |
| struct config_error_type *err_type)); |
| |
| |
| /** |
| * @brief NOOP config initializer and commit functions. |
| * Most config blocks refer to static structures that don't |
| * need either allocation and sometimes validation/commit |
| */ |
| void *noop_conf_init(void *link_mem, void *self_struct); |
| int noop_conf_commit(void *node, void *link_mem, void *self_struct, |
| struct config_error_type *err_type); |
| |
| #endif |