static void typecheck_config_array(config_setting_t *array) { assert(config_setting_is_array(array)); int length = config_setting_length(array); if (length > 6) die("Arrays must be fewer than seven elements."); for (int i = 0; i < length; i++) { config_setting_t *elem = config_setting_get_elem(array, i); int val = config_setting_get_int(elem); if (config_setting_type(elem) != CONFIG_TYPE_INT || val > 0xFF || val < -1) { die("Arrays must only contain numbers in the range -1 to 0xFF."); } } }
int read_volumes_local_config(config_t * config, bool reread) { config_setting_t * settings = config_lookup(config, "volumes"); if ((settings == NULL) && (config_setting_is_array(settings) != CONFIG_TRUE)) { // failed to locate volumes configuration section message(LOG_ERROR, FACILITY_CONFIG, "Volumes local config section is missing, please add it to local config.\n"); return CONFIG_FALSE; } config_setting_t * volume_setting; int i; // for each volume element for (i = 0; (volume_setting = config_setting_get_elem(settings, i)) != NULL; ++i) { uint64_t id = 0; uint64_t cache_size; const char * local_path; int rv; rv = config_setting_lookup_uint64_t(volume_setting, "id", &id); if (rv != CONFIG_TRUE || !is_valid_volume_id(id)) { // failed to read volume_setting id from zfsd.config message(LOG_ERROR, FACILITY_CONFIG, "Volume id config key is wrong type or is missing in local config.\n"); return CONFIG_FALSE; } rv = config_setting_lookup_uint64_t(volume_setting, "cache_size", &cache_size); if (rv != CONFIG_TRUE) { // failed to read volume_setting cache limit, assume 0 will be fine message(LOG_WARNING, FACILITY_CONFIG, "Volume cache_size key is wrong type or is missing in local config, assuming cache_size = 0.\n"); cache_size = 0; } rv = config_setting_lookup_string(volume_setting, "local_path", &local_path); if (rv != CONFIG_TRUE) { // failed to get local path message(LOG_ERROR, FACILITY_CONFIG, "Volume local_path config keyi is wrong type or is missing in local config.\n"); return CONFIG_FALSE; } create_volume_from_local_config(id, cache_size, local_path, reread); } return CONFIG_TRUE; }
static void typecheck_config_ifgroup(config_setting_t *ifgroup) { assert(config_setting_is_group(ifgroup)); config_setting_t *dflt = config_setting_get_member(ifgroup, "default"); config_setting_t *mac = config_setting_get_member(ifgroup, "mac"); config_setting_t *interface = config_setting_get_member(ifgroup, "interface"); if (dflt == NULL && interface == NULL) die("Interface group must contain either \"default\" or \"interface\" elements."); if (dflt != NULL && interface != NULL) die("Interface group must contain only one of \"default\" and \"interface\" elements."); if (mac == NULL) die("Interface group must contain a \"mac\" element."); if (dflt != NULL && config_setting_type(dflt) != CONFIG_TYPE_BOOL) die("Interface group element \"default\" must be a bool."); if (interface != NULL && config_setting_type(interface) != CONFIG_TYPE_STRING) die("Interface group element \"interface\" must be a string."); if (!config_setting_is_array(mac)) die("Interface group element \"mac\" must be an array."); typecheck_config_array(mac); }
/********************* return RET_NOK on error *********************/ ret_code_t entry_copy_config(config_setting_t * source, config_setting_t * dest) { config_setting_t * new_source; config_setting_t * new_dest; int index = -1; int int_value; long long long_value; double double_value; const char * string; while((new_source=config_setting_get_elem(source,index+1))!= NULL ) { index++; if(config_setting_is_group(new_source)) { if(!entry_copy_aggregate(new_source,dest,CONFIG_TYPE_GROUP)) { return RET_NOK; } } else if(config_setting_is_array(new_source)) { if(!entry_copy_aggregate(new_source,dest,CONFIG_TYPE_ARRAY)) { return RET_NOK; } } else if(config_setting_is_list(new_source)) { if(!entry_copy_aggregate(new_source,dest,CONFIG_TYPE_LIST)) { return RET_NOK; } } else { switch(config_setting_type(new_source)) { case CONFIG_TYPE_INT: int_value = config_setting_get_int(new_source); new_dest = config_setting_add (dest, config_setting_name(new_source),CONFIG_TYPE_INT); config_setting_set_int(new_dest,int_value); continue; case CONFIG_TYPE_INT64: long_value = config_setting_get_int64(new_source); new_dest = config_setting_add (dest, config_setting_name(new_source),CONFIG_TYPE_INT64); config_setting_set_int64(new_dest,long_value); continue; case CONFIG_TYPE_FLOAT: double_value = config_setting_get_float(new_source); new_dest = config_setting_add (dest, config_setting_name(new_source),CONFIG_TYPE_FLOAT); config_setting_set_float(new_dest,double_value); continue; case CONFIG_TYPE_BOOL: int_value = config_setting_get_bool(new_source); new_dest = config_setting_add (dest, config_setting_name(new_source),CONFIG_TYPE_BOOL); config_setting_set_bool(new_dest,int_value); continue; case CONFIG_TYPE_STRING: string = config_setting_get_string(new_source); new_dest = config_setting_add (dest, config_setting_name(new_source),CONFIG_TYPE_STRING); config_setting_set_string(new_dest,string); continue; default: return RET_NOK; } } } return RET_OK; }
static const char *test_libconfig_setting_types(void) { struct config_t config; struct config_setting_t *t; const char *input = "/* Test File */\n" "Setting_Int: 1;\n" "Setting_Int64: 1L;\n" "Setting_Float: 1.0;\n" "Setting_Bool: true;\n" "Setting_String: \"1\";\n" "Setting_Array: [ ];\n" "Setting_Group: { };\n" "Setting_List: ( );\n" "/* End test file */\n"; if (libconfig->read_string(&config, input) == CONFIG_FALSE) { libconfig->destroy(&config); return "Unable to parse configuration."; } if (config_setting_type(config.root) != CONFIG_TYPE_GROUP) { libconfig->destroy(&config); return "CONFIG_TYPE_GROUP failed."; } if ((t = libconfig->lookup(&config, "Setting_Int")) == NULL || config_setting_type(t) != CONFIG_TYPE_INT || config_setting_is_group(t) || config_setting_is_array(t) || config_setting_is_list(t) || config_setting_is_aggregate(t) || !config_setting_is_scalar(t) || !config_setting_is_number(t) ) { libconfig->destroy(&config); return "CONFIG_TYPE_INT failed."; } if ((t = libconfig->lookup(&config, "Setting_Int64")) == NULL || config_setting_type(t) != CONFIG_TYPE_INT64 || config_setting_is_group(t) || config_setting_is_array(t) || config_setting_is_list(t) || config_setting_is_aggregate(t) || !config_setting_is_scalar(t) || !config_setting_is_number(t) ) { libconfig->destroy(&config); return "CONFIG_TYPE_INT64 failed."; } if ((t = libconfig->lookup(&config, "Setting_Float")) == NULL || config_setting_type(t) != CONFIG_TYPE_FLOAT || config_setting_is_group(t) || config_setting_is_array(t) || config_setting_is_list(t) || config_setting_is_aggregate(t) || !config_setting_is_scalar(t) || !config_setting_is_number(t) ) { libconfig->destroy(&config); return "CONFIG_TYPE_FLOAT failed."; } if ((t = libconfig->lookup(&config, "Setting_Bool")) == NULL || config_setting_type(t) != CONFIG_TYPE_BOOL || config_setting_is_group(t) || config_setting_is_array(t) || config_setting_is_list(t) || config_setting_is_aggregate(t) || !config_setting_is_scalar(t) || config_setting_is_number(t) ) { libconfig->destroy(&config); return "CONFIG_TYPE_BOOL failed."; } if ((t = libconfig->lookup(&config, "Setting_String")) == NULL || config_setting_type(t) != CONFIG_TYPE_STRING || config_setting_is_group(t) || config_setting_is_array(t) || config_setting_is_list(t) || config_setting_is_aggregate(t) || !config_setting_is_scalar(t) || config_setting_is_number(t) ) { libconfig->destroy(&config); return "CONFIG_TYPE_STRING failed."; } if ((t = libconfig->lookup(&config, "Setting_Array")) == NULL || config_setting_type(t) != CONFIG_TYPE_ARRAY || config_setting_is_group(t) || !config_setting_is_array(t) || config_setting_is_list(t) || !config_setting_is_aggregate(t) || config_setting_is_scalar(t) || config_setting_is_number(t) ) { libconfig->destroy(&config); return "CONFIG_TYPE_ARRAY failed."; } if ((t = libconfig->lookup(&config, "Setting_Group")) == NULL || config_setting_type(t) != CONFIG_TYPE_GROUP || !config_setting_is_group(t) || config_setting_is_array(t) || config_setting_is_list(t) || !config_setting_is_aggregate(t) || config_setting_is_scalar(t) || config_setting_is_number(t) ) { libconfig->destroy(&config); return "CONFIG_TYPE_GROUP failed."; } if ((t = libconfig->lookup(&config, "Setting_List")) == NULL || config_setting_type(t) != CONFIG_TYPE_LIST || config_setting_is_group(t) || config_setting_is_array(t) || !config_setting_is_list(t) || !config_setting_is_aggregate(t) || config_setting_is_scalar(t) || config_setting_is_number(t) ) { libconfig->destroy(&config); return "CONFIG_TYPE_LIST failed."; } libconfig->destroy(&config); return NULL; }
/* Will validate the data retrieved from the configuration file */ int init(void) { int status; config_setting_t *conf_setting = NULL; const char *conf_value = NULL; /* Now the configuration file is read, we don't need to know the location * of the application anymore. We'll change working directory to root */ if(chdir("/") < 0) { syslog(LOG_ERR, "Unable to change working directory to root: %s", strerror(errno)); return EXIT_FAILURE; } syslog(LOG_INFO, "Checking presence and validity of required variables:"); validateConfigBool(&config, "sync_2way", &common_data.sync_2way, 0); validateConfigBool(&config, "diff_commands", &common_data.diff_commands, 0); common_data.send_query = config_lookup(&config, "query") ? 1:0; if(common_data.send_query && ((conf_setting = config_lookup(&config, "query.trigger")) == NULL || config_setting_is_array(conf_setting) == CONFIG_FALSE || (common_data.statusQueryLength = config_setting_length(conf_setting)) == 0)) { syslog(LOG_ERR, "[ERROR] Setting is not present or not formatted as array: query.trigger"); return EXIT_FAILURE; } if(common_data.send_query && validateConfigInt(&config, "query.interval", &common_data.statusQueryInterval, -1, 0, 255, -1) == EXIT_FAILURE) return EXIT_FAILURE; /* Set volume (curve) functions */ conf_value = NULL; config_lookup_string(&config, "volume.curve", &conf_value); if(!(common_data.volume = getVolume(&conf_value))) { syslog(LOG_ERR, "[Error] Volume curve is not recognised: %s", conf_value); return EXIT_FAILURE; } else { syslog(LOG_INFO, "[OK] volume.curve: %s", conf_value); } /* initialise volume variables */ if(common_data.volume->init() == EXIT_FAILURE) return EXIT_FAILURE; /* Set and initialise process type */ conf_value = NULL; config_lookup_string(&config, "data_type", &conf_value); if(!(common_data.process = getProcessMethod(&conf_value))) { syslog(LOG_ERR, "[Error] Setting 'data_type' is not recognised: %s", conf_value); return EXIT_FAILURE; } else { syslog(LOG_INFO, "[OK] data_type: %s", conf_value); } if(common_data.process->init() == EXIT_FAILURE) return EXIT_FAILURE; /* Set and initialise communication interface */ conf_value = NULL; config_lookup_string(&config, "interface", &conf_value); if(!(common_data.interface = getInterface(&conf_value))) { syslog(LOG_ERR, "[Error] Setting 'interface' is not recognised: %s", conf_value); return EXIT_FAILURE; } else { syslog(LOG_INFO, "[OK] interface: %s", conf_value); } if(common_data.interface->init() == EXIT_FAILURE) return EXIT_FAILURE; /* initialise mixer device */ if(initMixer() == EXIT_FAILURE) return EXIT_FAILURE; /* init multipliers */ common_data.volume->regenerateMultipliers(); #ifndef DISABLE_MSQ /* initialise message queue */ if(initMsQ() == EXIT_FAILURE) return EXIT_FAILURE; #endif if((status = pthread_mutex_init(&lockConfig, NULL)) != 0) { syslog(LOG_ERR, "Failed to create config mutex: %i", status); return EXIT_FAILURE; } return EXIT_SUCCESS; } /* end init */
void parse_tcp_relay_ports_config(config_t *cfg, uint16_t **tcp_relay_ports, int *tcp_relay_port_count) { const char *NAME_TCP_RELAY_PORTS = "tcp_relay_ports"; *tcp_relay_port_count = 0; config_setting_t *ports_array = config_lookup(cfg, NAME_TCP_RELAY_PORTS); if (ports_array == NULL) { syslog(LOG_WARNING, "No '%s' setting in the configuration file.\n", NAME_TCP_RELAY_PORTS); syslog(LOG_WARNING, "Using default '%s':\n", NAME_TCP_RELAY_PORTS); uint16_t default_ports[DEFAULT_TCP_RELAY_PORTS_COUNT] = {DEFAULT_TCP_RELAY_PORTS}; int i; for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) { syslog(LOG_WARNING, "Port #%d: %u\n", i, default_ports[i]); } // similar procedure to the one of reading config file below *tcp_relay_ports = malloc(DEFAULT_TCP_RELAY_PORTS_COUNT * sizeof(uint16_t)); for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) { (*tcp_relay_ports)[*tcp_relay_port_count] = default_ports[i]; if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) { syslog(LOG_WARNING, "Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\n", i, (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT); continue; } (*tcp_relay_port_count) ++; } // the loop above skips invalid ports, so we adjust the allocated memory size if ((*tcp_relay_port_count) > 0) { *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t)); } else { free(*tcp_relay_ports); *tcp_relay_ports = NULL; } return; } if (config_setting_is_array(ports_array) == CONFIG_FALSE) { syslog(LOG_WARNING, "'%s' setting should be an array. Array syntax: 'setting = [value1, value2, ...]'.\n", NAME_TCP_RELAY_PORTS); return; } int config_port_count = config_setting_length(ports_array); if (config_port_count == 0) { syslog(LOG_WARNING, "'%s' is empty.\n", NAME_TCP_RELAY_PORTS); return; } *tcp_relay_ports = malloc(config_port_count * sizeof(uint16_t)); int i; for (i = 0; i < config_port_count; i ++) { config_setting_t *elem = config_setting_get_elem(ports_array, i); if (elem == NULL) { // it's NULL if `ports_array` is not an array (we have that check earlier) or if `i` is out of range, which should not be syslog(LOG_WARNING, "Port #%d: Something went wrong while parsing the port. Stopping reading ports.\n", i); break; } if (config_setting_is_number(elem) == CONFIG_FALSE) { syslog(LOG_WARNING, "Port #%d: Not a number. Skipping.\n", i); continue; } (*tcp_relay_ports)[*tcp_relay_port_count] = config_setting_get_int(elem); if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) { syslog(LOG_WARNING, "Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\n", i, (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT); continue; } (*tcp_relay_port_count) ++; } // the loop above skips invalid ports, so we adjust the allocated memory size if ((*tcp_relay_port_count) > 0) { *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t)); } else { free(*tcp_relay_ports); *tcp_relay_ports = NULL; } }