From c581fb33326712d3985fd14587f7fefd2a4213ac Mon Sep 17 00:00:00 2001 From: Noel Maersk Date: Wed, 16 Apr 2014 17:22:43 +0300 Subject: [PATCH] config: move configuration options/functions to configuration.{c,h} --- configuration.c | 919 +++++++++++++++++++++++++++++++++++++++++++++ configuration.h | 54 +++ miner.c | 961 +----------------------------------------------- 3 files changed, 978 insertions(+), 956 deletions(-) create mode 100644 configuration.c create mode 100644 configuration.h diff --git a/configuration.c b/configuration.c new file mode 100644 index 00000000..2a6ad27b --- /dev/null +++ b/configuration.c @@ -0,0 +1,919 @@ +/* + * Copyright 2014 sgminer developers (see AUTHORS.md) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or (at + * your option) any later version. See COPYING for more details. + */ + +char *cnfbuf = NULL; + +static char *load_config(const char *arg, void __maybe_unused *unused) +{ + json_error_t err; + json_t *config; + char *json_error; + size_t siz; + + if (!cnfbuf) + cnfbuf = strdup(arg); + + if (++include_count > JSON_MAX_DEPTH) + return JSON_MAX_DEPTH_ERR; + +#if JANSSON_MAJOR_VERSION > 1 + config = json_load_file(arg, 0, &err); +#else + config = json_load_file(arg, &err); +#endif + if (!json_is_object(config)) { + siz = JSON_LOAD_ERROR_LEN + strlen(arg) + strlen(err.text); + json_error = (char *)malloc(siz); + if (!json_error) + quit(1, "Malloc failure in json error"); + + snprintf(json_error, siz, JSON_LOAD_ERROR, arg, err.text); + return json_error; + } + + config_loaded = true; + + /* Parse the config now, so we can override it. That can keep pointers + * so don't free config object. */ + return parse_config(config, true, -1); +} + +static int fileconf_load; + +static char *parse_config(json_t *config, bool fileconf, int parent_iteration) +{ + static char err_buf[200]; + struct opt_table *opt; + json_t *val; + + json_array_index = parent_iteration; + + if (fileconf && !fileconf_load) + fileconf_load = 1; + + for (opt = opt_config_table; opt->type != OPT_END; opt++) { + char *p, *name; + + /* We don't handle subtables. */ + assert(!(opt->type & OPT_SUBTABLE)); + + if (!opt->names) + continue; + + /* Pull apart the option name(s). */ + name = strdup(opt->names); + for (p = strtok(name, "|"); p; p = strtok(NULL, "|")) { + char *err = NULL; + + /* Ignore short options. */ + if (p[1] != '-') + continue; + + val = json_object_get(config, p+2); + if (!val) + continue; + + if ((opt->type & OPT_HASARG) && json_is_string(val)) { + err = opt->cb_arg(json_string_value(val), + opt->u.arg); + } else if ((opt->type & OPT_HASARG) && json_is_array(val)) { + size_t n, size = json_array_size(val); + + for (n = 0; n < size && !err; n++) { + if (json_is_string(json_array_get(val, n))) + err = opt->cb_arg(json_string_value(json_array_get(val, n)), opt->u.arg); + else if (json_is_object(json_array_get(val, n))) + { + err = parse_config(json_array_get(val, n), false, n); + } + } + } else if ((opt->type & OPT_NOARG) && json_is_true(val)) + err = opt->cb(opt->u.arg); + else + err = "Invalid value"; + + if (err) { + /* Allow invalid values to be in configuration + * file, just skipping over them provided the + * JSON is still valid after that. */ + if (fileconf) { + applog(LOG_WARNING, "Skipping config option %s: %s", p, err); + fileconf_load = -1; + } else { + snprintf(err_buf, sizeof(err_buf), "Error parsing JSON option %s: %s", + p, err); + return err_buf; + } + } + } + free(name); + } + + val = json_object_get(config, JSON_INCLUDE_CONF); + if (val && json_is_string(val)) + return load_config(json_string_value(val), NULL); + + return NULL; +} + +static char *set_default_config(const char *arg) +{ + opt_set_charp(arg, &default_config); + + return NULL; +} + +void default_save_file(char *filename); + +static void load_default_config(void) +{ + cnfbuf = (char *)malloc(PATH_MAX); + + default_save_file(cnfbuf); + + if (!access(cnfbuf, R_OK)) + load_config(cnfbuf, NULL); + else { + free(cnfbuf); + cnfbuf = NULL; + } +} + +static char *set_algo(const char *arg) +{ + if ((json_array_index < 0) || (total_pools == 0)) { + set_algorithm(opt_algorithm, arg); + applog(LOG_INFO, "Set default algorithm to %s", opt_algorithm->name); + } else { + set_pool_algorithm(arg); + } + + return NULL; +} + +static char *set_nfactor(const char *arg) +{ + if ((json_array_index < 0) || (total_pools == 0)) { + set_algorithm_nfactor(opt_algorithm, (const uint8_t) atoi(arg)); + applog(LOG_INFO, "Set algorithm N-factor to %d (N to %d)", + opt_algorithm->nfactor, opt_algorithm->n); + } else { + set_pool_nfactor(arg); + } + + return NULL; +} + +static char *set_api_allow(const char *arg) +{ + opt_set_charp(arg, &opt_api_allow); + + return NULL; +} + +static char *set_api_groups(const char *arg) +{ + opt_set_charp(arg, &opt_api_groups); + + return NULL; +} + +static char *set_api_description(const char *arg) +{ + opt_set_charp(arg, &opt_api_description); + + return NULL; +} + +static char *set_api_mcast_addr(const char *arg) +{ + opt_set_charp(arg, &opt_api_mcast_addr); + + return NULL; +} + +static char *set_api_mcast_code(const char *arg) +{ + opt_set_charp(arg, &opt_api_mcast_code); + + return NULL; +} + +static char *set_api_mcast_des(const char *arg) +{ + opt_set_charp(arg, &opt_api_mcast_des); + + return NULL; +} + +static char *set_null(const char __maybe_unused *arg) +{ + return NULL; +} + +static char *temp_cutoff_str = NULL; + +char *set_temp_cutoff(char *arg) +{ + int val; + + if (!(arg && arg[0])) + return "Invalid parameters for set temp cutoff"; + val = atoi(arg); + if (val < 0 || val > 200) + return "Invalid value passed to set temp cutoff"; + temp_cutoff_str = arg; + + return NULL; +} + +static char* set_sharelog(char *arg) +{ + char *r = ""; + long int i = strtol(arg, &r, 10); + + if ((!*r) && i >= 0 && i <= INT_MAX) { + sharelog_file = fdopen((int)i, "a"); + if (!sharelog_file) + applog(LOG_ERR, "Failed to open fd %u for share log", (unsigned int)i); + } else if (!strcmp(arg, "-")) { + sharelog_file = stdout; + if (!sharelog_file) + applog(LOG_ERR, "Standard output missing for share log"); + } else { + sharelog_file = fopen(arg, "a"); + if (!sharelog_file) + applog(LOG_ERR, "Failed to open %s for share log", arg); + } + + return NULL; +} + +static char *set_schedtime(const char *arg, struct schedtime *st) +{ + if (sscanf(arg, "%d:%d", &st->tm.tm_hour, &st->tm.tm_min) != 2) + return "Invalid time set, should be HH:MM"; + if (st->tm.tm_hour > 23 || st->tm.tm_min > 59 || st->tm.tm_hour < 0 || st->tm.tm_min < 0) + return "Invalid time set."; + st->enable = true; + return NULL; +} + +static char *set_pool_priority(char *arg) +{ + struct pool *pool = get_current_pool(); + + applog(LOG_DEBUG, "Setting pool %i priority to %s", pool->pool_no, arg); + opt_set_intval(arg, &pool->prio); + + return NULL; +} + +static char *set_pool_description(char *arg) +{ + struct pool *pool = get_current_pool(); + + applog(LOG_DEBUG, "Setting pool %i description to %s", pool->pool_no, arg); + opt_set_charp(arg, &pool->description); + + return NULL; +} + +static char *set_pass(const char *arg) +{ + struct pool *pool = get_current_pool(); + + opt_set_charp(arg, &pool->rpc_pass); + + return NULL; +} + +static char *set_userpass(const char *arg) +{ + struct pool *pool = get_current_pool(); + char *updup; + + updup = strdup(arg); + opt_set_charp(arg, &pool->rpc_userpass); + pool->rpc_user = strtok(updup, ":"); + if (!pool->rpc_user) + return "Failed to find : delimited user info"; + pool->rpc_pass = strtok(NULL, ":"); + if (!pool->rpc_pass) + pool->rpc_pass = ""; + + return NULL; +} + +static char *set_quota(char *arg) +{ + char *semicolon = strchr(arg, ';'), *url; + size_t len, qlen; + int quota; + struct pool *pool; + + if (!semicolon) + return "No semicolon separated quota;URL pair found"; + len = strlen(arg); + *semicolon = '\0'; + qlen = strlen(arg); + if (!qlen) + return "No parameter for quota found"; + len -= qlen + 1; + if (len < 1) + return "No parameter for URL found"; + quota = atoi(arg); + if (quota < 0) + return "Invalid negative parameter for quota set"; + url = arg + qlen + 1; + pool = add_url(); + setup_url(pool, url); + pool->quota = quota; + applog(LOG_INFO, "Setting %s to quota %d", get_pool_name(pool), pool->quota); + adjust_quota_gcd(); + + return NULL; +} + +static char *set_user(const char *arg) +{ + struct pool *pool = get_current_pool(); + + opt_set_charp(arg, &pool->rpc_user); + + return NULL; +} + +static char *set_pool_state(char *arg) +{ + struct pool *pool = get_current_pool(); + + applog(LOG_INFO, "Setting pool %s state to %s", get_pool_name(pool), arg); + if (strcmp(arg, "disabled") == 0) { + pool->state = POOL_DISABLED; + } else if (strcmp(arg, "enabled") == 0) { + pool->state = POOL_ENABLED; + } else if (strcmp(arg, "hidden") == 0) { + pool->state = POOL_HIDDEN; + } else if (strcmp(arg, "rejecting") == 0) { + pool->state = POOL_REJECTING; + } else { + pool->state = POOL_ENABLED; + } + + return NULL; +} + +static char *set_url(char *arg) +{ + struct pool *pool = add_url(); + + setup_url(pool, arg); + return NULL; +} + + +static char *set_pool_algorithm(const char *arg) +{ + struct pool *pool = get_current_pool(); + + applog(LOG_DEBUG, "Setting pool %i algorithm to %s", pool->pool_no, arg); + set_algorithm(&pool->algorithm, arg); + + return NULL; +} + +static char *set_pool_nfactor(const char *arg) +{ + struct pool *pool = get_current_pool(); + + applog(LOG_DEBUG, "Setting pool %i N-factor to %s", pool->pool_no, arg); + set_algorithm_nfactor(&pool->algorithm, (const uint8_t) atoi(arg)); + + return NULL; +} + +static char *set_pool_name(char *arg) +{ + struct pool *pool = get_current_pool(); + + applog(LOG_DEBUG, "Setting pool %i name to %s", pool->pool_no, arg); + opt_set_charp(arg, &pool->name); + + return NULL; +} + +static char *set_poolname_deprecated(char *arg) +{ + applog(LOG_ERR, "Specifying pool name by --poolname is deprecated. Use --name instead."); + set_pool_name(arg); + + return NULL; +} + +static char *set_balance(enum pool_strategy *strategy) +{ + *strategy = POOL_BALANCE; + return NULL; +} + +static char *set_loadbalance(enum pool_strategy *strategy) +{ + *strategy = POOL_LOADBALANCE; + return NULL; +} + +static char *set_rotate(const char *arg, int *i) +{ + pool_strategy = POOL_ROTATE; + return set_int_range(arg, i, 0, 9999); +} + +static char *set_rr(enum pool_strategy *strategy) +{ + *strategy = POOL_ROUNDROBIN; + return NULL; +} + +char *set_int_range(const char *arg, int *i, int min, int max) +{ + char *err = opt_set_intval(arg, i); + + if (err) + return err; + + if (*i < min || *i > max) + return "Value out of range"; + + return NULL; +} + +static 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) +{ + return set_int_range(arg, i, 1, 65535); +} + +static 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) +{ + return set_int_range(arg, i, 1, 10); +} + +void get_intrange(char *arg, int *val1, int *val2) +{ + if (sscanf(arg, "%d-%d", val1, val2) == 1) + *val2 = *val1; +} + +static char *set_devices(char *arg) +{ + int i, val1 = 0, val2 = 0; + char *nextptr; + + if (*arg) { + if (*arg == '?') { + opt_display_devs = true; + return NULL; + } + } else + return "Invalid device parameters"; + + nextptr = strtok(arg, ","); + if (nextptr == NULL) + return "Invalid parameters for set devices"; + get_intrange(nextptr, &val1, &val2); + if (val1 < 0 || val1 > MAX_DEVICES || val2 < 0 || val2 > MAX_DEVICES || + val1 > val2) { + return "Invalid value passed to set devices"; + } + + for (i = val1; i <= val2; i++) { + devices_enabled[i] = true; + opt_devs_enabled++; + } + + while ((nextptr = strtok(NULL, ",")) != NULL) { + get_intrange(nextptr, &val1, &val2); + if (val1 < 0 || val1 > MAX_DEVICES || val2 < 0 || val2 > MAX_DEVICES || + val1 > val2) { + return "Invalid value passed to set devices"; + } + + for (i = val1; i <= val2; i++) { + devices_enabled[i] = true; + opt_devs_enabled++; + } + } + + return NULL; +} + +/* Used in configuration parsing (get pool being set up). */ +static struct pool* get_current_pool() +{ + while ((json_array_index + 1) > total_pools) + add_pool(); + + if (json_array_index < 0) { + if (!total_pools) + add_pool(); + return pools[total_pools - 1]; + } + + return pools[json_array_index]; +} + +static char *enable_debug(bool *flag) +{ + *flag = true; + /* Turn on verbose output, too. */ + opt_log_output = true; + return NULL; +} + +/* These options are available from config file or commandline */ +static struct opt_table opt_config_table[] = { + OPT_WITH_ARG("--algorithm", + set_algo, NULL, NULL, + "Set mining algorithm and most common defaults, default: scrypt"), + OPT_WITH_ARG("--api-allow", + set_api_allow, NULL, NULL, + "Allow API access only to the given list of [G:]IP[/Prefix] addresses[/subnets]"), + OPT_WITH_ARG("--api-description", + set_api_description, NULL, NULL, + "Description placed in the API status header, default: sgminer version"), + OPT_WITH_ARG("--api-groups", + set_api_groups, NULL, NULL, + "API one letter groups G:cmd:cmd[,P:cmd:*...] defining the cmds a groups can use"), + OPT_WITHOUT_ARG("--api-listen", + opt_set_bool, &opt_api_listen, + "Enable API, default: disabled"), + OPT_WITHOUT_ARG("--api-mcast", + opt_set_bool, &opt_api_mcast, + "Enable API Multicast listener, default: disabled"), + OPT_WITH_ARG("--api-mcast-addr", + set_api_mcast_addr, NULL, NULL, + "API Multicast listen address"), + OPT_WITH_ARG("--api-mcast-code", + set_api_mcast_code, NULL, NULL, + "Code expected in the API Multicast message, don't use '-'"), + OPT_WITH_ARG("--api-mcast-des", + set_api_mcast_des, NULL, NULL, + "Description appended to the API Multicast reply, default: ''"), + OPT_WITH_ARG("--api-mcast-port", + set_int_1_to_65535, opt_show_intval, &opt_api_mcast_port, + "API Multicast listen port"), + OPT_WITHOUT_ARG("--api-network", + opt_set_bool, &opt_api_network, + "Allow API (if enabled) to listen on/for any address, default: only 127.0.0.1"), + OPT_WITH_ARG("--api-port", + set_int_1_to_65535, opt_show_intval, &opt_api_port, + "Port number of miner API"), +#ifdef HAVE_ADL + OPT_WITHOUT_ARG("--auto-fan", + opt_set_bool, &opt_autofan, + "Automatically adjust all GPU fan speeds to maintain a target temperature"), + OPT_WITHOUT_ARG("--auto-gpu", + opt_set_bool, &opt_autoengine, + "Automatically adjust all GPU engine clock speeds to maintain a target temperature"), +#endif + OPT_WITHOUT_ARG("--balance", + set_balance, &pool_strategy, + "Change multipool strategy from failover to even share balance"), +#ifdef HAVE_CURSES + OPT_WITHOUT_ARG("--compact", + opt_set_bool, &opt_compact, + "Use compact display without per device statistics"), +#endif + OPT_WITHOUT_ARG("--debug|-D", + enable_debug, &opt_debug, + "Enable debug output"), + OPT_WITH_ARG("--description", + set_pool_description, NULL, NULL, + "Pool description"), + OPT_WITH_ARG("--device|-d", + set_devices, NULL, NULL, + "Select device to use, one value, range and/or comma separated (e.g. 0-2,4) default: all"), + OPT_WITHOUT_ARG("--disable-rejecting", + opt_set_bool, &opt_disable_pool, + "Automatically disable pools that continually reject shares"), + OPT_WITH_ARG("--expiry|-E", + set_int_0_to_9999, opt_show_intval, &opt_expiry, + "Upper bound on how many seconds after getting work we consider a share from it stale"), + OPT_WITHOUT_ARG("--failover-only", + opt_set_bool, &opt_fail_only, + "Don't leak work to backup pools when primary pool is lagging"), + OPT_WITH_ARG("--failover-switch-delay", + set_int_1_to_65535, opt_show_intval, &opt_fail_switch_delay, + "Delay in seconds before switching back to a failed pool"), + OPT_WITHOUT_ARG("--fix-protocol", + opt_set_bool, &opt_fix_protocol, + "Do not redirect to a different getwork protocol (eg. stratum)"), + OPT_WITH_ARG("--gpu-dyninterval", + set_int_1_to_65535, opt_show_intval, &opt_dynamic_interval, + "Set the refresh interval in ms for GPUs using dynamic intensity"), + OPT_WITH_ARG("--gpu-platform", + set_int_0_to_9999, opt_show_intval, &opt_platform_id, + "Select OpenCL platform ID to use for GPU mining"), +#ifndef HAVE_ADL + // gpu-threads can only be set per-card if ADL is available + OPT_WITH_ARG("--gpu-threads|-g", + set_int_1_to_10, opt_show_intval, &opt_g_threads, + "Number of threads per GPU (1 - 10)"), +#else + OPT_WITH_ARG("--gpu-threads|-g", + set_gpu_threads, NULL, NULL, + "Number of threads per GPU - one value or comma separated list (e.g. 1,2,1)"), + OPT_WITH_ARG("--gpu-engine", + set_gpu_engine, NULL, NULL, + "GPU engine (over)clock range in Mhz - one value, range and/or comma separated list (e.g. 850-900,900,750-850)"), + OPT_WITH_ARG("--gpu-fan", + set_gpu_fan, NULL, NULL, + "GPU fan percentage range - one value, range and/or comma separated list (e.g. 0-85,85,65)"), + OPT_WITH_ARG("--gpu-map", + set_gpu_map, NULL, NULL, + "Map OpenCL to ADL device order manually, paired CSV (e.g. 1:0,2:1 maps OpenCL 1 to ADL 0, 2 to 1)"), + OPT_WITH_ARG("--gpu-memclock", + set_gpu_memclock, NULL, NULL, + "Set the GPU memory (over)clock in Mhz - one value for all or separate by commas for per card"), + OPT_WITH_ARG("--gpu-memdiff", + set_gpu_memdiff, NULL, NULL, + "Set a fixed difference in clock speed between the GPU and memory in auto-gpu mode"), + OPT_WITH_ARG("--gpu-powertune", + set_gpu_powertune, NULL, NULL, + "Set the GPU powertune percentage - one value for all or separate by commas for per card"), + OPT_WITHOUT_ARG("--gpu-reorder", + opt_set_bool, &opt_reorder, + "Attempt to reorder GPU devices according to PCI Bus ID"), + OPT_WITH_ARG("--gpu-vddc", + set_gpu_vddc, NULL, NULL, + "Set the GPU voltage in Volts - one value for all or separate by commas for per card"), +#endif + OPT_WITH_ARG("--lookup-gap", + set_lookup_gap, NULL, NULL, + "Set GPU lookup gap for scrypt mining, comma separated"), +#ifdef HAVE_CURSES + OPT_WITHOUT_ARG("--incognito", + opt_set_bool, &opt_incognito, + "Do not display user name in status window"), +#endif + OPT_WITH_ARG("--intensity|-I", + set_intensity, NULL, NULL, + "Intensity of GPU scanning (d or " MIN_INTENSITY_STR + " -> " MAX_INTENSITY_STR + ",default: d to maintain desktop interactivity), overridden by --xintensity or --rawintensity."), + OPT_WITH_ARG("--xintensity|-X", + set_xintensity, NULL, NULL, + "Shader based intensity of GPU scanning (" MIN_XINTENSITY_STR " to " + MAX_XINTENSITY_STR "), overrides --intensity|-I, overridden by --rawintensity."), + OPT_WITH_ARG("--rawintensity", + set_rawintensity, NULL, NULL, + "Raw intensity of GPU scanning (" MIN_RAWINTENSITY_STR " to " + MAX_RAWINTENSITY_STR "), overrides --intensity|-I and --xintensity|-X."), + OPT_WITH_ARG("--kernel-path|-K", + opt_set_charp, opt_show_charp, &opt_kernel_path, + "Specify a path to where kernel files are"), + OPT_WITH_ARG("--kernel|-k", + set_kernel, NULL, NULL, + "Override kernel to use - one value or comma separated"), + OPT_WITHOUT_ARG("--load-balance", + set_loadbalance, &pool_strategy, + "Change multipool strategy from failover to quota based balance"), + OPT_WITH_ARG("--log|-l", + set_int_0_to_9999, opt_show_intval, &opt_log_interval, + "Interval in seconds between log output"), + OPT_WITHOUT_ARG("--log-show-date|-L", + opt_set_bool, &opt_log_show_date, + "Show date on every log line"), + OPT_WITHOUT_ARG("--lowmem", + opt_set_bool, &opt_lowmem, + "Minimise caching of shares for low memory applications"), +#if defined(unix) || defined(__APPLE__) + OPT_WITH_ARG("--monitor|-m", + opt_set_charp, NULL, &opt_stderr_cmd, + "Use custom pipe cmd for output messages"), +#endif // defined(unix) + OPT_WITH_ARG("--name", + set_pool_name, NULL, NULL, + "Name of pool"), + OPT_WITHOUT_ARG("--net-delay", + opt_set_bool, &opt_delaynet, + "Impose small delays in networking to not overload slow routers"), + OPT_WITH_ARG("--nfactor", + set_nfactor, NULL, NULL, + "Override default scrypt N-factor parameter."), +#ifdef HAVE_ADL + OPT_WITHOUT_ARG("--no-adl", + opt_set_bool, &opt_noadl, + "Disable the ATI display library used for monitoring and setting GPU parameters"), +#else + OPT_WITHOUT_ARG("--no-adl", + opt_set_bool, &opt_noadl, opt_hidden), +#endif + OPT_WITHOUT_ARG("--no-pool-disable", + opt_set_invbool, &opt_disable_pool, + opt_hidden), + OPT_WITHOUT_ARG("--no-client-reconnect", + opt_set_invbool, &opt_disable_client_reconnect, + "Disable 'client.reconnect' stratum functionality"), + OPT_WITHOUT_ARG("--no-restart", + opt_set_invbool, &opt_restart, + "Do not attempt to restart GPUs that hang"), + OPT_WITHOUT_ARG("--no-submit-stale", + opt_set_invbool, &opt_submit_stale, + "Don't submit shares if they are detected as stale"), + OPT_WITH_ARG("--pass|-p", + set_pass, NULL, NULL, + "Password for bitcoin JSON-RPC server"), + OPT_WITHOUT_ARG("--per-device-stats", + opt_set_bool, &want_per_device_stats, + "Force verbose mode and output per-device statistics"), + OPT_WITH_ARG("--poolname", /* TODO: Backward compatibility, to be removed. */ + set_poolname_deprecated, NULL, NULL, + opt_hidden), + OPT_WITH_ARG("--priority", + set_pool_priority, NULL, NULL, + "Pool priority"), + OPT_WITHOUT_ARG("--protocol-dump|-P", + opt_set_bool, &opt_protocol, + "Verbose dump of protocol-level activities"), + OPT_WITH_ARG("--queue|-Q", + set_int_0_to_9999, opt_show_intval, &opt_queue, + "Minimum number of work items to have queued (0+)"), + OPT_WITHOUT_ARG("--quiet|-q", + opt_set_bool, &opt_quiet, + "Disable logging output, display status and errors"), + OPT_WITH_ARG("--quota|-U", + set_quota, NULL, NULL, + "quota;URL combination for server with load-balance strategy quotas"), + OPT_WITHOUT_ARG("--real-quiet", + opt_set_bool, &opt_realquiet, + "Disable all output"), + OPT_WITHOUT_ARG("--remove-disabled", + opt_set_bool, &opt_removedisabled, + "Remove disabled devices entirely, as if they didn't exist"), + OPT_WITH_ARG("--retries", + set_null, NULL, NULL, + opt_hidden), + OPT_WITH_ARG("--retry-pause", + set_null, NULL, NULL, + opt_hidden), + OPT_WITH_ARG("--rotate", + set_rotate, opt_show_intval, &opt_rotate_period, + "Change multipool strategy from failover to regularly rotate at N minutes"), + OPT_WITHOUT_ARG("--round-robin", + set_rr, &pool_strategy, + "Change multipool strategy from failover to round robin on failure"), + OPT_WITH_ARG("--scan-time|-s", + set_int_0_to_9999, opt_show_intval, &opt_scantime, + "Upper bound on time spent scanning current work, in seconds"), + OPT_WITH_ARG("--sched-start", + set_schedtime, NULL, &schedstart, + "Set a time of day in HH:MM to start mining (a once off without a stop time)"), + OPT_WITH_ARG("--sched-stop", + set_schedtime, NULL, &schedstop, + "Set a time of day in HH:MM to stop mining (will quit without a start time)"), + OPT_WITH_ARG("--shaders", + set_shaders, NULL, NULL, + "GPU shaders per card for tuning scrypt, comma separated"), + OPT_WITH_ARG("--sharelog", + set_sharelog, NULL, NULL, + "Append share log to file"), + OPT_WITH_ARG("--shares", + opt_set_intval, NULL, &opt_shares, + "Quit after mining N shares (default: unlimited)"), + OPT_WITH_ARG("--socks-proxy", + opt_set_charp, NULL, &opt_socks_proxy, + "Set socks4 proxy (host:port)"), + OPT_WITH_ARG("--state", + set_pool_state, NULL, NULL, + "Specify pool state at startup (default: enabled)"), +#ifdef HAVE_SYSLOG_H + OPT_WITHOUT_ARG("--syslog", + opt_set_bool, &use_syslog, + "Use system log for output messages (default: standard error)"), +#endif +#if defined(HAVE_LIBCURL) && defined(CURL_HAS_KEEPALIVE) + OPT_WITH_ARG("--tcp-keepalive", + set_int_0_to_9999, opt_show_intval, &opt_tcp_keepalive, + "TCP keepalive packet idle time"), +#else + OPT_WITH_ARG("--tcp-keepalive", + set_int_0_to_9999, opt_show_intval, &opt_tcp_keepalive, + opt_hidden), +#endif +#ifdef HAVE_ADL + OPT_WITH_ARG("--temp-cutoff", + set_temp_cutoff, opt_show_intval, &opt_cutofftemp, + "Temperature which a device will be automatically disabled at, one value or comma separated list"), + OPT_WITH_ARG("--temp-hysteresis", + set_int_1_to_10, opt_show_intval, &opt_hysteresis, + "Set how much the temperature can fluctuate outside limits when automanaging speeds"), + OPT_WITH_ARG("--temp-overheat", + set_temp_overheat, opt_show_intval, &opt_overheattemp, + "Temperature which a device will be throttled at while automanaging fan and/or GPU, one value or comma separated list"), + OPT_WITH_ARG("--temp-target", + set_temp_target, opt_show_intval, &opt_targettemp, + "Temperature which a device should stay at while automanaging fan and/or GPU, one value or comma separated list"), +#endif +#ifdef HAVE_CURSES + OPT_WITHOUT_ARG("--text-only|-T", + opt_set_invbool, &use_curses, + "Disable ncurses formatted screen output"), +#else + OPT_WITHOUT_ARG("--text-only|-T", + opt_set_invbool, &use_curses, + opt_hidden), +#endif + OPT_WITH_ARG("--thread-concurrency", + set_thread_concurrency, NULL, NULL, + "Set GPU thread concurrency for scrypt mining, comma separated"), + OPT_WITH_ARG("--url|-o", + set_url, NULL, NULL, + "URL for bitcoin JSON-RPC server"), + OPT_WITH_ARG("--pool-algorithm", + set_pool_algorithm, NULL, NULL, + "Set algorithm for pool"), + OPT_WITH_ARG("--pool-nfactor", + set_pool_nfactor, NULL, NULL, + "Set N-factor for pool"), + OPT_WITH_ARG("--user|-u", + set_user, NULL, NULL, + "Username for bitcoin JSON-RPC server"), + OPT_WITH_ARG("--vectors", + set_vector, NULL, NULL, + opt_hidden), + /* All current kernels only support vectors=1 */ + /* "Override detected optimal vector (1, 2 or 4) - one value or comma separated list"), */ + OPT_WITHOUT_ARG("--verbose|-v", + opt_set_bool, &opt_log_output, + "Log verbose output to stderr as well as status output"), + OPT_WITH_ARG("--worksize|-w", + set_worksize, NULL, NULL, + "Override detected optimal worksize - one value or comma separated list"), + OPT_WITH_ARG("--userpass|-O", + set_userpass, NULL, NULL, + "Username:Password pair for bitcoin JSON-RPC server"), + OPT_WITHOUT_ARG("--worktime", + opt_set_bool, &opt_worktime, + "Display extra work time debug information"), + OPT_WITH_ARG("--pools", + opt_set_bool, NULL, NULL, opt_hidden), + OPT_ENDTABLE +}; + + +extern const char *opt_argv0; + +static char *opt_verusage_and_exit(const char *extra) +{ + printf("%s\n", packagename); + printf("%s", opt_usage(opt_argv0, extra)); + fflush(stdout); + exit(0); +} + +char *display_devs(int *ndevs) +{ + *ndevs = 0; + print_ndevs(ndevs); + exit(*ndevs); +} + +/* These options are available from commandline only */ +static struct opt_table opt_cmdline_table[] = { + OPT_WITH_ARG("--config|-c", + load_config, NULL, NULL, + "Load a JSON-format configuration file\n" + "See example.conf for an example configuration."), + OPT_WITH_ARG("--default-config", + set_default_config, NULL, NULL, + "Specify the filename of the default config file\n" + "Loaded at start and used when saving without a name."), + OPT_WITHOUT_ARG("--help|-h", + opt_verusage_and_exit, NULL, + "Print this message"), + OPT_WITHOUT_ARG("--ndevs|-n", + display_devs, &nDevs, + "Display number of detected GPUs, OpenCL platform " + "information, and exit"), + OPT_WITHOUT_ARG("--version|-V", + opt_version_and_exit, packagename, + "Display version and exit"), + OPT_ENDTABLE +}; diff --git a/configuration.h b/configuration.h new file mode 100644 index 00000000..0f3f8236 --- /dev/null +++ b/configuration.h @@ -0,0 +1,54 @@ +#ifndef CONFIGURATION_H +#define CONFIGURATION_H + +char *opt_api_allow = NULL; +char *opt_api_groups; +char *opt_api_description = PACKAGE_STRING; +int opt_api_port = 4028; +bool opt_api_listen; +bool opt_api_mcast; +char *opt_api_mcast_addr = API_MCAST_ADDR; +char *opt_api_mcast_code = API_MCAST_CODE; +char *opt_api_mcast_des = ""; +int opt_api_mcast_port = 4028; +bool opt_api_network; + +bool opt_autofan; +bool opt_autoengine; +bool opt_noadl; + +bool opt_quiet; +bool opt_realquiet; +#define QUIET (opt_quiet || opt_realquiet) +bool opt_protocol; + +bool opt_compact; +bool opt_incognito; + +const int opt_cutofftemp = 95; +int opt_log_interval = 5; +int opt_queue = 1; +int opt_scantime = 7; +int opt_expiry = 28; + +static bool opt_submit_stale = true; + +bool opt_delaynet; +bool opt_disable_pool; +bool opt_disable_client_reconnect = false; + +bool opt_fail_only; +int opt_fail_switch_delay = 60; +static bool opt_fix_protocol; +static bool opt_lowmem; + +algorithm_t *opt_algorithm; + +static bool opt_removedisabled; + +char *opt_socks_proxy = NULL; + +char *opt_kernel_path; + + +#endif /* CONFIGURATION_H */ diff --git a/miner.c b/miner.c index 6f73723b..af4aeba6 100644 --- a/miner.c +++ b/miner.c @@ -80,23 +80,11 @@ struct strategies strategies[] = { static char packagename[256]; bool opt_work_update; -bool opt_protocol; bool have_longpoll; bool want_per_device_stats; bool use_syslog; -bool opt_quiet; -bool opt_realquiet; -bool opt_loginput; -bool opt_compact; -bool opt_incognito; - -const int opt_cutofftemp = 95; -int opt_log_interval = 5; -int opt_queue = 1; -int opt_scantime = 7; -int opt_expiry = 28; -algorithm_t *opt_algorithm; +bool opt_loginput; static const bool opt_time = true; unsigned long long global_hashrate; @@ -113,7 +101,6 @@ struct list_head scan_devices; static bool devices_enabled[MAX_DEVICES]; static int opt_devs_enabled; static bool opt_display_devs; -static bool opt_removedisabled; int total_devices; int zombie_devs; static int most_devices; @@ -126,29 +113,8 @@ bool use_curses = true; bool use_curses; #endif -static bool opt_submit_stale = true; static int opt_shares; -bool opt_fail_only; -int opt_fail_switch_delay = 60; -static bool opt_fix_protocol; -static bool opt_lowmem; -bool opt_autofan; -bool opt_autoengine; -bool opt_noadl; -char *opt_api_allow = NULL; -char *opt_api_groups; -char *opt_api_description = PACKAGE_STRING; -int opt_api_port = 4028; -bool opt_api_listen; -bool opt_api_mcast; -char *opt_api_mcast_addr = API_MCAST_ADDR; -char *opt_api_mcast_code = API_MCAST_CODE; -char *opt_api_mcast_des = ""; -int opt_api_mcast_port = 4028; -bool opt_api_network; -bool opt_delaynet; -bool opt_disable_pool; -bool opt_disable_client_reconnect = false; + static bool no_work; bool opt_worktime; #if defined(HAVE_LIBCURL) && defined(CURL_HAS_KEEPALIVE) @@ -157,11 +123,8 @@ int opt_tcp_keepalive = 30; int opt_tcp_keepalive; #endif -char *opt_kernel_path; char *sgminer_path; -#define QUIET (opt_quiet || opt_realquiet) - struct thr_info *control_thr; struct thr_info **mining_thr; static int gwsched_thr_id; @@ -279,8 +242,6 @@ struct stratum_share { static struct stratum_share *stratum_shares = NULL; -char *opt_socks_proxy = NULL; - static const char def_conf[] = "sgminer.conf"; static char *default_config; static bool config_loaded; @@ -484,8 +445,8 @@ static char *getwork_req = "{\"method\": \"getwork\", \"params\": [], \"id\":0}\ static char *gbt_req = "{\"id\": 0, \"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": [\"coinbasetxn\", \"workid\", \"coinbase/append\"]}]}\n"; -/* Adjust all the pools' quota to the greatest common denominator after a pool - * has been added or the quotas changed. */ +/* Adjust all the pools' quota to the greatest common denominator after + * a pool has been added or the quotas changed. */ void adjust_quota_gcd(void) { unsigned long gcd, lowest_quota = ~0UL, quota; @@ -566,22 +527,7 @@ struct pool *add_pool(void) return pool; } -/* Used in configuration parsing. */ -static struct pool* get_current_pool() -{ - while ((json_array_index + 1) > total_pools) - add_pool(); - - if (json_array_index < 0) { - if (!total_pools) - add_pool(); - return pools[total_pools - 1]; - } - - return pools[json_array_index]; -} - -/* Used everywhere else (to get pool currently mined on). */ +/* Used everywhere but config parsing (get pool currently mined on). */ struct pool *current_pool(void) { struct pool *pool; @@ -618,112 +564,6 @@ bool pool_tclear(struct pool *pool, bool *var) return ret; } -char *set_int_range(const char *arg, int *i, int min, int max) -{ - char *err = opt_set_intval(arg, i); - - if (err) - return err; - - if (*i < min || *i > max) - return "Value out of range"; - - return NULL; -} - -static 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) -{ - return set_int_range(arg, i, 1, 65535); -} - -static 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) -{ - return set_int_range(arg, i, 1, 10); -} - -void get_intrange(char *arg, int *val1, int *val2) -{ - if (sscanf(arg, "%d-%d", val1, val2) == 1) - *val2 = *val1; -} - -static char *set_devices(char *arg) -{ - int i, val1 = 0, val2 = 0; - char *nextptr; - - if (*arg) { - if (*arg == '?') { - opt_display_devs = true; - return NULL; - } - } else - return "Invalid device parameters"; - - nextptr = strtok(arg, ","); - if (nextptr == NULL) - return "Invalid parameters for set devices"; - get_intrange(nextptr, &val1, &val2); - if (val1 < 0 || val1 > MAX_DEVICES || val2 < 0 || val2 > MAX_DEVICES || - val1 > val2) { - return "Invalid value passed to set devices"; - } - - for (i = val1; i <= val2; i++) { - devices_enabled[i] = true; - opt_devs_enabled++; - } - - while ((nextptr = strtok(NULL, ",")) != NULL) { - get_intrange(nextptr, &val1, &val2); - if (val1 < 0 || val1 > MAX_DEVICES || val2 < 0 || val2 > MAX_DEVICES || - val1 > val2) { - return "Invalid value passed to set devices"; - } - - for (i = val1; i <= val2; i++) { - devices_enabled[i] = true; - opt_devs_enabled++; - } - } - - return NULL; -} - -static char *set_balance(enum pool_strategy *strategy) -{ - *strategy = POOL_BALANCE; - return NULL; -} - -static char *set_loadbalance(enum pool_strategy *strategy) -{ - *strategy = POOL_LOADBALANCE; - return NULL; -} - -static char *set_rotate(const char *arg, int *i) -{ - pool_strategy = POOL_ROTATE; - return set_int_range(arg, i, 0, 9999); -} - -static char *set_rr(enum pool_strategy *strategy) -{ - *strategy = POOL_ROUNDROBIN; - return NULL; -} - /* Detect that url is for a stratum protocol either via the presence of * stratum+tcp or by detecting a stratum server response */ bool detect_stratum(struct pool *pool, char *url) @@ -770,53 +610,6 @@ static void setup_url(struct pool *pool, char *arg) } } -static char *set_url(char *arg) -{ - struct pool *pool = add_url(); - - setup_url(pool, arg); - return NULL; -} - - -static char *set_pool_algorithm(const char *arg) -{ - struct pool *pool = get_current_pool(); - - applog(LOG_DEBUG, "Setting pool %i algorithm to %s", pool->pool_no, arg); - set_algorithm(&pool->algorithm, arg); - - return NULL; -} - -static char *set_pool_nfactor(const char *arg) -{ - struct pool *pool = get_current_pool(); - - applog(LOG_DEBUG, "Setting pool %i N-factor to %s", pool->pool_no, arg); - set_algorithm_nfactor(&pool->algorithm, (const uint8_t) atoi(arg)); - - return NULL; -} - -static char *set_pool_name(char *arg) -{ - struct pool *pool = get_current_pool(); - - applog(LOG_DEBUG, "Setting pool %i name to %s", pool->pool_no, arg); - opt_set_charp(arg, &pool->name); - - return NULL; -} - -static char *set_poolname_deprecated(char *arg) -{ - applog(LOG_ERR, "Specifying pool name by --poolname is deprecated. Use --name instead."); - set_pool_name(arg); - - return NULL; -} - static void enable_pool(struct pool *pool) { if (pool->state != POOL_ENABLED) @@ -863,167 +656,6 @@ void remove_pool(struct pool *pool) total_pools--; } -static char *set_pool_state(char *arg) -{ - struct pool *pool = get_current_pool(); - - applog(LOG_INFO, "Setting pool %s state to %s", get_pool_name(pool), arg); - if (strcmp(arg, "disabled") == 0) { - pool->state = POOL_DISABLED; - } else if (strcmp(arg, "enabled") == 0) { - pool->state = POOL_ENABLED; - } else if (strcmp(arg, "hidden") == 0) { - pool->state = POOL_HIDDEN; - } else if (strcmp(arg, "rejecting") == 0) { - pool->state = POOL_REJECTING; - } else { - pool->state = POOL_ENABLED; - } - - return NULL; -} - -static char *set_quota(char *arg) -{ - char *semicolon = strchr(arg, ';'), *url; - size_t len, qlen; - int quota; - struct pool *pool; - - if (!semicolon) - return "No semicolon separated quota;URL pair found"; - len = strlen(arg); - *semicolon = '\0'; - qlen = strlen(arg); - if (!qlen) - return "No parameter for quota found"; - len -= qlen + 1; - if (len < 1) - return "No parameter for URL found"; - quota = atoi(arg); - if (quota < 0) - return "Invalid negative parameter for quota set"; - url = arg + qlen + 1; - pool = add_url(); - setup_url(pool, url); - pool->quota = quota; - applog(LOG_INFO, "Setting %s to quota %d", get_pool_name(pool), pool->quota); - adjust_quota_gcd(); - - return NULL; -} - -static char *set_user(const char *arg) -{ - struct pool *pool = get_current_pool(); - - opt_set_charp(arg, &pool->rpc_user); - - return NULL; -} - -static char *set_pass(const char *arg) -{ - struct pool *pool = get_current_pool(); - - opt_set_charp(arg, &pool->rpc_pass); - - return NULL; -} - -static char *set_userpass(const char *arg) -{ - struct pool *pool = get_current_pool(); - char *updup; - - updup = strdup(arg); - opt_set_charp(arg, &pool->rpc_userpass); - pool->rpc_user = strtok(updup, ":"); - if (!pool->rpc_user) - return "Failed to find : delimited user info"; - pool->rpc_pass = strtok(NULL, ":"); - if (!pool->rpc_pass) - pool->rpc_pass = ""; - - return NULL; -} - -static char *set_pool_priority(char *arg) -{ - struct pool *pool = get_current_pool(); - - applog(LOG_DEBUG, "Setting pool %i priority to %s", pool->pool_no, arg); - opt_set_intval(arg, &pool->prio); - - return NULL; -} - -static char *set_pool_description(char *arg) -{ - struct pool *pool = get_current_pool(); - - applog(LOG_DEBUG, "Setting pool %i description to %s", pool->pool_no, arg); - opt_set_charp(arg, &pool->description); - - return NULL; -} - -static char *enable_debug(bool *flag) -{ - *flag = true; - /* Turn on verbose output, too. */ - opt_log_output = true; - return NULL; -} - -static char *set_schedtime(const char *arg, struct schedtime *st) -{ - if (sscanf(arg, "%d:%d", &st->tm.tm_hour, &st->tm.tm_min) != 2) - return "Invalid time set, should be HH:MM"; - if (st->tm.tm_hour > 23 || st->tm.tm_min > 59 || st->tm.tm_hour < 0 || st->tm.tm_min < 0) - return "Invalid time set."; - st->enable = true; - return NULL; -} - -static char* set_sharelog(char *arg) -{ - char *r = ""; - long int i = strtol(arg, &r, 10); - - if ((!*r) && i >= 0 && i <= INT_MAX) { - sharelog_file = fdopen((int)i, "a"); - if (!sharelog_file) - applog(LOG_ERR, "Failed to open fd %u for share log", (unsigned int)i); - } else if (!strcmp(arg, "-")) { - sharelog_file = stdout; - if (!sharelog_file) - applog(LOG_ERR, "Standard output missing for share log"); - } else { - sharelog_file = fopen(arg, "a"); - if (!sharelog_file) - applog(LOG_ERR, "Failed to open %s for share log", arg); - } - - return NULL; -} - -static char *temp_cutoff_str = NULL; - -char *set_temp_cutoff(char *arg) -{ - int val; - - if (!(arg && arg[0])) - return "Invalid parameters for set temp cutoff"; - val = atoi(arg); - if (val < 0 || val > 200) - return "Invalid value passed to set temp cutoff"; - temp_cutoff_str = arg; - - return NULL; -} - static void load_temp_cutoffs() { int i, val = 0, device = 0; @@ -1059,589 +691,6 @@ static void load_temp_cutoffs() } } -static char *set_algo(const char *arg) -{ - if ((json_array_index < 0) || (total_pools == 0)) { - set_algorithm(opt_algorithm, arg); - applog(LOG_INFO, "Set default algorithm to %s", opt_algorithm->name); - } else { - set_pool_algorithm(arg); - } - - return NULL; -} - -static char *set_nfactor(const char *arg) -{ - if ((json_array_index < 0) || (total_pools == 0)) { - set_algorithm_nfactor(opt_algorithm, (const uint8_t) atoi(arg)); - applog(LOG_INFO, "Set algorithm N-factor to %d (N to %d)", - opt_algorithm->nfactor, opt_algorithm->n); - } else { - set_pool_nfactor(arg); - } - - return NULL; -} - -static char *set_api_allow(const char *arg) -{ - opt_set_charp(arg, &opt_api_allow); - - return NULL; -} - -static char *set_api_groups(const char *arg) -{ - opt_set_charp(arg, &opt_api_groups); - - return NULL; -} - -static char *set_api_description(const char *arg) -{ - opt_set_charp(arg, &opt_api_description); - - return NULL; -} - -static char *set_api_mcast_addr(const char *arg) -{ - opt_set_charp(arg, &opt_api_mcast_addr); - - return NULL; -} - -static char *set_api_mcast_code(const char *arg) -{ - opt_set_charp(arg, &opt_api_mcast_code); - - return NULL; -} - -static char *set_api_mcast_des(const char *arg) -{ - opt_set_charp(arg, &opt_api_mcast_des); - - return NULL; -} - -static char *set_null(const char __maybe_unused *arg) -{ - return NULL; -} - -/* These options are available from config file or commandline */ -static struct opt_table opt_config_table[] = { - OPT_WITH_ARG("--algorithm", - set_algo, NULL, NULL, - "Set mining algorithm and most common defaults, default: scrypt"), - OPT_WITH_ARG("--api-allow", - set_api_allow, NULL, NULL, - "Allow API access only to the given list of [G:]IP[/Prefix] addresses[/subnets]"), - OPT_WITH_ARG("--api-description", - set_api_description, NULL, NULL, - "Description placed in the API status header, default: sgminer version"), - OPT_WITH_ARG("--api-groups", - set_api_groups, NULL, NULL, - "API one letter groups G:cmd:cmd[,P:cmd:*...] defining the cmds a groups can use"), - OPT_WITHOUT_ARG("--api-listen", - opt_set_bool, &opt_api_listen, - "Enable API, default: disabled"), - OPT_WITHOUT_ARG("--api-mcast", - opt_set_bool, &opt_api_mcast, - "Enable API Multicast listener, default: disabled"), - OPT_WITH_ARG("--api-mcast-addr", - set_api_mcast_addr, NULL, NULL, - "API Multicast listen address"), - OPT_WITH_ARG("--api-mcast-code", - set_api_mcast_code, NULL, NULL, - "Code expected in the API Multicast message, don't use '-'"), - OPT_WITH_ARG("--api-mcast-des", - set_api_mcast_des, NULL, NULL, - "Description appended to the API Multicast reply, default: ''"), - OPT_WITH_ARG("--api-mcast-port", - set_int_1_to_65535, opt_show_intval, &opt_api_mcast_port, - "API Multicast listen port"), - OPT_WITHOUT_ARG("--api-network", - opt_set_bool, &opt_api_network, - "Allow API (if enabled) to listen on/for any address, default: only 127.0.0.1"), - OPT_WITH_ARG("--api-port", - set_int_1_to_65535, opt_show_intval, &opt_api_port, - "Port number of miner API"), -#ifdef HAVE_ADL - OPT_WITHOUT_ARG("--auto-fan", - opt_set_bool, &opt_autofan, - "Automatically adjust all GPU fan speeds to maintain a target temperature"), - OPT_WITHOUT_ARG("--auto-gpu", - opt_set_bool, &opt_autoengine, - "Automatically adjust all GPU engine clock speeds to maintain a target temperature"), -#endif - OPT_WITHOUT_ARG("--balance", - set_balance, &pool_strategy, - "Change multipool strategy from failover to even share balance"), -#ifdef HAVE_CURSES - OPT_WITHOUT_ARG("--compact", - opt_set_bool, &opt_compact, - "Use compact display without per device statistics"), -#endif - OPT_WITHOUT_ARG("--debug|-D", - enable_debug, &opt_debug, - "Enable debug output"), - OPT_WITH_ARG("--description", - set_pool_description, NULL, NULL, - "Pool description"), - OPT_WITH_ARG("--device|-d", - set_devices, NULL, NULL, - "Select device to use, one value, range and/or comma separated (e.g. 0-2,4) default: all"), - OPT_WITHOUT_ARG("--disable-rejecting", - opt_set_bool, &opt_disable_pool, - "Automatically disable pools that continually reject shares"), - OPT_WITH_ARG("--expiry|-E", - set_int_0_to_9999, opt_show_intval, &opt_expiry, - "Upper bound on how many seconds after getting work we consider a share from it stale"), - OPT_WITHOUT_ARG("--failover-only", - opt_set_bool, &opt_fail_only, - "Don't leak work to backup pools when primary pool is lagging"), - OPT_WITH_ARG("--failover-switch-delay", - set_int_1_to_65535, opt_show_intval, &opt_fail_switch_delay, - "Delay in seconds before switching back to a failed pool"), - OPT_WITHOUT_ARG("--fix-protocol", - opt_set_bool, &opt_fix_protocol, - "Do not redirect to a different getwork protocol (eg. stratum)"), - OPT_WITH_ARG("--gpu-dyninterval", - set_int_1_to_65535, opt_show_intval, &opt_dynamic_interval, - "Set the refresh interval in ms for GPUs using dynamic intensity"), - OPT_WITH_ARG("--gpu-platform", - set_int_0_to_9999, opt_show_intval, &opt_platform_id, - "Select OpenCL platform ID to use for GPU mining"), -#ifndef HAVE_ADL - // gpu-threads can only be set per-card if ADL is available - OPT_WITH_ARG("--gpu-threads|-g", - set_int_1_to_10, opt_show_intval, &opt_g_threads, - "Number of threads per GPU (1 - 10)"), -#else - OPT_WITH_ARG("--gpu-threads|-g", - set_gpu_threads, NULL, NULL, - "Number of threads per GPU - one value or comma separated list (e.g. 1,2,1)"), - OPT_WITH_ARG("--gpu-engine", - set_gpu_engine, NULL, NULL, - "GPU engine (over)clock range in Mhz - one value, range and/or comma separated list (e.g. 850-900,900,750-850)"), - OPT_WITH_ARG("--gpu-fan", - set_gpu_fan, NULL, NULL, - "GPU fan percentage range - one value, range and/or comma separated list (e.g. 0-85,85,65)"), - OPT_WITH_ARG("--gpu-map", - set_gpu_map, NULL, NULL, - "Map OpenCL to ADL device order manually, paired CSV (e.g. 1:0,2:1 maps OpenCL 1 to ADL 0, 2 to 1)"), - OPT_WITH_ARG("--gpu-memclock", - set_gpu_memclock, NULL, NULL, - "Set the GPU memory (over)clock in Mhz - one value for all or separate by commas for per card"), - OPT_WITH_ARG("--gpu-memdiff", - set_gpu_memdiff, NULL, NULL, - "Set a fixed difference in clock speed between the GPU and memory in auto-gpu mode"), - OPT_WITH_ARG("--gpu-powertune", - set_gpu_powertune, NULL, NULL, - "Set the GPU powertune percentage - one value for all or separate by commas for per card"), - OPT_WITHOUT_ARG("--gpu-reorder", - opt_set_bool, &opt_reorder, - "Attempt to reorder GPU devices according to PCI Bus ID"), - OPT_WITH_ARG("--gpu-vddc", - set_gpu_vddc, NULL, NULL, - "Set the GPU voltage in Volts - one value for all or separate by commas for per card"), -#endif - OPT_WITH_ARG("--lookup-gap", - set_lookup_gap, NULL, NULL, - "Set GPU lookup gap for scrypt mining, comma separated"), -#ifdef HAVE_CURSES - OPT_WITHOUT_ARG("--incognito", - opt_set_bool, &opt_incognito, - "Do not display user name in status window"), -#endif - OPT_WITH_ARG("--intensity|-I", - set_intensity, NULL, NULL, - "Intensity of GPU scanning (d or " MIN_INTENSITY_STR - " -> " MAX_INTENSITY_STR - ",default: d to maintain desktop interactivity), overridden by --xintensity or --rawintensity."), - OPT_WITH_ARG("--xintensity|-X", - set_xintensity, NULL, NULL, - "Shader based intensity of GPU scanning (" MIN_XINTENSITY_STR " to " - MAX_XINTENSITY_STR "), overrides --intensity|-I, overridden by --rawintensity."), - OPT_WITH_ARG("--rawintensity", - set_rawintensity, NULL, NULL, - "Raw intensity of GPU scanning (" MIN_RAWINTENSITY_STR " to " - MAX_RAWINTENSITY_STR "), overrides --intensity|-I and --xintensity|-X."), - OPT_WITH_ARG("--kernel-path|-K", - opt_set_charp, opt_show_charp, &opt_kernel_path, - "Specify a path to where kernel files are"), - OPT_WITH_ARG("--kernel|-k", - set_kernel, NULL, NULL, - "Override kernel to use - one value or comma separated"), - OPT_WITHOUT_ARG("--load-balance", - set_loadbalance, &pool_strategy, - "Change multipool strategy from failover to quota based balance"), - OPT_WITH_ARG("--log|-l", - set_int_0_to_9999, opt_show_intval, &opt_log_interval, - "Interval in seconds between log output"), - OPT_WITHOUT_ARG("--log-show-date|-L", - opt_set_bool, &opt_log_show_date, - "Show date on every log line"), - OPT_WITHOUT_ARG("--lowmem", - opt_set_bool, &opt_lowmem, - "Minimise caching of shares for low memory applications"), -#if defined(unix) || defined(__APPLE__) - OPT_WITH_ARG("--monitor|-m", - opt_set_charp, NULL, &opt_stderr_cmd, - "Use custom pipe cmd for output messages"), -#endif // defined(unix) - OPT_WITH_ARG("--name", - set_pool_name, NULL, NULL, - "Name of pool"), - OPT_WITHOUT_ARG("--net-delay", - opt_set_bool, &opt_delaynet, - "Impose small delays in networking to not overload slow routers"), - OPT_WITH_ARG("--nfactor", - set_nfactor, NULL, NULL, - "Override default scrypt N-factor parameter."), -#ifdef HAVE_ADL - OPT_WITHOUT_ARG("--no-adl", - opt_set_bool, &opt_noadl, - "Disable the ATI display library used for monitoring and setting GPU parameters"), -#else - OPT_WITHOUT_ARG("--no-adl", - opt_set_bool, &opt_noadl, opt_hidden), -#endif - OPT_WITHOUT_ARG("--no-pool-disable", - opt_set_invbool, &opt_disable_pool, - opt_hidden), - OPT_WITHOUT_ARG("--no-client-reconnect", - opt_set_invbool, &opt_disable_client_reconnect, - "Disable 'client.reconnect' stratum functionality"), - OPT_WITHOUT_ARG("--no-restart", - opt_set_invbool, &opt_restart, - "Do not attempt to restart GPUs that hang"), - OPT_WITHOUT_ARG("--no-submit-stale", - opt_set_invbool, &opt_submit_stale, - "Don't submit shares if they are detected as stale"), - OPT_WITH_ARG("--pass|-p", - set_pass, NULL, NULL, - "Password for bitcoin JSON-RPC server"), - OPT_WITHOUT_ARG("--per-device-stats", - opt_set_bool, &want_per_device_stats, - "Force verbose mode and output per-device statistics"), - OPT_WITH_ARG("--poolname", /* TODO: Backward compatibility, to be removed. */ - set_poolname_deprecated, NULL, NULL, - opt_hidden), - OPT_WITH_ARG("--priority", - set_pool_priority, NULL, NULL, - "Pool priority"), - OPT_WITHOUT_ARG("--protocol-dump|-P", - opt_set_bool, &opt_protocol, - "Verbose dump of protocol-level activities"), - OPT_WITH_ARG("--queue|-Q", - set_int_0_to_9999, opt_show_intval, &opt_queue, - "Minimum number of work items to have queued (0+)"), - OPT_WITHOUT_ARG("--quiet|-q", - opt_set_bool, &opt_quiet, - "Disable logging output, display status and errors"), - OPT_WITH_ARG("--quota|-U", - set_quota, NULL, NULL, - "quota;URL combination for server with load-balance strategy quotas"), - OPT_WITHOUT_ARG("--real-quiet", - opt_set_bool, &opt_realquiet, - "Disable all output"), - OPT_WITHOUT_ARG("--remove-disabled", - opt_set_bool, &opt_removedisabled, - "Remove disabled devices entirely, as if they didn't exist"), - OPT_WITH_ARG("--retries", - set_null, NULL, NULL, - opt_hidden), - OPT_WITH_ARG("--retry-pause", - set_null, NULL, NULL, - opt_hidden), - OPT_WITH_ARG("--rotate", - set_rotate, opt_show_intval, &opt_rotate_period, - "Change multipool strategy from failover to regularly rotate at N minutes"), - OPT_WITHOUT_ARG("--round-robin", - set_rr, &pool_strategy, - "Change multipool strategy from failover to round robin on failure"), - OPT_WITH_ARG("--scan-time|-s", - set_int_0_to_9999, opt_show_intval, &opt_scantime, - "Upper bound on time spent scanning current work, in seconds"), - OPT_WITH_ARG("--sched-start", - set_schedtime, NULL, &schedstart, - "Set a time of day in HH:MM to start mining (a once off without a stop time)"), - OPT_WITH_ARG("--sched-stop", - set_schedtime, NULL, &schedstop, - "Set a time of day in HH:MM to stop mining (will quit without a start time)"), - OPT_WITH_ARG("--shaders", - set_shaders, NULL, NULL, - "GPU shaders per card for tuning scrypt, comma separated"), - OPT_WITH_ARG("--sharelog", - set_sharelog, NULL, NULL, - "Append share log to file"), - OPT_WITH_ARG("--shares", - opt_set_intval, NULL, &opt_shares, - "Quit after mining N shares (default: unlimited)"), - OPT_WITH_ARG("--socks-proxy", - opt_set_charp, NULL, &opt_socks_proxy, - "Set socks4 proxy (host:port)"), - OPT_WITH_ARG("--state", - set_pool_state, NULL, NULL, - "Specify pool state at startup (default: enabled)"), -#ifdef HAVE_SYSLOG_H - OPT_WITHOUT_ARG("--syslog", - opt_set_bool, &use_syslog, - "Use system log for output messages (default: standard error)"), -#endif -#if defined(HAVE_LIBCURL) && defined(CURL_HAS_KEEPALIVE) - OPT_WITH_ARG("--tcp-keepalive", - set_int_0_to_9999, opt_show_intval, &opt_tcp_keepalive, - "TCP keepalive packet idle time"), -#else - OPT_WITH_ARG("--tcp-keepalive", - set_int_0_to_9999, opt_show_intval, &opt_tcp_keepalive, - opt_hidden), -#endif -#ifdef HAVE_ADL - OPT_WITH_ARG("--temp-cutoff", - set_temp_cutoff, opt_show_intval, &opt_cutofftemp, - "Temperature which a device will be automatically disabled at, one value or comma separated list"), - OPT_WITH_ARG("--temp-hysteresis", - set_int_1_to_10, opt_show_intval, &opt_hysteresis, - "Set how much the temperature can fluctuate outside limits when automanaging speeds"), - OPT_WITH_ARG("--temp-overheat", - set_temp_overheat, opt_show_intval, &opt_overheattemp, - "Temperature which a device will be throttled at while automanaging fan and/or GPU, one value or comma separated list"), - OPT_WITH_ARG("--temp-target", - set_temp_target, opt_show_intval, &opt_targettemp, - "Temperature which a device should stay at while automanaging fan and/or GPU, one value or comma separated list"), -#endif -#ifdef HAVE_CURSES - OPT_WITHOUT_ARG("--text-only|-T", - opt_set_invbool, &use_curses, - "Disable ncurses formatted screen output"), -#else - OPT_WITHOUT_ARG("--text-only|-T", - opt_set_invbool, &use_curses, - opt_hidden), -#endif - OPT_WITH_ARG("--thread-concurrency", - set_thread_concurrency, NULL, NULL, - "Set GPU thread concurrency for scrypt mining, comma separated"), - OPT_WITH_ARG("--url|-o", - set_url, NULL, NULL, - "URL for bitcoin JSON-RPC server"), - OPT_WITH_ARG("--pool-algorithm", - set_pool_algorithm, NULL, NULL, - "Set algorithm for pool"), - OPT_WITH_ARG("--pool-nfactor", - set_pool_nfactor, NULL, NULL, - "Set N-factor for pool"), - OPT_WITH_ARG("--user|-u", - set_user, NULL, NULL, - "Username for bitcoin JSON-RPC server"), - OPT_WITH_ARG("--vectors", - set_vector, NULL, NULL, - opt_hidden), - /* All current kernels only support vectors=1 */ - /* "Override detected optimal vector (1, 2 or 4) - one value or comma separated list"), */ - OPT_WITHOUT_ARG("--verbose|-v", - opt_set_bool, &opt_log_output, - "Log verbose output to stderr as well as status output"), - OPT_WITH_ARG("--worksize|-w", - set_worksize, NULL, NULL, - "Override detected optimal worksize - one value or comma separated list"), - OPT_WITH_ARG("--userpass|-O", - set_userpass, NULL, NULL, - "Username:Password pair for bitcoin JSON-RPC server"), - OPT_WITHOUT_ARG("--worktime", - opt_set_bool, &opt_worktime, - "Display extra work time debug information"), - OPT_WITH_ARG("--pools", - opt_set_bool, NULL, NULL, opt_hidden), - OPT_ENDTABLE -}; - -static char *load_config(const char *arg, void __maybe_unused *unused); - -static int fileconf_load; - -static char *parse_config(json_t *config, bool fileconf, int parent_iteration) -{ - static char err_buf[200]; - struct opt_table *opt; - json_t *val; - - json_array_index = parent_iteration; - - if (fileconf && !fileconf_load) - fileconf_load = 1; - - for (opt = opt_config_table; opt->type != OPT_END; opt++) { - char *p, *name; - - /* We don't handle subtables. */ - assert(!(opt->type & OPT_SUBTABLE)); - - if (!opt->names) - continue; - - /* Pull apart the option name(s). */ - name = strdup(opt->names); - for (p = strtok(name, "|"); p; p = strtok(NULL, "|")) { - char *err = NULL; - - /* Ignore short options. */ - if (p[1] != '-') - continue; - - val = json_object_get(config, p+2); - if (!val) - continue; - - if ((opt->type & OPT_HASARG) && json_is_string(val)) { - err = opt->cb_arg(json_string_value(val), - opt->u.arg); - } else if ((opt->type & OPT_HASARG) && json_is_array(val)) { - size_t n, size = json_array_size(val); - - for (n = 0; n < size && !err; n++) { - if (json_is_string(json_array_get(val, n))) - err = opt->cb_arg(json_string_value(json_array_get(val, n)), opt->u.arg); - else if (json_is_object(json_array_get(val, n))) - { - err = parse_config(json_array_get(val, n), false, n); - } - } - } else if ((opt->type & OPT_NOARG) && json_is_true(val)) - err = opt->cb(opt->u.arg); - else - err = "Invalid value"; - - if (err) { - /* Allow invalid values to be in configuration - * file, just skipping over them provided the - * JSON is still valid after that. */ - if (fileconf) { - applog(LOG_WARNING, "Skipping config option %s: %s", p, err); - fileconf_load = -1; - } else { - snprintf(err_buf, sizeof(err_buf), "Error parsing JSON option %s: %s", - p, err); - return err_buf; - } - } - } - free(name); - } - - val = json_object_get(config, JSON_INCLUDE_CONF); - if (val && json_is_string(val)) - return load_config(json_string_value(val), NULL); - - return NULL; -} - -char *cnfbuf = NULL; - -static char *load_config(const char *arg, void __maybe_unused *unused) -{ - json_error_t err; - json_t *config; - char *json_error; - size_t siz; - - if (!cnfbuf) - cnfbuf = strdup(arg); - - if (++include_count > JSON_MAX_DEPTH) - return JSON_MAX_DEPTH_ERR; - -#if JANSSON_MAJOR_VERSION > 1 - config = json_load_file(arg, 0, &err); -#else - config = json_load_file(arg, &err); -#endif - if (!json_is_object(config)) { - siz = JSON_LOAD_ERROR_LEN + strlen(arg) + strlen(err.text); - json_error = (char *)malloc(siz); - if (!json_error) - quit(1, "Malloc failure in json error"); - - snprintf(json_error, siz, JSON_LOAD_ERROR, arg, err.text); - return json_error; - } - - config_loaded = true; - - /* Parse the config now, so we can override it. That can keep pointers - * so don't free config object. */ - return parse_config(config, true, -1); -} - -static char *set_default_config(const char *arg) -{ - opt_set_charp(arg, &default_config); - - return NULL; -} - -void default_save_file(char *filename); - -static void load_default_config(void) -{ - cnfbuf = (char *)malloc(PATH_MAX); - - default_save_file(cnfbuf); - - if (!access(cnfbuf, R_OK)) - load_config(cnfbuf, NULL); - else { - free(cnfbuf); - cnfbuf = NULL; - } -} - -extern const char *opt_argv0; - -static char *opt_verusage_and_exit(const char *extra) -{ - printf("%s\n", packagename); - printf("%s", opt_usage(opt_argv0, extra)); - fflush(stdout); - exit(0); -} - -char *display_devs(int *ndevs) -{ - *ndevs = 0; - print_ndevs(ndevs); - exit(*ndevs); -} - -/* These options are available from commandline only */ -static struct opt_table opt_cmdline_table[] = { - OPT_WITH_ARG("--config|-c", - load_config, NULL, NULL, - "Load a JSON-format configuration file\n" - "See example.conf for an example configuration."), - OPT_WITH_ARG("--default-config", - set_default_config, NULL, NULL, - "Specify the filename of the default config file\n" - "Loaded at start and used when saving without a name."), - OPT_WITHOUT_ARG("--help|-h", - opt_verusage_and_exit, NULL, - "Print this message"), - OPT_WITHOUT_ARG("--ndevs|-n", - display_devs, &nDevs, - "Display number of detected GPUs, OpenCL platform " - "information, and exit"), - OPT_WITHOUT_ARG("--version|-V", - opt_version_and_exit, packagename, - "Display version and exit"), - OPT_ENDTABLE -}; - #ifdef HAVE_LIBCURL static bool jobj_binary(const json_t *obj, const char *key, void *buf, size_t buflen, bool required)