diff --git a/api.c b/api.c index 6983f927..afe9ebe0 100644 --- a/api.c +++ b/api.c @@ -31,6 +31,8 @@ #include "util.h" #include "pool.h" +#include "config_parser.h" + // BUFSIZ varies on Windows and Linux #define TMPBUFSIZ 8192 @@ -2735,7 +2737,7 @@ void dosave(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, b param = filename; } - fcfg = fopen(param, "w"); + /*fcfg = fopen(param, "w"); if (!fcfg) { ptr = escape_string(param, isjson); message(io_data, MSG_BADFN, 0, ptr, isjson); @@ -2743,10 +2745,10 @@ void dosave(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, b free(ptr); ptr = NULL; return; - } + }*/ - write_config(fcfg); - fclose(fcfg); + write_config(param); + //fclose(fcfg); ptr = escape_string(param, isjson); message(io_data, MSG_SAVED, 0, ptr, isjson); diff --git a/config_parser.c b/config_parser.c index 1b6a12f3..b314edd2 100644 --- a/config_parser.c +++ b/config_parser.c @@ -42,6 +42,10 @@ #include "algorithm.h" #include "pool.h" +#ifdef HAVE_ADL +#include "adl.h" +#endif + #if defined(unix) || defined(__APPLE__) #include #include @@ -57,9 +61,6 @@ bool config_loaded; int json_array_index = -1; //current array index being parsed char *last_json_error = NULL; //last json_error -//#define JSON_INCLUDE_CONF "include" -#define JSON_LOAD_ERROR "JSON decode of file '%s' failed\n %s" -#define JSON_LOAD_ERROR_LEN strlen(JSON_LOAD_ERROR) /*#define JSON_MAX_DEPTH 10 #define JSON_MAX_DEPTH_ERR "Too many levels of JSON includes (limit 10) or a loop"*/ @@ -272,8 +273,35 @@ char *set_profile_nfactor(const char *arg) /*************************************** * Helper Functions ****************************************/ +json_t *json_sprintf(const char *fmt, ...) +{ + va_list args; + char *buf; + size_t bufsize; + + //build args + va_start(args, fmt); + //get final string buffer size + bufsize = vsnprintf(NULL, 0, fmt, args); + va_end(args); + + if(!(buf = (char *)malloc(++bufsize))) + quit(1, "Malloc failure in config_parser::json_sprintf()."); + + //zero out buffer + memset(buf, '\0', bufsize); + + //get args again + va_start(args, fmt); + vsnprintf(buf, bufsize, fmt, args); + va_end(args); + + //return json string + return json_string(buf); +} + //set last json error -void set_last_json_error(const char *fmt, ...) +char *set_last_json_error(const char *fmt, ...) { va_list args; size_t bufsize; @@ -281,28 +309,30 @@ void set_last_json_error(const char *fmt, ...) //build args va_start(args, fmt); //get final string buffer size - bufsize = vsnprintf(NULL, 0, JSON_LOAD_ERROR, args); + bufsize = vsnprintf(NULL, 0, fmt, args); va_end(args); //if NULL allocate memory... otherwise reallocate if(!last_json_error) { - if(!(last_json_error = (char *)malloc(bufsize+1))) - quit(1, "Malloc failure in json error"); + if(!(last_json_error = (char *)malloc(++bufsize))) + quit(1, "Malloc failure in config_parser::set_last_json_error()."); } else { - if(!(last_json_error = (char *)realloc(last_json_error, bufsize+1))) - quit(1, "Realloc failure in json error"); + if(!(last_json_error = (char *)realloc(last_json_error, ++bufsize))) + quit(1, "Realloc failure in config_parser::set_last_json_error()."); } //zero out buffer - memset(last_json_error, '\0', bufsize+1); + memset(last_json_error, '\0', bufsize); //get args again va_start(args, fmt); - vsnprintf(last_json_error, bufsize, JSON_LOAD_ERROR, args); + vsnprintf(last_json_error, bufsize, fmt, args); va_end(args); + + return last_json_error; } //find opt by name in an opt table @@ -487,10 +517,7 @@ char *load_config(const char *arg, const char *parentkey, void __maybe_unused *u //if json root is not an object, error out if(!json_is_object(config)) - { - set_last_json_error(JSON_LOAD_ERROR, arg, err.text); - return last_json_error; - } + return set_last_json_error("Error: JSON decode of file \"%s\" failed:\n %s", arg, err.text); config_loaded = true; @@ -655,3 +682,940 @@ void apply_pool_profiles() } } } + +//builds the "pools" json array for config file +json_t *build_pool_json() +{ + json_t *pool_array, *obj; + struct pool *pool; + struct profile *profile; + int i; + + //create the "pools" array + if(!(pool_array = json_array())) + { + set_last_json_error("json_array() failed on pools"); + return NULL; + } + + //process pool entries + for(i=0;ipool_no); + return NULL; + } + + //pool name + if(!empty_string(pool->name)) + { + if(json_object_set(obj, "name", json_string(pool->name)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):name", pool->pool_no); + return NULL; + } + } + + //add quota/url + if(pool->quota != 1) + { + if(json_object_set(obj, "quota", json_sprintf("%s%s%s%d;%s", + ((pool->rpc_proxy)?(char *)proxytype(pool->rpc_proxytype):""), + ((pool->rpc_proxy)?pool->rpc_proxy:""), + ((pool->rpc_proxy)?"|":""), + pool->quota, + pool->rpc_url)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):quota", pool->pool_no); + return NULL; + } + } + else + { + if(json_object_set(obj, "url", json_sprintf("%s%s%s%s", + ((pool->rpc_proxy)?(char *)proxytype(pool->rpc_proxytype):""), + ((pool->rpc_proxy)?pool->rpc_proxy:""), + ((pool->rpc_proxy)?"|":""), + pool->rpc_url)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):url", pool->pool_no); + return NULL; + } + } + + //user + if(json_object_set(obj, "user", json_string(pool->rpc_user)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):user", pool->pool_no); + return NULL; + } + + //pass + if(json_object_set(obj, "pass", json_string(pool->rpc_pass)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):pass", pool->pool_no); + return NULL; + } + + if(!pool->extranonce_subscribe) + { + if(json_object_set(obj, "no-extranonce-subscribe", json_true()) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):no-extranonce-subscribe", pool->pool_no); + return NULL; + } + } + + if(!empty_string(pool->description)) + { + if(json_object_set(obj, "description", json_string(pool->description)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):description", pool->pool_no); + return NULL; + } + } + + //if priority isnt the same as array index, specify it + if(pool->prio != i) + { + if(json_object_set(obj, "priority", json_sprintf("%d", pool->prio)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):description", pool->pool_no); + return NULL; + } + } + + //if a profile was specified, add it then compare pool/profile settings to see what we write + if(!empty_string(pool->profile)) + { + if((profile = get_profile(pool->profile))) + { + //save profile name + if(json_object_set(obj, "profile", json_string(pool->profile)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):profile", pool->pool_no); + return NULL; + } + } + //profile not found use default profile + else + profile = &default_profile; + } + //or select default profile + else + profile = &default_profile; + + //if algorithm is different than profile, add it + if(!cmp_algorithm(&pool->algorithm, &profile->algorithm)) + { + //save algorithm name + if(json_object_set(obj, "algorithm", json_string(pool->algorithm.name)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):algorithm", pool->pool_no); + return NULL; + } + + //TODO: add other options like nfactor etc... + } + + //if pool and profile value doesn't match below, add it + //intensity + if(!empty_string(pool->intensity)) + { + if(strcmp(pool->intensity, profile->intensity)) + { + if(json_object_set(obj, "intensity", json_string(pool->intensity)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):intensity", pool->pool_no); + return NULL; + } + } + } + + //xintensity + if(!empty_string(pool->xintensity)) + { + if(strcmp(pool->xintensity, profile->xintensity) != 0) + { + if(json_object_set(obj, "xintensity", json_string(pool->xintensity)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):xintensity", pool->pool_no); + return NULL; + } + } + } + + //rawintensity + if(!empty_string(pool->rawintensity)) + { + if(strcmp(pool->rawintensity, profile->rawintensity) != 0) + { + if(json_object_set(obj, "rawintensity", json_string(pool->rawintensity)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):rawintensity", pool->pool_no); + return NULL; + } + } + } + + //thread_concurrency + if(!empty_string(pool->thread_concurrency)) + { + if(strcmp(pool->thread_concurrency, profile->thread_concurrency) != 0) + { + if(json_object_set(obj, "thread_concurrency", json_string(pool->thread_concurrency)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):thread_concurrency", pool->pool_no); + return NULL; + } + } + } + +#ifdef HAVE_ADL + //gpu_engine + if(!empty_string(pool->gpu_engine)) + { + if(strcmp(pool->gpu_engine, profile->gpu_engine) != 0) + { + if(json_object_set(obj, "gpu_engine", json_string(pool->gpu_engine)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):gpu_engine", pool->pool_no); + return NULL; + } + } + } + + //gpu_memclock + if(!empty_string(pool->gpu_memclock)) + { + if(strcmp(pool->gpu_memclock, profile->gpu_memclock) != 0) + { + if(json_object_set(obj, "gpu_memclock", json_string(pool->gpu_memclock)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):gpu_memclock", pool->pool_no); + return NULL; + } + } + } + + //gpu_threads + if(!empty_string(pool->gpu_threads)) + { + if(strcmp(pool->gpu_threads, profile->gpu_threads) != 0) + { + if(json_object_set(obj, "gpu_threads", json_string(pool->gpu_threads)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):gpu_threads", pool->pool_no); + return NULL; + } + } + } + + //gpu_fan + if(!empty_string(pool->gpu_fan)) + { + if(strcmp(pool->gpu_fan, profile->gpu_fan) != 0) + { + if(json_object_set(obj, "gpu_fan", json_string(pool->gpu_fan)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):gpu_fan", pool->pool_no); + return NULL; + } + } + } +#endif + + //all done, add pool to array... + if(json_array_append_new(pool_array, obj) == -1) + { + set_last_json_error("json_array_append() failed on pool %d", pool->pool_no); + return NULL; + } + } + + return pool_array; +} + +//builds the "profiles" json array for config file +json_t *build_profile_json() +{ + json_t *profile_array, *obj; + struct profile *profile; + int i; + + //create the "pools" array + if(!(profile_array = json_array())) + { + set_last_json_error("json_array() failed on profiles"); + return NULL; + } + + //process pool entries + for(i=0;iprofile_no); + return NULL; + } + + //profile name + if(!empty_string(profile->name)) + { + if(json_object_set(obj, "name", json_string(profile->name)) == -1) + { + set_last_json_error("json_object_set() failed on profile(%d):name", profile->profile_no); + return NULL; + } + } + + //if algorithm is different than profile, add it + if(!cmp_algorithm(&default_profile.algorithm, &profile->algorithm)) + { + //save algorithm name + if(json_object_set(obj, "algorithm", json_string(profile->algorithm.name)) == -1) + { + set_last_json_error("json_object_set() failed on profile(%d):algorithm", profile->profile_no); + return NULL; + } + + //TODO: add other options like nfactor etc... + } + + //if pool and profile value doesn't match below, add it + //intensity + if(!empty_string(profile->intensity)) + { + if(strcmp(default_profile.intensity, profile->intensity) != 0) + { + if(json_object_set(obj, "intensity", json_string(profile->intensity)) == -1) + { + set_last_json_error("json_object_set() failed on profile(%d):intensity", profile->profile_no); + return NULL; + } + } + } + + //xintensity + if(!empty_string(profile->xintensity)) + { + if(strcmp(default_profile.xintensity, profile->xintensity) != 0) + { + if(json_object_set(obj, "xintensity", json_string(profile->xintensity)) == -1) + { + set_last_json_error("json_object_set() failed on profile(%d):xintensity", profile->profile_no); + return NULL; + } + } + } + + //rawintensity + if(!empty_string(profile->rawintensity)) + { + if(strcmp(default_profile.rawintensity, profile->rawintensity) != 0) + { + if(json_object_set(obj, "rawintensity", json_string(profile->rawintensity)) == -1) + { + set_last_json_error("json_object_set() failed on profile(%d):rawintensity", profile->profile_no); + return NULL; + } + } + } + + //thread_concurrency + if(!empty_string(profile->thread_concurrency)) + { + if(strcmp(default_profile.thread_concurrency, profile->thread_concurrency) != 0) + { + if(json_object_set(obj, "thread_concurrency", json_string(profile->thread_concurrency)) == -1) + { + set_last_json_error("json_object_set() failed on profile(%d):thread_concurrency", profile->profile_no); + return NULL; + } + } + } + +#ifdef HAVE_ADL + //gpu_engine + if(!empty_string(profile->gpu_engine)) + { + if(strcmp(default_profile.gpu_engine, profile->gpu_engine) != 0) + { + if(json_object_set(obj, "gpu_engine", json_string(profile->gpu_engine)) == -1) + { + set_last_json_error("json_object_set() failed on profile(%d):gpu_engine", profile->profile_no); + return NULL; + } + } + } + + //gpu_memclock + if(!empty_string(profile->gpu_memclock)) + { + if(strcmp(default_profile.gpu_memclock, profile->gpu_memclock) != 0) + { + if(json_object_set(obj, "gpu_memclock", json_string(profile->gpu_memclock)) == -1) + { + set_last_json_error("json_object_set() failed on profile(%d):gpu_memclock", profile->profile_no); + return NULL; + } + } + } + + //gpu_threads + if(!empty_string(profile->gpu_threads)) + { + if(strcmp(default_profile.gpu_threads, profile->gpu_threads) != 0) + { + if(json_object_set(obj, "gpu_threads", json_string(profile->gpu_threads)) == -1) + { + set_last_json_error("json_object_set() failed on profile(%d):gpu_threads", profile->profile_no); + return NULL; + } + } + } + + //gpu_fan + if(!empty_string(profile->gpu_fan)) + { + if(strcmp(default_profile.gpu_fan, profile->gpu_fan) != 0) + { + if(json_object_set(obj, "gpu_fan", json_string(profile->gpu_fan)) == -1) + { + set_last_json_error("json_object_set() failed on profile(%d):gpu_fan", profile->profile_no); + return NULL; + } + } + } +#endif + + //all done, add pool to array... + if(json_array_append_new(profile_array, obj) == -1) + { + set_last_json_error("json_array_append() failed on profile %d", profile->profile_no); + return NULL; + } + } + + return profile_array; +} + +void write_config(const char *filename) +{ + json_t *config, *obj; + struct opt_table *opt; + char *p, *optname; + int i; + + if(!(config = json_object())) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object() failed on root."); + return; + } + + //build pools + if(!(obj = build_pool_json())) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n %s.", last_json_error); + return; + } + + //add pools to config + if(json_object_set(config, "pools", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set(pools) failed."); + return; + } + + //build profiles + if(!(obj = build_profile_json())) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n %s.", last_json_error); + return; + } + + //add profiles to config + if(json_object_set(config, "profiles", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set(profiles) failed."); + return; + } + + //pool strategy + switch(pool_strategy) + { + case POOL_BALANCE: + if(json_object_set(config, "balance", json_true()) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on balance"); + return; + } + break; + case POOL_LOADBALANCE: + if(json_object_set(config, "load-balance", json_true()) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on load-balance"); + return; + } + break; + case POOL_ROUNDROBIN: + if(json_object_set(config, "round-robin", json_true()) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on round-robin"); + return; + } + break; + case POOL_ROTATE: + if(json_object_set(config, "rotate", json_sprintf("%d", opt_rotate_period)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on rotate"); + return; + } + break; + //default failover only + default: + if(json_object_set(config, "failover-only", json_true()) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on failover-only"); + return; + } + break; + } + + //if using a specific profile as default, set it + if(!empty_string(default_profile.name)) + { + if(json_object_set(config, "default_profile", json_string(default_profile.name)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on default_profile"); + return; + } + } + //otherwise save default profile values + else + { + //save algorithm name + if(json_object_set(config, "algorithm", json_string(opt_algorithm->name)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on algorithm"); + return; + } + //TODO: add other options like nfactor etc... + + //intensity + if(!empty_string(default_profile.intensity)) + { + if(json_object_set(config, "intensity", json_string(default_profile.intensity)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on intensity"); + return; + } + } + + //xintensity + if(!empty_string(default_profile.xintensity)) + { + if(json_object_set(config, "xintensity", json_string(default_profile.xintensity)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on xintensity"); + return; + } + } + + //rawintensity + if(!empty_string(default_profile.rawintensity)) + { + if(json_object_set(config, "rawintensity", json_string(default_profile.rawintensity)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on rawintensity"); + return; + } + } + + //thread_concurrency + if(!empty_string(default_profile.thread_concurrency)) + { + if(json_object_set(config, "thread_concurrency", json_string(default_profile.thread_concurrency)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on thread_concurrency"); + return; + } + } + +#ifdef HAVE_ADL + //gpu_engine + if(!empty_string(default_profile.gpu_engine)) + { + if(json_object_set(config, "gpu_engine", json_string(default_profile.gpu_engine)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu_engine"); + return; + } + } + + //gpu_memclock + if(!empty_string(default_profile.gpu_memclock)) + { + if(json_object_set(config, "gpu_memclock", json_string(default_profile.gpu_memclock)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu_memclock"); + return; + } + } + + //gpu_threads + if(!empty_string(default_profile.gpu_threads)) + { + if(json_object_set(config, "gpu_threads", json_string(default_profile.gpu_threads)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu_threads"); + return; + } + } + + //gpu_fan + if(!empty_string(default_profile.gpu_fan)) + { + if(json_object_set(config, "gpu_fan", json_string(default_profile.gpu_fan)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu_fan"); + return; + } + } +#endif + } + + //devices + if(opt_devs_enabled) + { + bool extra_devs = false; + obj = json_string(""); + + for(i = 0; i < MAX_DEVICES; i++) + { + if(devices_enabled[i]) + { + int startd = i; + + if(extra_devs) + obj = json_sprintf("%s%s", json_string_value(obj), ","); + + while (i < MAX_DEVICES && devices_enabled[i + 1]) + ++i; + + obj = json_sprintf("%s%d", json_string_value(obj), startd); + if(i > startd) + obj = json_sprintf("%s-%d", json_string_value(obj), i); + } + } + + if(json_object_set(config, "devices", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on devices"); + return; + } + } + + //remove-disabled + if(opt_removedisabled) + { + if(json_object_set(config, "remove-disabled", json_true()) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on remove-disabled"); + return; + } + + } + + //write gpu settings that aren't part of profiles -- only write if gpus are available + if(nDevs) + { + +#ifdef HAVE_ADL + //temp-cutoff + for(i = 0;i < nDevs; i++) + obj = json_sprintf("%s%s%d", ((i > 0)?json_string_value(obj):""), ((i > 0)?",":""), gpus[i].cutofftemp); + + if(json_object_set(config, "temp-cutoff", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on temp-cutoff"); + return; + } + + //temp-overheat + for(i = 0;i < nDevs; i++) + obj = json_sprintf("%s%s%d", ((i > 0)?json_string_value(obj):""), ((i > 0)?",":""), gpus[i].adl.overtemp); + + if(json_object_set(config, "temp-overheat", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on temp-overheat"); + return; + } + + //temp-target + for(i = 0;i < nDevs; i++) + obj = json_sprintf("%s%s%d", ((i > 0)?json_string_value(obj):""), ((i > 0)?",":""), gpus[i].adl.targettemp); + + if(json_object_set(config, "temp-target", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on temp-target"); + return; + } + + //reorder gpus + if(opt_reorder) + { + if(json_object_set(config, "gpu-reorder", json_true()) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-reorder"); + return; + } + } +#endif + + //lookup-gap + for(i = 0;i < nDevs; i++) + obj = json_sprintf("%s%s%d", ((i > 0)?json_string_value(obj):""), ((i > 0)?",":""), (int)gpus[i].opt_lg); + + if(json_object_set(config, "lookup-gap", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on lookup-gap"); + return; + } + + //TODO: move the below into profiles/algorithm switching + //worksize + for(i = 0;i < nDevs; i++) + obj = json_sprintf("%s%s%d", ((i > 0)?json_string_value(obj):""), ((i > 0)?",":""), (int)gpus[i].work_size); + + if(json_object_set(config, "worksize", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on worksize"); + return; + } + + //shaders + for(i = 0;i < nDevs; i++) + obj = json_sprintf("%s%s%d", ((i > 0)?json_string_value(obj):""), ((i > 0)?",":""), (int)gpus[i].shaders); + + if(json_object_set(config, "shaders", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on shaders"); + return; + } + +#ifdef HAVE_ADL + + //gpu-memdiff + for(i = 0;i < nDevs; i++) + obj = json_sprintf("%s%s%d", ((i > 0)?json_string_value(obj):""), ((i > 0)?",":""), (int)gpus[i].gpu_memdiff); + + if(json_object_set(config, "gpu-memdiff", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-memdiff"); + return; + } + + //gpu-powertune + for(i = 0;i < nDevs; i++) + obj = json_sprintf("%s%s%d", ((i > 0)?json_string_value(obj):""), ((i > 0)?",":""), gpus[i].gpu_powertune); + + if(json_object_set(config, "gpu-powertune", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-powertune"); + return; + } + + //gpu-vdcc + for(i = 0;i < nDevs; i++) + obj = json_sprintf("%s%s%1.3f", ((i > 0)?json_string_value(obj):""), ((i > 0)?",":""), gpus[i].gpu_vddc); + + if(json_object_set(config, "gpu-vddc", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-vddc"); + return; + } +#endif + } + + //add other misc options + //shares + if(json_object_set(config, "shares", json_sprintf("%d", opt_shares)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on shares"); + return; + } + +#if defined(unix) || defined(__APPLE__) + //monitor + if(opt_stderr_cmd && *opt_stderr_cmd) + { + if(json_object_set(config, "monitor", json_string(opt_stderr_cmd)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on monitor"); + return; + } + } +#endif // defined(unix) + + //kernel path + if(opt_kernel_path && *opt_kernel_path) + { + //strip end / + char *kpath = strdup(opt_kernel_path); + if(kpath[strlen(kpath)-1] == '/') + kpath[strlen(kpath)-1] = 0; + + if(json_object_set(config, "kernel-path", json_string(kpath)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on kernel-path"); + return; + } + } + + //sched-time + if(schedstart.enable) + { + if(json_object_set(config, "sched-time", json_sprintf("%d:%d", schedstart.tm.tm_hour, schedstart.tm.tm_min)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on sched-time"); + return; + } + } + + //stop-time + if(schedstop.enable) + { + if(json_object_set(config, "stop-time", json_sprintf("%d:%d", schedstop.tm.tm_hour, schedstop.tm.tm_min)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on stop-time"); + return; + } + } + + //socks-proxy + if(opt_socks_proxy && *opt_socks_proxy) + { + if(json_object_set(config, "socks-proxy", json_string(opt_socks_proxy)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on socks-proxy"); + return; + } + } + + + //api stuff + //api-allow + if(opt_api_allow) + { + if(json_object_set(config, "api-allow", json_string(opt_api_allow)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on api-allow"); + return; + } + } + + //api-mcast-addr + if(strcmp(opt_api_mcast_addr, API_MCAST_ADDR) != 0) + { + if(json_object_set(config, "api-mcast-addr", json_string(opt_api_mcast_addr)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on api-mcast-addr"); + return; + } + } + + //api-mcast-code + if(strcmp(opt_api_mcast_code, API_MCAST_CODE) != 0) + { + if(json_object_set(config, "api-mcast-code", json_string(opt_api_mcast_code)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on api-mcast-code"); + return; + } + } + + //api-mcast-des + if(*opt_api_mcast_des) + { + if(json_object_set(config, "api-mcast-des", json_string(opt_api_mcast_des)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on api-mcast-des"); + return; + } + } + + //api-description + if(strcmp(opt_api_description, PACKAGE_STRING) != 0) + { + if(json_object_set(config, "api-description", json_string(opt_api_description)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on api-description"); + return; + } + } + + //api-groups + if(opt_api_groups) + { + if(json_object_set(config, "api-groups", json_string(opt_api_groups)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on api-groups"); + return; + } + } + + //add other misc bool/int options + for(opt = opt_config_table; opt->type != OPT_END; opt++) + { + optname = strdup(opt->names); + + //ignore --pool-* and --profile-* options + if(!strstr(optname, "--pool-") && !strstr(optname, "--profile-")) + { + //get first available long form option name + for(p = strtok(optname, "|"); p; p = strtok(NULL, "|")) + { + //skip short options + if(p[1] != '-') + continue; + + //type bool + if (opt->type & OPT_NOARG && + ((void *)opt->cb == (void *)opt_set_bool || (void *)opt->cb == (void *)opt_set_invbool) && + (*(bool *)opt->u.arg == ((void *)opt->cb == (void *)opt_set_bool))) + { + if(json_object_set(config, p+2, json_true()) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on %s.", p+2); + return; + } + break; //exit for loop... so we don't enter a duplicate value if an option has multiple names + } + //numeric types + else if (opt->type & OPT_HASARG && + ((void *)opt->cb_arg == (void *)set_int_0_to_9999 || + (void *)opt->cb_arg == (void *)set_int_1_to_65535 || + (void *)opt->cb_arg == (void *)set_int_0_to_10 || + (void *)opt->cb_arg == (void *)set_int_1_to_10) && opt->desc != opt_hidden) + { + if(json_object_set(config, p+2, json_sprintf("%d", *(int *)opt->u.arg)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on %s.", p+2); + return; + } + break; //exit for loop... so we don't enter a duplicate value if an option has multiple names + } + } + } + } + + json_dump_file(config, filename, JSON_PRESERVE_ORDER|JSON_INDENT(4)); +} diff --git a/config_parser.h b/config_parser.h index 0a7e58d3..ae3783d7 100644 --- a/config_parser.h +++ b/config_parser.h @@ -11,6 +11,11 @@ #define empty_string(str) ((str && str[0] != '\0')?0:1) #endif +//helper function to get a gpu option value +#define gpu_opt + #define gpu_opt(i,optname) gpus[i].optname +#endif + //profile structure struct profile { int profile_no; @@ -65,24 +70,18 @@ extern char *set_profile_thread_concurrency(const char *arg); #endif extern char *set_profile_nfactor(const char *arg); -/* helpers */ -//void set_last_json_error(const char *fmt, ...); -//struct opt_table *opt_find(struct opt_table *tbl, char *optname); - /* config parser functions */ -//void parse_config_object(json_t *obj, const char *parentkey, bool fileconf, int parent_iteration); -//char *parse_config_array(json_t *obj, char *parentkey, bool fileconf); extern char *parse_config(json_t *val, const char *key, const char *parentkey, bool fileconf, int parent_iteration); extern char *load_config(const char *arg, const char *parentkey, void __maybe_unused *unused); extern char *set_default_config(const char *arg); extern void load_default_config(void); -/*struct profile *add_profile(); -struct profile *get_current_profile(); -struct profile *get_profile(char *name);*/ - +/* startup functions */ extern void load_default_profile(); extern void apply_defaults(); extern void apply_pool_profiles(); +/* config writer */ +extern void write_config(const char *filename); + #endif // CONFIG_PARSER_H diff --git a/miner.h b/miner.h index 37c899ea..3d4017a1 100644 --- a/miner.h +++ b/miner.h @@ -934,7 +934,21 @@ extern bool opt_protocol; extern bool have_longpoll; extern char *opt_kernel_path; extern char *opt_socks_proxy; + +#if defined(unix) || defined(__APPLE__) + extern char *opt_stderr_cmd; +#endif // defined(unix) + +struct schedtime { + bool enable; + struct tm tm; +}; + +extern struct schedtime schedstart; +extern struct schedtime schedstop; + extern char *sgminer_path; +extern int opt_shares; extern bool opt_fail_only; extern bool opt_autofan; extern bool opt_autoengine; @@ -1058,6 +1072,9 @@ extern struct cgpu_info gpus[MAX_GPUDEVICES]; extern double total_secs; extern int mining_threads; extern int total_devices; +extern bool devices_enabled[MAX_DEVICES]; +extern int opt_devs_enabled; +extern bool opt_removedisabled; extern struct cgpu_info **devices; extern int total_pools; extern struct pool **pools; @@ -1380,7 +1397,7 @@ extern void kill_work(void); extern void switch_pools(struct pool *selected); extern void discard_work(struct work *work); extern void remove_pool(struct pool *pool); -extern void write_config(FILE *fcfg); +//extern void write_config(FILE *fcfg); extern void zero_bestshare(void); extern void zero_stats(void); extern void default_save_file(char *filename); @@ -1404,6 +1421,11 @@ extern struct work *copy_work_noffset(struct work *base_work, int noffset); #define copy_work(work_in) copy_work_noffset(work_in, 0) extern struct cgpu_info *get_devices(int id); +extern char *set_int_0_to_9999(const char *arg, int *i); +extern char *set_int_1_to_65535(const char *arg, int *i); +extern char *set_int_0_to_10(const char *arg, int *i); +extern char *set_int_1_to_10(const char *arg, int *i); + enum api_data_type { API_ESCAPE, API_STRING, diff --git a/sgminer.c b/sgminer.c index 7fad68af..781c47a3 100644 --- a/sgminer.c +++ b/sgminer.c @@ -113,10 +113,10 @@ int opt_hamsi_expand_big = 4; bool opt_restart = true; struct list_head scan_devices; -static bool devices_enabled[MAX_DEVICES]; -static int opt_devs_enabled; +bool devices_enabled[MAX_DEVICES]; +int opt_devs_enabled; static bool opt_display_devs; -static bool opt_removedisabled; +bool opt_removedisabled; int total_devices; static int most_devices; struct cgpu_info **devices; @@ -129,7 +129,7 @@ bool use_curses; #endif static bool opt_submit_stale = true; -static int opt_shares; +int opt_shares; bool opt_fail_only; int opt_fail_switch_delay = 60; static bool opt_fix_protocol; @@ -279,7 +279,7 @@ static struct stratum_share *stratum_shares = NULL; char *opt_socks_proxy = NULL; #if defined(unix) || defined(__APPLE__) - static char *opt_stderr_cmd = NULL; + char *opt_stderr_cmd = NULL; static int forkpid; #endif // defined(unix) @@ -292,11 +292,6 @@ struct thread_q *getq; static int total_work; struct work *staged_work = NULL; -struct schedtime { - bool enable; - struct tm tm; -}; - struct schedtime schedstart; struct schedtime schedstop; bool sched_paused; @@ -608,22 +603,22 @@ char *set_int_range(const char *arg, int *i, int min, int max) return NULL; } -static char *set_int_0_to_9999(const char *arg, int *i) +char *set_int_0_to_9999(const char *arg, int *i) { return set_int_range(arg, i, 0, 9999); } -static char *set_int_1_to_65535(const char *arg, int *i) +char *set_int_1_to_65535(const char *arg, int *i) { return set_int_range(arg, i, 1, 65535); } -static char *set_int_0_to_10(const char *arg, int *i) +char *set_int_0_to_10(const char *arg, int *i) { return set_int_range(arg, i, 0, 10); } -static char *set_int_1_to_10(const char *arg, int *i) +char *set_int_1_to_10(const char *arg, int *i) { return set_int_range(arg, i, 1, 10); } @@ -4243,285 +4238,6 @@ static void display_pool_summary(struct pool *pool) } #endif -/* add a mutex if this needs to be thread safe in the future */ -static struct JE { - char *buf; - struct JE *next; -} *jedata = NULL; - -static void json_escape_free() -{ - struct JE *jeptr = jedata; - struct JE *jenext; - - jedata = NULL; - - while (jeptr) { - jenext = jeptr->next; - free(jeptr->buf); - free(jeptr); - jeptr = jenext; - } -} - -static char *json_escape(char *str) -{ - struct JE *jeptr; - char *buf, *ptr; - - /* 2x is the max, may as well just allocate that */ - ptr = buf = (char *)malloc(strlen(str) * 2 + 1); - - jeptr = (struct JE *)malloc(sizeof(*jeptr)); - - jeptr->buf = buf; - jeptr->next = jedata; - jedata = jeptr; - - while (*str) { - if (*str == '\\' || *str == '"') - *(ptr++) = '\\'; - - *(ptr++) = *(str++); - } - - *ptr = '\0'; - - return buf; -} - -void write_config(FILE *fcfg) -{ - int i; - - /* Write pool values */ - fputs("{\n\"pools\" : [", fcfg); - for(i = 0; i < total_pools; i++) { - struct pool *pool = pools[i]; - - fprintf(fcfg, "%s", i > 0 ? "," : ""); - if (pool->quota != 1) { - fprintf(fcfg, "\n\t{\n\t\t\"quota\" : \"%s%s%s%d;%s\"", - pool->rpc_proxy ? json_escape((char *)proxytype(pool->rpc_proxytype)) : "", - pool->rpc_proxy ? json_escape(pool->rpc_proxy) : "", - pool->rpc_proxy ? "|" : "", - pool->quota, - json_escape(pool->rpc_url)); - } else { - fprintf(fcfg, "\n\t{\n\t\t\"url\" : \"%s%s%s%s\"", - pool->rpc_proxy ? json_escape((char *)proxytype(pool->rpc_proxytype)) : "", - pool->rpc_proxy ? json_escape(pool->rpc_proxy) : "", - pool->rpc_proxy ? "|" : "", - json_escape(pool->rpc_url)); - } - if (!pool->extranonce_subscribe) - fprintf(fcfg, ",\n\t\t\"no-extranonce-subscribe\" : true"); - fprintf(fcfg, ",\n\t\t\"user\" : \"%s\"", json_escape(pool->rpc_user)); - fprintf(fcfg, ",\n\t\t\"pass\" : \"%s\"", json_escape(pool->rpc_pass)); - /* Using get_pool_name() here is unsafe if opt_incognito is true. */ - if (strcmp(pool->name, "") != 0) { - fprintf(fcfg, ",\n\t\t\"name\" : \"%s\"", json_escape(pool->name)); - } - if (strcmp(pool->description, "") != 0) { - fprintf(fcfg, ",\n\t\t\"description\" : \"%s\"", json_escape(pool->description)); - } - if (!cmp_algorithm(&pool->algorithm, &opt_algorithm)) { - fprintf(fcfg, ",\n\t\t\"algorithm\" : \"%s\"", json_escape(pool->algorithm.name)); - } - if (pool->prio != i) { - fprintf(fcfg, ",\n\t\t\"priority\" : \"%d\"", pool->prio); - } - fprintf(fcfg, "\n\t}"); - } - fputs("\n]\n", fcfg); - - /* Write only if there are usable GPUs */ - if (nDevs) { - fputs(",\n\"intensity\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - if (gpus[i].dynamic) - fprintf(fcfg, "%sd", i > 0 ? "," : ""); - else - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].intensity); - - fputs("\",\n\"xintensity\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].xintensity); - - fputs("\",\n\"rawintensity\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].rawintensity); - - /* All current kernels only support vector=1 */ - /* fputs("\",\n\"vectors\" : \"", fcfg); */ - /* for(i = 0; i < nDevs; i++) */ - /* fprintf(fcfg, "%s%d", i > 0 ? "," : "", */ - /* gpus[i].vwidth); */ - - fputs("\",\n\"worksize\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", - (int)gpus[i].work_size); - - fputs("\",\n\"algorithm\" : \"", fcfg); - for(i = 0; i < nDevs; i++) { - fprintf(fcfg, "%s", i > 0 ? "," : ""); - fprintf(fcfg, "%s", gpus[i].algorithm.name); - } - - fputs("\",\n\"lookup-gap\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", - (int)gpus[i].opt_lg); - - fputs("\",\n\"thread-concurrency\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", - (int)gpus[i].opt_tc); - - fputs("\",\n\"shaders\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", - (int)gpus[i].shaders); - - fputs("\",\n\"gpu-threads\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", - (int)gpus[i].threads); - -#ifdef HAVE_ADL - fputs("\",\n\"gpu-engine\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d-%d", i > 0 ? "," : "", gpus[i].min_engine, gpus[i].gpu_engine); - - fputs("\",\n\"gpu-fan\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d-%d", i > 0 ? "," : "", gpus[i].min_fan, gpus[i].gpu_fan); - - fputs("\",\n\"gpu-memclock\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].gpu_memclock); - - fputs("\",\n\"gpu-memdiff\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].gpu_memdiff); - - fputs("\",\n\"gpu-powertune\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].gpu_powertune); - - fputs("\",\n\"gpu-vddc\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%1.3f", i > 0 ? "," : "", gpus[i].gpu_vddc); - - fputs("\",\n\"temp-cutoff\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].cutofftemp); - - fputs("\",\n\"temp-overheat\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].adl.overtemp); - - fputs("\",\n\"temp-target\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].adl.targettemp); -#endif - - fputs("\"", fcfg); - } -#ifdef HAVE_ADL - if (opt_reorder) - fprintf(fcfg, ",\n\"gpu-reorder\" : true"); -#endif - - /* Simple bool and int options */ - struct opt_table *opt; - for (opt = opt_config_table; opt->type != OPT_END; opt++) { - char *p, *name = strdup(opt->names); - for (p = strtok(name, "|"); p; p = strtok(NULL, "|")) { - if (p[1] != '-') - continue; - if (opt->type & OPT_NOARG && - ((void *)opt->cb == (void *)opt_set_bool || (void *)opt->cb == (void *)opt_set_invbool) && - (*(bool *)opt->u.arg == ((void *)opt->cb == (void *)opt_set_bool))) - fprintf(fcfg, ",\n\"%s\" : true", p+2); - - if (opt->type & OPT_HASARG && - ((void *)opt->cb_arg == (void *)set_int_0_to_9999 || - (void *)opt->cb_arg == (void *)set_int_1_to_65535 || - (void *)opt->cb_arg == (void *)set_int_0_to_10 || - (void *)opt->cb_arg == (void *)set_int_1_to_10) && opt->desc != opt_hidden) - fprintf(fcfg, ",\n\"%s\" : \"%d\"", p+2, *(int *)opt->u.arg); - } - } - - /* Special case options */ - fprintf(fcfg, ",\n\"shares\" : \"%d\"", opt_shares); - if (pool_strategy == POOL_BALANCE) - fputs(",\n\"balance\" : true", fcfg); - if (pool_strategy == POOL_LOADBALANCE) - fputs(",\n\"load-balance\" : true", fcfg); - if (pool_strategy == POOL_ROUNDROBIN) - fputs(",\n\"round-robin\" : true", fcfg); - if (pool_strategy == POOL_ROTATE) - fprintf(fcfg, ",\n\"rotate\" : \"%d\"", opt_rotate_period); -#if defined(unix) || defined(__APPLE__) - if (opt_stderr_cmd && *opt_stderr_cmd) - fprintf(fcfg, ",\n\"monitor\" : \"%s\"", json_escape(opt_stderr_cmd)); -#endif // defined(unix) - if (opt_kernel_path && *opt_kernel_path) { - char *kpath = strdup(opt_kernel_path); - if (kpath[strlen(kpath)-1] == '/') - kpath[strlen(kpath)-1] = 0; - fprintf(fcfg, ",\n\"kernel-path\" : \"%s\"", json_escape(kpath)); - } - if (schedstart.enable) - fprintf(fcfg, ",\n\"sched-time\" : \"%d:%d\"", schedstart.tm.tm_hour, schedstart.tm.tm_min); - if (schedstop.enable) - fprintf(fcfg, ",\n\"stop-time\" : \"%d:%d\"", schedstop.tm.tm_hour, schedstop.tm.tm_min); - if (opt_socks_proxy && *opt_socks_proxy) - fprintf(fcfg, ",\n\"socks-proxy\" : \"%s\"", json_escape(opt_socks_proxy)); - if (opt_devs_enabled) { - fprintf(fcfg, ",\n\"device\" : \""); - bool extra_devs = false; - - for (i = 0; i < MAX_DEVICES; i++) { - if (devices_enabled[i]) { - int startd = i; - - if (extra_devs) - fprintf(fcfg, ","); - while (i < MAX_DEVICES && devices_enabled[i + 1]) - ++i; - fprintf(fcfg, "%d", startd); - if (i > startd) - fprintf(fcfg, "-%d", i); - } - } - fprintf(fcfg, "\""); - } - if (opt_removedisabled) - fprintf(fcfg, ",\n\"remove-disabled\" : true"); - if (strcmp(opt_algorithm.name, "scrypt") != 0) - fprintf(fcfg, ",\n\"algorithm\" : \"%s\"", json_escape(opt_algorithm.name)); - if (opt_api_allow) - fprintf(fcfg, ",\n\"api-allow\" : \"%s\"", json_escape(opt_api_allow)); - if (strcmp(opt_api_mcast_addr, API_MCAST_ADDR) != 0) - fprintf(fcfg, ",\n\"api-mcast-addr\" : \"%s\"", json_escape(opt_api_mcast_addr)); - if (strcmp(opt_api_mcast_code, API_MCAST_CODE) != 0) - fprintf(fcfg, ",\n\"api-mcast-code\" : \"%s\"", json_escape(opt_api_mcast_code)); - if (*opt_api_mcast_des) - fprintf(fcfg, ",\n\"api-mcast-des\" : \"%s\"", json_escape(opt_api_mcast_des)); - if (strcmp(opt_api_description, PACKAGE_STRING) != 0) - fprintf(fcfg, ",\n\"api-description\" : \"%s\"", json_escape(opt_api_description)); - if (opt_api_groups) - fprintf(fcfg, ",\n\"api-groups\" : \"%s\"", json_escape(opt_api_groups)); - - fputs("\n}\n", fcfg); - - json_escape_free(); -} - void zero_bestshare(void) { int i; @@ -4975,13 +4691,13 @@ retry: } else free(str); - fcfg = fopen(filename, "w"); + /*fcfg = fopen(filename, "w"); if (!fcfg) { wlogprint("Cannot open or create file\n"); goto retry; - } - write_config(fcfg); - fclose(fcfg); + }*/ + write_config(filename); + //fclose(fcfg); goto retry; } else if (!strncasecmp(&input, "r", 1)) { @@ -7889,6 +7605,16 @@ int main(int argc, char *argv[]) //apply pool-specific config from profiles apply_pool_profiles(); + /*FILE *fcfg = fopen("testconf_test.conf", "w"); + if (!fcfg) { + wlogprint("Cannot open or create file\n"); + quit(1,""); + }*/ + write_config("./testconf_test.conf"); + //fclose(fcfg); + quit(1,"file saved."); + + if (opt_benchmark) { struct pool *pool;