| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #ifndef LIBNETDATA_INICFG_H |
| 4 | #define LIBNETDATA_INICFG_H |
| 5 | |
| 6 | /* |
| 7 | * This section manages ini config files, like netdata.conf and stream.conf |
| 8 | * |
| 9 | * It is organized like this: |
| 10 | * |
| 11 | * struct config (i.e. netdata.conf or stream.conf) |
| 12 | * .sections = a linked list of struct section |
| 13 | * .mutex = a mutex to protect the above linked list due to multi-threading |
| 14 | * .index = an AVL tree of struct section |
| 15 | * |
| 16 | * struct section (i.e. [global] or [health] of netdata.conf) |
| 17 | * .value = a linked list of struct config_option |
| 18 | * .mutex = a mutex to protect the above linked list due to multi-threading |
| 19 | * .value_index = an AVL tree of struct config_option |
| 20 | * |
| 21 | * struct config_option (ie. a name-value pair for each ini file option) |
| 22 | * |
| 23 | * The following operations on name-value options are supported: |
| 24 | * SET to set the value of an option |
| 25 | * SET DEFAULT to set the value and the default value of an option |
| 26 | * GET to get the value of an option |
| 27 | * EXISTS to check if an option exists |
| 28 | * MOVE to move an option from a section to another section, and/or rename it |
| 29 | * |
| 30 | * GET and SET operations are provided for the following data types: |
| 31 | * STRING |
| 32 | * NUMBER (long long) |
| 33 | * FLOAT (long double) |
| 34 | * BOOLEAN (false, true) |
| 35 | * BOOLEAN ONDEMAND (false, true, auto) |
| 36 | * |
| 37 | * GET and SET operations create struct config_option, if it is not already present. |
| 38 | * This allows netdata to run even without netdata.conf and stream.conf. The internal |
| 39 | * defaults are used to create the structure that should exist in the ini file and the config |
| 40 | * file can be downloaded from the server. |
| 41 | * |
| 42 | * Also 2 operations are supported for the whole config file: |
| 43 | * |
| 44 | * LOAD To load the ini file from disk |
| 45 | * GENERATE To generate the ini file (this is used to download the ini file from the server) |
| 46 | * |
| 47 | * For each option (name-value pair), the system maintains 4 flags: |
| 48 | * LOADED to indicate that the value has been loaded from the file |
| 49 | * USED to indicate that netdata used the value |
| 50 | * CHANGED to indicate that the value has been changed from the loaded value or the internal default value |
| 51 | * CHECKED is used internally for optimization (to avoid an strcmp() every time GET is called). |
| 52 | * |
| 53 | * TODO: |
| 54 | * 1. The linked lists and the mutexes can be removed and the AVL trees can become DICTIONARY. |
| 55 | * This part of the code was written before we add traversal to AVL. |
| 56 | * |
| 57 | * 2. High level data types could be supported, to simplify the rest of the code: |
| 58 | * MULTIPLE CHOICE to let the user select one of the supported keywords |
| 59 | * this would allow users see in comments the available options |
| 60 | * |
| 61 | * SIMPLE PATTERN to let the user define netdata SIMPLE PATTERNS |
| 62 | * |
| 63 | * 3. Sorting of options should be supported. |
| 64 | * Today, when the ini file is downloaded from the server, the options are shown in the order |
| 65 | * they appear in the linked list (the order they were added, listing changed options first). |
| 66 | * If we remove the linked list, the order they appear in the AVL tree will be used (which is |
| 67 | * random due to simple_hash()). |
| 68 | * Ideally, we support sorting of options when generating the ini file. |
| 69 | * |
| 70 | * 4. There is no free() operation. So, memory is freed on netdata exit. |
| 71 | * |
| 72 | * 5. Avoid memory fragmentation |
| 73 | * Since entries are created from multiple threads and a lot of allocations are required |
| 74 | * for each config_option, fragmentation can be a problem for IoT. |
| 75 | * |
| 76 | * 6. Although this way of managing options is quite flexible and dynamic, it wastes memory |
| 77 | * for the names of the options. Since most of the option names are static, we could provide |
| 78 | * a method to allocate only the dynamic option names. |
| 79 | */ |
| 80 | |
| 81 | #include "../libnetdata.h" |
| 82 | |
| 83 | #define CONFIG_FILENAME "netdata.conf" |
| 84 | |
| 85 | #define CONFIG_SECTION_GLOBAL "global" |
| 86 | #define CONFIG_SECTION_DIRECTORIES "directories" |
| 87 | #define CONFIG_SECTION_LOGS "logs" |
| 88 | #define CONFIG_SECTION_ENV_VARS "environment variables" |
| 89 | #define CONFIG_SECTION_SQLITE "sqlite" |
| 90 | #define CONFIG_SECTION_WEB "web" |
| 91 | #define CONFIG_SECTION_WEBRTC "webrtc" |
| 92 | #define CONFIG_SECTION_STATSD "statsd" |
| 93 | #define CONFIG_SECTION_PLUGINS "plugins" |
| 94 | #define CONFIG_SECTION_CLOUD "cloud" |
| 95 | #define CONFIG_SECTION_REGISTRY "registry" |
| 96 | #define CONFIG_SECTION_HEALTH "health" |
| 97 | #define CONFIG_SECTION_STREAM "stream" |
| 98 | #define CONFIG_SECTION_ML "ml" |
| 99 | #define CONFIG_SECTION_EXPORTING "exporting:global" |
| 100 | #define CONFIG_SECTION_PROMETHEUS "prometheus:exporter" |
| 101 | #define CONFIG_SECTION_HOST_LABEL "host labels" |
| 102 | #define EXPORTING_CONF "exporting.conf" |
| 103 | #define CONFIG_SECTION_PULSE "pulse" |
| 104 | #define CONFIG_SECTION_DB "db" |
| 105 | |
| 106 | // these are used to limit the configuration names and values lengths |
| 107 | // they are not enforced by config.c functions (they will strdup() all strings, no matter of their length) |
| 108 | #define CONFIG_MAX_NAME 1024 |
| 109 | #define CONFIG_MAX_VALUE 2048 |
| 110 | |
| 111 | // ---------------------------------------------------------------------------- |
| 112 | // Config definitions |
| 113 | #define CONFIG_FILE_LINE_MAX ((CONFIG_MAX_NAME + CONFIG_MAX_VALUE + 1024) * 2) |
| 114 | |
| 115 | struct config_section; |
| 116 | |
| 117 | struct config { |
| 118 | struct config_section *sections; |
| 119 | SPINLOCK spinlock; |
| 120 | avl_tree_lock index; |
| 121 | }; |
| 122 | |
| 123 | #define APPCONFIG_INITIALIZER (struct config) { \ |
| 124 | .sections = NULL, \ |
| 125 | .spinlock = SPINLOCK_INITIALIZER, \ |
| 126 | .index = { \ |
| 127 | .avl_tree = { \ |
| 128 | .root = NULL, \ |
| 129 | .compar = inicfg_section_compare, \ |
| 130 | }, \ |
| 131 | .rwlock = AVL_LOCK_INITIALIZER, \ |
| 132 | }, \ |
| 133 | } |
| 134 | |
| 135 | int inicfg_load(struct config *root, char *filename, int overwrite_used, const char *section_name); |
| 136 | |
| 137 | typedef bool (*inicfg_foreach_value_cb_t)(void *data, const char *name, const char *value); |
| 138 | size_t inicfg_foreach_value_in_section(struct config *root, const char *section, inicfg_foreach_value_cb_t cb, void *data); |
| 139 | |
| 140 | // sets a raw value, only if it is not loaded from the config |
| 141 | void inicfg_set_default_raw_value(struct config *root, const char *section, const char *name, const char *value); |
| 142 | |
| 143 | int inicfg_exists(struct config *root, const char *section, const char *name); |
| 144 | int inicfg_move(struct config *root, const char *section_old, const char *name_old, const char *section_new, const char *name_new); |
| 145 | int inicfg_move_everywhere(struct config *root, const char *name_old, const char *name_new); |
| 146 | |
| 147 | void inicfg_generate(struct config *root, BUFFER *wb, int only_changed, bool netdata_conf); |
| 148 | |
| 149 | int inicfg_section_compare(void *a, void *b); |
| 150 | |
| 151 | bool inicfg_test_boolean_value(const char *s); |
| 152 | |
| 153 | struct connector_instance { |
| 154 | char instance_name[CONFIG_MAX_NAME + 1]; |
| 155 | char connector_name[CONFIG_MAX_NAME + 1]; |
| 156 | }; |
| 157 | |
| 158 | typedef struct _connector_instance { |
| 159 | struct config_section *connector; // actual connector |
| 160 | struct config_section *instance; // This instance |
| 161 | char instance_name[CONFIG_MAX_NAME + 1]; |
| 162 | char connector_name[CONFIG_MAX_NAME + 1]; |
| 163 | struct _connector_instance *next; // Next instance |
| 164 | } _CONNECTOR_INSTANCE; |
| 165 | |
| 166 | _CONNECTOR_INSTANCE *add_connector_instance(struct config_section *connector, struct config_section *instance); |
| 167 | |
| 168 | // ---------------------------------------------------------------------------- |
| 169 | // shortcuts for the default netdata configuration |
| 170 | |
| 171 | extern struct config netdata_config; |
| 172 | |
| 173 | bool stream_conf_needs_dbengine(struct config *root); |
| 174 | bool stream_conf_has_api_enabled(struct config *root); |
| 175 | |
| 176 | /** |
| 177 | * Free all configuration resources |
| 178 | * |
| 179 | * This function frees all memory associated with a configuration, |
| 180 | * including all sections and options. |
| 181 | * |
| 182 | * @param root The config structure to free |
| 183 | */ |
| 184 | void inicfg_free(struct config *root); |
| 185 | |
| 186 | const char *inicfg_get(struct config *root, const char *section, const char *name, const char *default_value); |
| 187 | const char *inicfg_set(struct config *root, const char *section, const char *name, const char *value); |
| 188 | const char *inicfg_get_filename(struct config *root, const char *section, const char *name, const char *default_value); |
| 189 | const char *inicfg_get_path(struct config *root, const char *section, const char *name, const char *default_value); |
| 190 | const char *inicfg_get_path_list(struct config *root, const char *section, const char *name, const char *default_value); |
| 191 | const char *inicfg_get_quoted_path_list(struct config *root, const char *section, const char *name, const char *default_value); |
| 192 | const char *inicfg_get_log_path_setting(struct config *root, const char *section, const char *name, const char *default_value); |
| 193 | const char *inicfg_log_path_setting_for_display(const char *value, char *dst, size_t dst_size); |
| 194 | |
| 195 | long long inicfg_get_number(struct config *root, const char *section, const char *name, long long value); |
| 196 | long long inicfg_get_number_range(struct config *root, const char *section, const char *name, long long value, long long min, long long max); |
| 197 | |
| 198 | long long inicfg_set_number(struct config *root, const char *section, const char *name, long long value); |
| 199 | NETDATA_DOUBLE inicfg_get_double(struct config *root, const char *section, const char *name, NETDATA_DOUBLE value); |
| 200 | NETDATA_DOUBLE inicfg_set_double(struct config *root, const char *section, const char *name, NETDATA_DOUBLE value); |
| 201 | |
| 202 | // disabled |
| 203 | #define CONFIG_BOOLEAN_NO 0 |
| 204 | // enabled |
| 205 | #define CONFIG_BOOLEAN_YES 1 |
| 206 | // enabled if it has useful info when enabled |
| 207 | #define CONFIG_BOOLEAN_AUTO 2 |
| 208 | // an invalid value to check for validity (used as default initialization when needed) |
| 209 | #define CONFIG_BOOLEAN_INVALID 100 |
| 210 | |
| 211 | int inicfg_get_boolean(struct config *root, const char *section, const char *name, int value); |
| 212 | int inicfg_get_boolean_ondemand(struct config *root, const char *section, const char *name, int value); |
| 213 | int inicfg_set_boolean(struct config *root, const char *section, const char *name, int value); |
| 214 | |
| 215 | uint64_t inicfg_get_size_bytes(struct config *root, const char *section, const char *name, uint64_t default_value); |
| 216 | uint64_t inicfg_set_size_bytes(struct config *root, const char *section, const char *name, uint64_t value); |
| 217 | |
| 218 | uint64_t inicfg_get_size_mb(struct config *root, const char *section, const char *name, uint64_t default_value); |
| 219 | uint64_t inicfg_set_size_mb(struct config *root, const char *section, const char *name, uint64_t value); |
| 220 | |
| 221 | msec_t inicfg_get_duration_ms(struct config *root, const char *section, const char *name, msec_t default_value); |
| 222 | msec_t inicfg_set_duration_ms(struct config *root, const char *section, const char *name, msec_t value); |
| 223 | |
| 224 | time_t inicfg_get_duration_seconds(struct config *root, const char *section, const char *name, time_t default_value); |
| 225 | time_t inicfg_set_duration_seconds(struct config *root, const char *section, const char *name, time_t value); |
| 226 | |
| 227 | time_t inicfg_get_duration_days_to_seconds(struct config *root, const char *section, const char *name, unsigned default_value_seconds); |
| 228 | |
| 229 | #endif // LIBNETDATA_INICFG_H |