diff --git a/Makefile.am b/Makefile.am index 97953303..d89c4776 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,7 +32,7 @@ sgminer_CPPFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\" endif sgminer_SOURCES := sgminer.c -sgminer_SOURCES += api.c +sgminer_SOURCES += api.c api.h sgminer_SOURCES += elist.h miner.h compat.h bench_block.h sgminer_SOURCES += util.c util.h uthash.h sgminer_SOURCES += logging.c logging.h diff --git a/api.c b/api.c index afe9ebe0..53ed542f 100644 --- a/api.c +++ b/api.c @@ -26,6 +26,7 @@ #include #include "compat.h" +#include "api.h" #include "miner.h" #include "pool.h" #include "util.h" @@ -33,72 +34,9 @@ #include "config_parser.h" -// BUFSIZ varies on Windows and Linux -#define TMPBUFSIZ 8192 - -// Number of requests to queue - normally would be small -#define QUEUE 100 - -#if defined WIN32 +#ifdef WIN32 static char WSAbuf[1024]; -struct WSAERRORS { - int id; - char *code; -} WSAErrors[] = { - { 0, "No error" }, - { WSAEINTR, "Interrupted system call" }, - { WSAEBADF, "Bad file number" }, - { WSAEACCES, "Permission denied" }, - { WSAEFAULT, "Bad address" }, - { WSAEINVAL, "Invalid argument" }, - { WSAEMFILE, "Too many open sockets" }, - { WSAEWOULDBLOCK, "Operation would block" }, - { WSAEINPROGRESS, "Operation now in progress" }, - { WSAEALREADY, "Operation already in progress" }, - { WSAENOTSOCK, "Socket operation on non-socket" }, - { WSAEDESTADDRREQ, "Destination address required" }, - { WSAEMSGSIZE, "Message too long" }, - { WSAEPROTOTYPE, "Protocol wrong type for socket" }, - { WSAENOPROTOOPT, "Bad protocol option" }, - { WSAEPROTONOSUPPORT, "Protocol not supported" }, - { WSAESOCKTNOSUPPORT, "Socket type not supported" }, - { WSAEOPNOTSUPP, "Operation not supported on socket" }, - { WSAEPFNOSUPPORT, "Protocol family not supported" }, - { WSAEAFNOSUPPORT, "Address family not supported" }, - { WSAEADDRINUSE, "Address already in use" }, - { WSAEADDRNOTAVAIL, "Can't assign requested address" }, - { WSAENETDOWN, "Network is down" }, - { WSAENETUNREACH, "Network is unreachable" }, - { WSAENETRESET, "Net connection reset" }, - { WSAECONNABORTED, "Software caused connection abort" }, - { WSAECONNRESET, "Connection reset by peer" }, - { WSAENOBUFS, "No buffer space available" }, - { WSAEISCONN, "Socket is already connected" }, - { WSAENOTCONN, "Socket is not connected" }, - { WSAESHUTDOWN, "Can't send after socket shutdown" }, - { WSAETOOMANYREFS, "Too many references, can't splice" }, - { WSAETIMEDOUT, "Connection timed out" }, - { WSAECONNREFUSED, "Connection refused" }, - { WSAELOOP, "Too many levels of symbolic links" }, - { WSAENAMETOOLONG, "File name too long" }, - { WSAEHOSTDOWN, "Host is down" }, - { WSAEHOSTUNREACH, "No route to host" }, - { WSAENOTEMPTY, "Directory not empty" }, - { WSAEPROCLIM, "Too many processes" }, - { WSAEUSERS, "Too many users" }, - { WSAEDQUOT, "Disc quota exceeded" }, - { WSAESTALE, "Stale NFS file handle" }, - { WSAEREMOTE, "Too many levels of remote in path" }, - { WSASYSNOTREADY, "Network system is unavailable" }, - { WSAVERNOTSUPPORTED, "Winsock version out of range" }, - { WSANOTINITIALISED, "WSAStartup not yet called" }, - { WSAEDISCON, "Graceful shutdown in progress" }, - { WSAHOST_NOT_FOUND, "Host not found" }, - { WSANO_DATA, "No host data of that type was found" }, - { -1, "Unknown error code" } -}; - char *WSAErrorMsg(void) { int i; int id = WSAGetLastError(); @@ -114,21 +52,15 @@ char *WSAErrorMsg(void) { } #endif + static const char *UNAVAILABLE = " - API will not be available"; static const char *MUNAVAILABLE = " - API multicast listener will not be available"; static const char *BLANK = ""; static const char *COMMA = ","; -#define COMSTR "," static const char SEPARATOR = '|'; -#define SEPSTR "|" static const char GPUSEP = ','; - -#define CMDJOIN '+' -#define JOIN_CMD "CMD=" -#define BETWEEN_JOIN SEPSTR - -static const char *APIVERSION = "3.2"; +static const char *APIVERSION = "4.0"; static const char *DEAD = "Dead"; static const char *SICK = "Sick"; static const char *NOSTART = "NoStart"; @@ -137,7 +69,6 @@ static const char *DISABLED = "Disabled"; static const char *ALIVE = "Alive"; static const char *REJECTING = "Rejecting"; static const char *UNKNOWN = "Unknown"; -#define _DYNAMIC "D" static const char *DYNAMIC = _DYNAMIC; static __maybe_unused const char *NONE = "None"; @@ -166,270 +97,9 @@ static const char *OSINFO = "Unknown"; #endif -#define _DEVS "DEVS" -#define _POOLS "POOLS" -#define _SUMMARY "SUMMARY" -#define _STATUS "STATUS" -#define _VERSION "VERSION" -#define _MINECONFIG "CONFIG" -#define _GPU "GPU" - -#define _GPUS "GPUS" -#define _NOTIFY "NOTIFY" -#define _DEVDETAILS "DEVDETAILS" -#define _BYE "BYE" -#define _RESTART "RESTART" -#define _MINESTATS "STATS" -#define _CHECK "CHECK" -#define _MINECOIN "COIN" -#define _DEBUGSET "DEBUG" -#define _SETCONFIG "SETCONFIG" - -static const char ISJSON = '{'; -#define JSON0 "{" -#define JSON1 "\"" -#define JSON2 "\":[" -#define JSON3 "]" -#define JSON4 ",\"id\":1" -// If anyone cares, id=0 for truncated output -#define JSON4_TRUNCATED ",\"id\":0" -#define JSON5 "}" - -#define JSON_START JSON0 -#define JSON_DEVS JSON1 _DEVS JSON2 -#define JSON_POOLS JSON1 _POOLS JSON2 -#define JSON_SUMMARY JSON1 _SUMMARY JSON2 -#define JSON_STATUS JSON1 _STATUS JSON2 -#define JSON_VERSION JSON1 _VERSION JSON2 -#define JSON_MINECONFIG JSON1 _MINECONFIG JSON2 -#define JSON_GPU JSON1 _GPU JSON2 - -#define JSON_GPUS JSON1 _GPUS JSON2 -#define JSON_NOTIFY JSON1 _NOTIFY JSON2 -#define JSON_DEVDETAILS JSON1 _DEVDETAILS JSON2 -#define JSON_CLOSE JSON3 -#define JSON_MINESTATS JSON1 _MINESTATS JSON2 -#define JSON_CHECK JSON1 _CHECK JSON2 -#define JSON_MINECOIN JSON1 _MINECOIN JSON2 -#define JSON_DEBUGSET JSON1 _DEBUGSET JSON2 -#define JSON_SETCONFIG JSON1 _SETCONFIG JSON2 - -#define JSON_END JSON4 JSON5 -#define JSON_END_TRUNCATED JSON4_TRUNCATED JSON5 -#define JSON_BETWEEN_JOIN "," - static const char *JSON_COMMAND = "command"; static const char *JSON_PARAMETER = "parameter"; - -#define MSG_INVGPU 1 -#define MSG_ALRENA 2 -#define MSG_ALRDIS 3 -#define MSG_GPUMRE 4 -#define MSG_GPUREN 5 -#define MSG_GPUNON 6 -#define MSG_POOL 7 -#define MSG_NOPOOL 8 -#define MSG_DEVS 9 -#define MSG_NODEVS 10 -#define MSG_SUMM 11 -#define MSG_GPUDIS 12 -#define MSG_GPUREI 13 -#define MSG_INVCMD 14 -#define MSG_MISID 15 -#define MSG_GPUDEV 17 - -#define MSG_NUMGPU 20 - -#define MSG_VERSION 22 -#define MSG_INVJSON 23 -#define MSG_MISCMD 24 -#define MSG_MISPID 25 -#define MSG_INVPID 26 -#define MSG_SWITCHP 27 -#define MSG_MISVAL 28 -#define MSG_NOADL 29 -#define MSG_NOGPUADL 30 -#define MSG_INVINT 31 -#define MSG_GPUINT 32 -#define MSG_MINECONFIG 33 -#define MSG_GPUMERR 34 -#define MSG_GPUMEM 35 -#define MSG_GPUEERR 36 -#define MSG_GPUENG 37 -#define MSG_GPUVERR 38 -#define MSG_GPUVDDC 39 -#define MSG_GPUFERR 40 -#define MSG_GPUFAN 41 -#define MSG_MISFN 42 -#define MSG_BADFN 43 -#define MSG_SAVED 44 -#define MSG_ACCDENY 45 -#define MSG_ACCOK 46 -#define MSG_ENAPOOL 47 -#define MSG_DISPOOL 48 -#define MSG_ALRENAP 49 -#define MSG_ALRDISP 50 -#define MSG_MISPDP 52 -#define MSG_INVPDP 53 -#define MSG_TOOMANYP 54 -#define MSG_ADDPOOL 55 - -#define MSG_NOTIFY 60 - -#define MSG_REMLASTP 66 -#define MSG_ACTPOOL 67 -#define MSG_REMPOOL 68 -#define MSG_DEVDETAILS 69 -#define MSG_MINESTATS 70 -#define MSG_MISCHK 71 -#define MSG_CHECK 72 -#define MSG_POOLPRIO 73 -#define MSG_DUPPID 74 -#define MSG_MISBOOL 75 -#define MSG_INVBOOL 76 -#define MSG_FOO 77 -#define MSG_MINECOIN 78 -#define MSG_DEBUGSET 79 -#define MSG_SETCONFIG 82 -#define MSG_UNKCON 83 -#define MSG_INVNUM 84 -#define MSG_CONPAR 85 -#define MSG_CONVAL 86 - -#define MSG_NOUSTA 88 - -#define MSG_ZERMIS 94 -#define MSG_ZERINV 95 -#define MSG_ZERSUM 96 -#define MSG_ZERNOSUM 97 - -#define MSG_BYE 0x101 - -#define MSG_INVNEG 121 -#define MSG_SETQUOTA 122 -#define MSG_LOCKOK 123 -#define MSG_LOCKDIS 124 - -enum code_severity { - SEVERITY_ERR, - SEVERITY_WARN, - SEVERITY_INFO, - SEVERITY_SUCC, - SEVERITY_FAIL -}; - -enum code_parameters { - PARAM_GPU, - PARAM_PID, - PARAM_GPUMAX, - PARAM_PMAX, - PARAM_POOLMAX, - -// Single generic case: have the code resolve it - see below - PARAM_DMAX, - - PARAM_CMD, - PARAM_POOL, - PARAM_STR, - PARAM_BOTH, - PARAM_BOOL, - PARAM_SET, - PARAM_INT, - PARAM_NONE -}; - -struct CODES { - const enum code_severity severity; - const int code; - const enum code_parameters params; - const char *description; -} codes[] = { - { SEVERITY_ERR, MSG_INVGPU, PARAM_GPUMAX, "Invalid GPU id %d - range is 0 - %d" }, - { SEVERITY_INFO, MSG_ALRENA, PARAM_GPU, "GPU %d already enabled" }, - { SEVERITY_INFO, MSG_ALRDIS, PARAM_GPU, "GPU %d already disabled" }, - { SEVERITY_WARN, MSG_GPUMRE, PARAM_GPU, "GPU %d must be restarted first" }, - { SEVERITY_INFO, MSG_GPUREN, PARAM_GPU, "GPU %d sent enable message" }, - { SEVERITY_ERR, MSG_GPUNON, PARAM_NONE, "No GPUs" }, - { SEVERITY_SUCC, MSG_POOL, PARAM_PMAX, "%d Pool(s)" }, - { SEVERITY_ERR, MSG_NOPOOL, PARAM_NONE, "No pools" }, - - { SEVERITY_SUCC, MSG_DEVS, PARAM_DMAX, "%d GPU(s)" }, - { SEVERITY_ERR, MSG_NODEVS, PARAM_NONE, "No GPUs" - }, - - { SEVERITY_SUCC, MSG_SUMM, PARAM_NONE, "Summary" }, - { SEVERITY_INFO, MSG_GPUDIS, PARAM_GPU, "GPU %d set disable flag" }, - { SEVERITY_INFO, MSG_GPUREI, PARAM_GPU, "GPU %d restart attempted" }, - { SEVERITY_ERR, MSG_INVCMD, PARAM_NONE, "Invalid command" }, - { SEVERITY_ERR, MSG_MISID, PARAM_NONE, "Missing device id parameter" }, - { SEVERITY_SUCC, MSG_GPUDEV, PARAM_GPU, "GPU%d" }, - { SEVERITY_SUCC, MSG_NUMGPU, PARAM_NONE, "GPU count" }, - { SEVERITY_SUCC, MSG_VERSION, PARAM_NONE, "SGMiner versions" }, - { SEVERITY_ERR, MSG_INVJSON, PARAM_NONE, "Invalid JSON" }, - { SEVERITY_ERR, MSG_MISCMD, PARAM_CMD, "Missing JSON '%s'" }, - { SEVERITY_ERR, MSG_MISPID, PARAM_NONE, "Missing pool id parameter" }, - { SEVERITY_ERR, MSG_INVPID, PARAM_POOLMAX, "Invalid pool id %d - range is 0 - %d" }, - { SEVERITY_SUCC, MSG_SWITCHP, PARAM_POOL, "Switching to pool %d:'%s'" }, - { SEVERITY_ERR, MSG_MISVAL, PARAM_NONE, "Missing comma after GPU number" }, - { SEVERITY_ERR, MSG_NOADL, PARAM_NONE, "ADL is not available" }, - { SEVERITY_ERR, MSG_NOGPUADL,PARAM_GPU, "GPU %d does not have ADL" }, - { SEVERITY_ERR, MSG_INVINT, PARAM_STR, "Invalid intensity (%s) - must be '" _DYNAMIC "' or range " MIN_INTENSITY_STR " - " MAX_INTENSITY_STR }, - { SEVERITY_INFO, MSG_GPUINT, PARAM_BOTH, "GPU %d set new intensity to %s" }, - { SEVERITY_SUCC, MSG_MINECONFIG,PARAM_NONE, "sgminer config" }, - { SEVERITY_ERR, MSG_GPUMERR, PARAM_BOTH, "Setting GPU %d memoryclock to (%s) reported failure" }, - { SEVERITY_SUCC, MSG_GPUMEM, PARAM_BOTH, "Setting GPU %d memoryclock to (%s) reported success" }, - { SEVERITY_ERR, MSG_GPUEERR, PARAM_BOTH, "Setting GPU %d clock to (%s) reported failure" }, - { SEVERITY_SUCC, MSG_GPUENG, PARAM_BOTH, "Setting GPU %d clock to (%s) reported success" }, - { SEVERITY_ERR, MSG_GPUVERR, PARAM_BOTH, "Setting GPU %d vddc to (%s) reported failure" }, - { SEVERITY_SUCC, MSG_GPUVDDC, PARAM_BOTH, "Setting GPU %d vddc to (%s) reported success" }, - { SEVERITY_ERR, MSG_GPUFERR, PARAM_BOTH, "Setting GPU %d fan to (%s) reported failure" }, - { SEVERITY_SUCC, MSG_GPUFAN, PARAM_BOTH, "Setting GPU %d fan to (%s) reported success" }, - { SEVERITY_ERR, MSG_MISFN, PARAM_NONE, "Missing save filename parameter" }, - { SEVERITY_ERR, MSG_BADFN, PARAM_STR, "Can't open or create save file '%s'" }, - { SEVERITY_SUCC, MSG_SAVED, PARAM_STR, "Configuration saved to file '%s'" }, - { SEVERITY_ERR, MSG_ACCDENY, PARAM_STR, "Access denied to '%s' command" }, - { SEVERITY_SUCC, MSG_ACCOK, PARAM_NONE, "Privileged access OK" }, - { SEVERITY_SUCC, MSG_ENAPOOL, PARAM_POOL, "Enabling pool %d:'%s'" }, - { SEVERITY_SUCC, MSG_POOLPRIO,PARAM_NONE, "Changed pool priorities" }, - { SEVERITY_ERR, MSG_DUPPID, PARAM_PID, "Duplicate pool specified %d" }, - { SEVERITY_SUCC, MSG_DISPOOL, PARAM_POOL, "Disabling pool %d:'%s'" }, - { SEVERITY_INFO, MSG_ALRENAP, PARAM_POOL, "Pool %d:'%s' already enabled" }, - { SEVERITY_INFO, MSG_ALRDISP, PARAM_POOL, "Pool %d:'%s' already disabled" }, - { SEVERITY_ERR, MSG_MISPDP, PARAM_NONE, "Missing addpool details" }, - { SEVERITY_ERR, MSG_INVPDP, PARAM_STR, "Invalid addpool details '%s'" }, - { SEVERITY_ERR, MSG_TOOMANYP,PARAM_NONE, "Reached maximum number of pools (%d)" }, - { SEVERITY_SUCC, MSG_ADDPOOL, PARAM_STR, "Added pool '%s'" }, - { SEVERITY_ERR, MSG_REMLASTP,PARAM_POOL, "Cannot remove last pool %d:'%s'" }, - { SEVERITY_ERR, MSG_ACTPOOL, PARAM_POOL, "Cannot remove active pool %d:'%s'" }, - { SEVERITY_SUCC, MSG_REMPOOL, PARAM_BOTH, "Removed pool %d:'%s'" }, - { SEVERITY_SUCC, MSG_NOTIFY, PARAM_NONE, "Notify" }, - { SEVERITY_SUCC, MSG_DEVDETAILS,PARAM_NONE, "Device Details" }, - { SEVERITY_SUCC, MSG_MINESTATS,PARAM_NONE, "sgminer stats" }, - { SEVERITY_ERR, MSG_MISCHK, PARAM_NONE, "Missing check cmd" }, - { SEVERITY_SUCC, MSG_CHECK, PARAM_NONE, "Check command" }, - { SEVERITY_ERR, MSG_MISBOOL, PARAM_NONE, "Missing parameter: true/false" }, - { SEVERITY_ERR, MSG_INVBOOL, PARAM_NONE, "Invalid parameter should be true or false" }, - { SEVERITY_SUCC, MSG_FOO, PARAM_BOOL, "Failover-Only set to %s" }, - { SEVERITY_SUCC, MSG_MINECOIN,PARAM_NONE, "sgminer coin" }, - { SEVERITY_SUCC, MSG_DEBUGSET,PARAM_NONE, "Debug settings" }, - { SEVERITY_SUCC, MSG_SETCONFIG,PARAM_SET, "Set config '%s' to %d" }, - { SEVERITY_ERR, MSG_UNKCON, PARAM_STR, "Unknown config '%s'" }, - { SEVERITY_ERR, MSG_INVNUM, PARAM_BOTH, "Invalid number (%d) for '%s' range is 0-9999" }, - { SEVERITY_ERR, MSG_INVNEG, PARAM_BOTH, "Invalid negative number (%d) for '%s'" }, - { SEVERITY_SUCC, MSG_SETQUOTA,PARAM_SET, "Set pool '%s' to quota %d'" }, - { SEVERITY_ERR, MSG_CONPAR, PARAM_NONE, "Missing config parameters 'name,N'" }, - { SEVERITY_ERR, MSG_CONVAL, PARAM_STR, "Missing config value N for '%s,N'" }, - { SEVERITY_INFO, MSG_NOUSTA, PARAM_NONE, "No USB Statistics" }, - { SEVERITY_ERR, MSG_ZERMIS, PARAM_NONE, "Missing zero parameters" }, - { SEVERITY_ERR, MSG_ZERINV, PARAM_STR, "Invalid zero parameter '%s'" }, - { SEVERITY_SUCC, MSG_ZERSUM, PARAM_STR, "Zeroed %s stats with summary" }, - { SEVERITY_SUCC, MSG_ZERNOSUM, PARAM_STR, "Zeroed %s stats without summary" }, - { SEVERITY_SUCC, MSG_LOCKOK, PARAM_NONE, "Lock stats created" }, - { SEVERITY_WARN, MSG_LOCKDIS, PARAM_NONE, "Lock stats not enabled" }, - { SEVERITY_SUCC, MSG_BYE, PARAM_STR, "%s" }, - { SEVERITY_FAIL, 0, (enum code_parameters)0, NULL } -}; - +static const char ISJSON = '{'; static const char *localaddr = "127.0.0.1"; static int my_thr_id = 0; @@ -443,50 +113,11 @@ static bool do_a_restart; static time_t when = 0; // when the request occurred -struct IP4ACCESS { - in_addr_t ip; - in_addr_t mask; - char group; -}; - -#define GROUP(g) (toupper(g)) -#define PRIVGROUP GROUP('W') -#define NOPRIVGROUP GROUP('R') -#define ISPRIVGROUP(g) (GROUP(g) == PRIVGROUP) -#define GROUPOFFSET(g) (GROUP(g) - GROUP('A')) -#define VALIDGROUP(g) (GROUP(g) >= GROUP('A') && GROUP(g) <= GROUP('Z')) -#define COMMANDS(g) (apigroups[GROUPOFFSET(g)].commands) -#define DEFINEDGROUP(g) (ISPRIVGROUP(g) || COMMANDS(g) != NULL) - -struct APIGROUPS { - // This becomes a string like: "|cmd1|cmd2|cmd3|" so it's quick to search - char *commands; -} apigroups['Z' - 'A' + 1]; // only A=0 to Z=25 (R: noprivs, W: allprivs) - static struct IP4ACCESS *ipaccess = NULL; static int ips = 0; -struct io_data { - size_t siz; - char *ptr; - char *cur; - bool sock; - bool close; -}; - -struct io_list { - struct io_data *io_data; - struct io_list *prev; - struct io_list *next; -}; - static struct io_list *io_head = NULL; -#define SOCKBUFALLOCSIZ 65536 - -#define io_new(init) _io_new(init, false) -#define sock_io_new() _io_new(SOCKBUFALLOCSIZ, true) - static void io_reinit(struct io_data *io_data) { io_data->cur = io_data->ptr; @@ -1047,7 +678,7 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson // All replies (except BYE and RESTART) start with a message // thus for JSON, message() inserts JSON_START at the front // and send_result() adds JSON_END at the end -static void message(struct io_data *io_data, int messageid, int paramid, char *param2, bool isjson) +void message(struct io_data *io_data, int messageid, int paramid, char *param2, bool isjson) { struct api_data *root = NULL; char buf[TMPBUFSIZ]; @@ -1149,49 +780,6 @@ static void message(struct io_data *io_data, int messageid, int paramid, char *p #if LOCK_TRACKING -#define LOCK_FMT_FFL " - called from %s %s():%d" - -#define LOCKMSG(fmt, ...) fprintf(stderr, "APILOCK: " fmt "\n", ##__VA_ARGS__) -#define LOCKMSGMORE(fmt, ...) fprintf(stderr, " " fmt "\n", ##__VA_ARGS__) -#define LOCKMSGFFL(fmt, ...) fprintf(stderr, "APILOCK: " fmt LOCK_FMT_FFL "\n", ##__VA_ARGS__, file, func, linenum) -#define LOCKMSGFLUSH() fflush(stderr) - -typedef struct lockstat { - uint64_t lock_id; - const char *file; - const char *func; - int linenum; - struct timeval tv; -} LOCKSTAT; - -typedef struct lockline { - struct lockline *prev; - struct lockstat *stat; - struct lockline *next; -} LOCKLINE; - -typedef struct lockinfo { - void *lock; - enum cglock_typ typ; - const char *file; - const char *func; - int linenum; - uint64_t gets; - uint64_t gots; - uint64_t tries; - uint64_t dids; - uint64_t didnts; // should be tries - dids - uint64_t unlocks; - LOCKSTAT lastgot; - LOCKLINE *lockgets; - LOCKLINE *locktries; -} LOCKINFO; - -typedef struct locklist { - LOCKINFO *info; - struct locklist *next; -} LOCKLIST; - static uint64_t lock_id = 1; static LOCKLIST *lockhead; @@ -1534,6 +1122,23 @@ void show_locks() } #endif +static void copyadvanceafter(char ch, char **param, char **buf) +{ +#define src_p (*param) +#define dst_b (*buf) + + while (*src_p && *src_p != ch) { + if (*src_p == '\\' && *(src_p+1) != '\0') + src_p++; + + *(dst_b++) = *(src_p++); + } + if (*src_p) + src_p++; + + *(dst_b++) = '\0'; +} + static void lockstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { #if LOCK_TRACKING @@ -1824,6 +1429,7 @@ static void poolstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __m root = api_add_string(root, "Name", get_pool_name(pool), true); mutex_unlock(&pool->stratum_lock); root = api_add_escape(root, "URL", pool->rpc_url, false); + root = api_add_string(root, "Profile", pool->profile, false); root = api_add_string(root, "Algorithm", pool->algorithm.name, false); root = api_add_string(root, "Description", pool->description, false); root = api_add_string(root, "Status", status, false); @@ -2101,25 +1707,74 @@ static void switchpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, cha message(io_data, MSG_SWITCHP, id, NULL, isjson); } -static void copyadvanceafter(char ch, char **param, char **buf) +static void api_pool_strategy(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { -#define src_p (*param) -#define dst_b (*buf) + char *p; + int strategy; + + if (total_pools == 0) + { + message(io_data, MSG_NOPOOL, 0, NULL, isjson); + return; + } - while (*src_p && *src_p != ch) { - if (*src_p == '\\' && *(src_p+1) != '\0') - src_p++; + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISSTRAT, 0, NULL, isjson); + return; + } - *(dst_b++) = *(src_p++); + //get strategy in parameter 1 + if(!(p = strtok(param, ","))) + { + message(io_data, MSG_MISSTRAT, 0, NULL, isjson); + return; } - if (*src_p) - src_p++; + + strategy = atoi(p); - *(dst_b++) = '\0'; + //invalid strategy + if(strategy < 0 || strategy > TOP_STRATEGY) + { + message(io_data, MSG_INVSTRAT, strategy, NULL, isjson); + return; + } + + //if set to rotate, get second param + if(strategy == POOL_ROTATE) + { + //if second param is missing then invalid + if(!(p = strtok(NULL, ","))) + { + message(io_data, MSG_MISSTRATINT, 0, NULL, isjson); + return; + } + + //get interval in parameter 2 + int interval; + interval = atoi(p); + + //interval can only be between 0 and 9999 + if(interval < 0 || interval > 9999) + { + message(io_data, MSG_INVNUM, interval, "interval", isjson); + return; + } + + //set interval + opt_rotate_period = interval; + } + + //set pool strategy + pool_strategy = (enum pool_strategy)strategy; + //initiate new strategy + switch_pools(NULL); + + message(io_data, MSG_CHSTRAT, 0, (char *)strategies[strategy].s, isjson); } static bool pooldetails(char *param, char **url, char **user, char **pass, - char **name, char **desc, char **algo) + char **name, char **desc, char **profile, char **algo) { char *ptr, *buf; @@ -2134,23 +1789,28 @@ static bool pooldetails(char *param, char **url, char **user, char **pass, *user = buf; copyadvanceafter(',', ¶m, &buf); - if (!*param) // missing pass + if (!(*param)) // missing pass goto exitsama; *pass = buf; copyadvanceafter(',', ¶m, &buf); - if (!*param) // missing name (allowed) + if (!(*param)) // missing name (allowed) return true; *name = buf; copyadvanceafter(',', ¶m, &buf); - if (!*param) // missing desc - goto exitsama; + if (!(*param)) // missing desc + return true; *desc = buf; copyadvanceafter(',', ¶m, &buf); - if (!*param) // missing algo - goto exitsama; + if (!(*param)) // missing profile + return true; + + *profile = buf; + copyadvanceafter(',', ¶m, &buf); + if (!(*param)) // missing algo + return true; *algo = buf; copyadvanceafter(',', ¶m, &buf); @@ -2165,7 +1825,7 @@ exitsama: static void addpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { char *url, *user, *pass; - char *name = NULL, *desc = NULL, *algo = NULL; + char *name = NULL, *desc = NULL, *algo = NULL, *profile = NULL; struct pool *pool; char *ptr; @@ -2175,7 +1835,7 @@ static void addpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char * } if (!pooldetails(param, &url, &user, &pass, - &name, &desc, &algo)) { + &name, &desc, &profile, &algo)) { ptr = escape_string(param, isjson); message(io_data, MSG_INVPDP, 0, ptr, isjson); if (ptr != param) @@ -2185,13 +1845,14 @@ static void addpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char * } /* If API client is old, it might not have provided all fields. */ - if (name == NULL) name = strdup(""); - if (desc == NULL) desc = strdup(""); - if (algo == NULL) algo = strdup("scrypt"); // FIXME? + name = ((name == NULL)?strdup(""):name); + desc = ((desc == NULL)?strdup(""):desc); + profile = ((profile == NULL)?strdup(""):profile); + algo = ((algo == NULL)?strdup(""):algo); pool = add_pool(); detect_stratum(pool, url); - add_pool_details(pool, true, url, user, pass, name, desc, algo); + add_pool_details(pool, true, url, user, pass, name, desc, profile, algo); ptr = escape_string(url, isjson); message(io_data, MSG_ADDPOOL, 0, ptr, isjson); @@ -2729,7 +2390,7 @@ static void devdetails(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __m void dosave(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { char filename[PATH_MAX]; - FILE *fcfg; +// FILE *fcfg; char *ptr; if (param == NULL || *param == '\0') { @@ -3071,6 +2732,7 @@ struct CMDS { { "gpu", gpudev, false, false }, { "gpucount", gpucount, false, true }, { "switchpool", switchpool, true, false }, + { "changestrategy", api_pool_strategy, true, false }, { "addpool", addpool, true, false }, { "poolpriority", poolpriority, true, false }, { "poolquota", poolquota, true, false }, diff --git a/api.h b/api.h new file mode 100644 index 00000000..8c445c68 --- /dev/null +++ b/api.h @@ -0,0 +1,436 @@ +#ifndef API_H +#define API_H + +#include "config.h" + +#include "miner.h" + +// BUFSIZ varies on Windows and Linux +#define TMPBUFSIZ 8192 + +// Number of requests to queue - normally would be small +#define QUEUE 100 + +#ifdef WIN32 +struct WSAERRORS { + int id; + char *code; +} WSAErrors[] = { + { 0, "No error" }, + { WSAEINTR, "Interrupted system call" }, + { WSAEBADF, "Bad file number" }, + { WSAEACCES, "Permission denied" }, + { WSAEFAULT, "Bad address" }, + { WSAEINVAL, "Invalid argument" }, + { WSAEMFILE, "Too many open sockets" }, + { WSAEWOULDBLOCK, "Operation would block" }, + { WSAEINPROGRESS, "Operation now in progress" }, + { WSAEALREADY, "Operation already in progress" }, + { WSAENOTSOCK, "Socket operation on non-socket" }, + { WSAEDESTADDRREQ, "Destination address required" }, + { WSAEMSGSIZE, "Message too long" }, + { WSAEPROTOTYPE, "Protocol wrong type for socket" }, + { WSAENOPROTOOPT, "Bad protocol option" }, + { WSAEPROTONOSUPPORT, "Protocol not supported" }, + { WSAESOCKTNOSUPPORT, "Socket type not supported" }, + { WSAEOPNOTSUPP, "Operation not supported on socket" }, + { WSAEPFNOSUPPORT, "Protocol family not supported" }, + { WSAEAFNOSUPPORT, "Address family not supported" }, + { WSAEADDRINUSE, "Address already in use" }, + { WSAEADDRNOTAVAIL, "Can't assign requested address" }, + { WSAENETDOWN, "Network is down" }, + { WSAENETUNREACH, "Network is unreachable" }, + { WSAENETRESET, "Net connection reset" }, + { WSAECONNABORTED, "Software caused connection abort" }, + { WSAECONNRESET, "Connection reset by peer" }, + { WSAENOBUFS, "No buffer space available" }, + { WSAEISCONN, "Socket is already connected" }, + { WSAENOTCONN, "Socket is not connected" }, + { WSAESHUTDOWN, "Can't send after socket shutdown" }, + { WSAETOOMANYREFS, "Too many references, can't splice" }, + { WSAETIMEDOUT, "Connection timed out" }, + { WSAECONNREFUSED, "Connection refused" }, + { WSAELOOP, "Too many levels of symbolic links" }, + { WSAENAMETOOLONG, "File name too long" }, + { WSAEHOSTDOWN, "Host is down" }, + { WSAEHOSTUNREACH, "No route to host" }, + { WSAENOTEMPTY, "Directory not empty" }, + { WSAEPROCLIM, "Too many processes" }, + { WSAEUSERS, "Too many users" }, + { WSAEDQUOT, "Disc quota exceeded" }, + { WSAESTALE, "Stale NFS file handle" }, + { WSAEREMOTE, "Too many levels of remote in path" }, + { WSASYSNOTREADY, "Network system is unavailable" }, + { WSAVERNOTSUPPORTED, "Winsock version out of range" }, + { WSANOTINITIALISED, "WSAStartup not yet called" }, + { WSAEDISCON, "Graceful shutdown in progress" }, + { WSAHOST_NOT_FOUND, "Host not found" }, + { WSANO_DATA, "No host data of that type was found" }, + { -1, "Unknown error code" } +}; +#endif + +#define COMSTR "," +#define SEPSTR "|" + +#define CMDJOIN '+' +#define JOIN_CMD "CMD=" +#define BETWEEN_JOIN SEPSTR +#define _DYNAMIC "D" + +#define _DEVS "DEVS" +#define _POOLS "POOLS" +#define _SUMMARY "SUMMARY" +#define _STATUS "STATUS" +#define _VERSION "VERSION" +#define _MINECONFIG "CONFIG" +#define _GPU "GPU" + +#define _GPUS "GPUS" +#define _NOTIFY "NOTIFY" +#define _DEVDETAILS "DEVDETAILS" +#define _BYE "BYE" +#define _RESTART "RESTART" +#define _MINESTATS "STATS" +#define _CHECK "CHECK" +#define _MINECOIN "COIN" +#define _DEBUGSET "DEBUG" +#define _SETCONFIG "SETCONFIG" + +#define JSON0 "{" +#define JSON1 "\"" +#define JSON2 "\":[" +#define JSON3 "]" +#define JSON4 ",\"id\":1" +// If anyone cares, id=0 for truncated output +#define JSON4_TRUNCATED ",\"id\":0" +#define JSON5 "}" + +#define JSON_START JSON0 +#define JSON_DEVS JSON1 _DEVS JSON2 +#define JSON_POOLS JSON1 _POOLS JSON2 +#define JSON_SUMMARY JSON1 _SUMMARY JSON2 +#define JSON_STATUS JSON1 _STATUS JSON2 +#define JSON_VERSION JSON1 _VERSION JSON2 +#define JSON_MINECONFIG JSON1 _MINECONFIG JSON2 +#define JSON_GPU JSON1 _GPU JSON2 + +#define JSON_GPUS JSON1 _GPUS JSON2 +#define JSON_NOTIFY JSON1 _NOTIFY JSON2 +#define JSON_DEVDETAILS JSON1 _DEVDETAILS JSON2 +#define JSON_CLOSE JSON3 +#define JSON_MINESTATS JSON1 _MINESTATS JSON2 +#define JSON_CHECK JSON1 _CHECK JSON2 +#define JSON_MINECOIN JSON1 _MINECOIN JSON2 +#define JSON_DEBUGSET JSON1 _DEBUGSET JSON2 +#define JSON_SETCONFIG JSON1 _SETCONFIG JSON2 + +#define JSON_END JSON4 JSON5 +#define JSON_END_TRUNCATED JSON4_TRUNCATED JSON5 +#define JSON_BETWEEN_JOIN "," + +#define MSG_INVGPU 1 +#define MSG_ALRENA 2 +#define MSG_ALRDIS 3 +#define MSG_GPUMRE 4 +#define MSG_GPUREN 5 +#define MSG_GPUNON 6 +#define MSG_POOL 7 +#define MSG_NOPOOL 8 +#define MSG_DEVS 9 +#define MSG_NODEVS 10 +#define MSG_SUMM 11 +#define MSG_GPUDIS 12 +#define MSG_GPUREI 13 +#define MSG_INVCMD 14 +#define MSG_MISID 15 +#define MSG_GPUDEV 17 + +#define MSG_NUMGPU 20 + +#define MSG_VERSION 22 +#define MSG_INVJSON 23 +#define MSG_MISCMD 24 +#define MSG_MISPID 25 +#define MSG_INVPID 26 +#define MSG_SWITCHP 27 +#define MSG_MISVAL 28 +#define MSG_NOADL 29 +#define MSG_NOGPUADL 30 +#define MSG_INVINT 31 +#define MSG_GPUINT 32 +#define MSG_MINECONFIG 33 +#define MSG_GPUMERR 34 +#define MSG_GPUMEM 35 +#define MSG_GPUEERR 36 +#define MSG_GPUENG 37 +#define MSG_GPUVERR 38 +#define MSG_GPUVDDC 39 +#define MSG_GPUFERR 40 +#define MSG_GPUFAN 41 +#define MSG_MISFN 42 +#define MSG_BADFN 43 +#define MSG_SAVED 44 +#define MSG_ACCDENY 45 +#define MSG_ACCOK 46 +#define MSG_ENAPOOL 47 +#define MSG_DISPOOL 48 +#define MSG_ALRENAP 49 +#define MSG_ALRDISP 50 +#define MSG_MISPDP 52 +#define MSG_INVPDP 53 +#define MSG_TOOMANYP 54 +#define MSG_ADDPOOL 55 + +#define MSG_NOTIFY 60 + +#define MSG_REMLASTP 66 +#define MSG_ACTPOOL 67 +#define MSG_REMPOOL 68 +#define MSG_DEVDETAILS 69 +#define MSG_MINESTATS 70 +#define MSG_MISCHK 71 +#define MSG_CHECK 72 +#define MSG_POOLPRIO 73 +#define MSG_DUPPID 74 +#define MSG_MISBOOL 75 +#define MSG_INVBOOL 76 +#define MSG_FOO 77 +#define MSG_MINECOIN 78 +#define MSG_DEBUGSET 79 +#define MSG_SETCONFIG 82 +#define MSG_UNKCON 83 +#define MSG_INVNUM 84 +#define MSG_CONPAR 85 +#define MSG_CONVAL 86 + +#define MSG_NOUSTA 88 + +#define MSG_ZERMIS 94 +#define MSG_ZERINV 95 +#define MSG_ZERSUM 96 +#define MSG_ZERNOSUM 97 + +#define MSG_BYE 0x101 + +#define MSG_INVNEG 121 +#define MSG_SETQUOTA 122 +#define MSG_LOCKOK 123 +#define MSG_LOCKDIS 124 + +#define MSG_CHSTRAT 125 +#define MSG_MISSTRAT 126 +#define MSG_INVSTRAT 127 +#define MSG_MISSTRATINT 128 + +enum code_severity { + SEVERITY_ERR, + SEVERITY_WARN, + SEVERITY_INFO, + SEVERITY_SUCC, + SEVERITY_FAIL +}; + +enum code_parameters { + PARAM_GPU, + PARAM_PID, + PARAM_GPUMAX, + PARAM_PMAX, + PARAM_POOLMAX, + +// Single generic case: have the code resolve it - see below + PARAM_DMAX, + + PARAM_CMD, + PARAM_POOL, + PARAM_STR, + PARAM_BOTH, + PARAM_BOOL, + PARAM_SET, + PARAM_INT, + PARAM_NONE +}; + +struct CODES { + const enum code_severity severity; + const int code; + const enum code_parameters params; + const char *description; +} codes[] = { + { SEVERITY_ERR, MSG_INVGPU, PARAM_GPUMAX, "Invalid GPU id %d - range is 0 - %d" }, + { SEVERITY_INFO, MSG_ALRENA, PARAM_GPU, "GPU %d already enabled" }, + { SEVERITY_INFO, MSG_ALRDIS, PARAM_GPU, "GPU %d already disabled" }, + { SEVERITY_WARN, MSG_GPUMRE, PARAM_GPU, "GPU %d must be restarted first" }, + { SEVERITY_INFO, MSG_GPUREN, PARAM_GPU, "GPU %d sent enable message" }, + { SEVERITY_ERR, MSG_GPUNON, PARAM_NONE, "No GPUs" }, + { SEVERITY_SUCC, MSG_POOL, PARAM_PMAX, "%d Pool(s)" }, + { SEVERITY_ERR, MSG_NOPOOL, PARAM_NONE, "No pools" }, + + { SEVERITY_SUCC, MSG_DEVS, PARAM_DMAX, "%d GPU(s)" }, + { SEVERITY_ERR, MSG_NODEVS, PARAM_NONE, "No GPUs" + }, + + { SEVERITY_SUCC, MSG_SUMM, PARAM_NONE, "Summary" }, + { SEVERITY_INFO, MSG_GPUDIS, PARAM_GPU, "GPU %d set disable flag" }, + { SEVERITY_INFO, MSG_GPUREI, PARAM_GPU, "GPU %d restart attempted" }, + { SEVERITY_ERR, MSG_INVCMD, PARAM_NONE, "Invalid command" }, + { SEVERITY_ERR, MSG_MISID, PARAM_NONE, "Missing device id parameter" }, + { SEVERITY_SUCC, MSG_GPUDEV, PARAM_GPU, "GPU%d" }, + { SEVERITY_SUCC, MSG_NUMGPU, PARAM_NONE, "GPU count" }, + { SEVERITY_SUCC, MSG_VERSION, PARAM_NONE, "SGMiner versions" }, + { SEVERITY_ERR, MSG_INVJSON, PARAM_NONE, "Invalid JSON" }, + { SEVERITY_ERR, MSG_MISCMD, PARAM_CMD, "Missing JSON '%s'" }, + { SEVERITY_ERR, MSG_MISPID, PARAM_NONE, "Missing pool id parameter" }, + { SEVERITY_ERR, MSG_INVPID, PARAM_POOLMAX, "Invalid pool id %d - range is 0 - %d" }, + { SEVERITY_SUCC, MSG_SWITCHP, PARAM_POOL, "Switching to pool %d:'%s'" }, + { SEVERITY_ERR, MSG_MISVAL, PARAM_NONE, "Missing comma after GPU number" }, + { SEVERITY_ERR, MSG_NOADL, PARAM_NONE, "ADL is not available" }, + { SEVERITY_ERR, MSG_NOGPUADL,PARAM_GPU, "GPU %d does not have ADL" }, + { SEVERITY_ERR, MSG_INVINT, PARAM_STR, "Invalid intensity (%s) - must be '" _DYNAMIC "' or range " MIN_INTENSITY_STR " - " MAX_INTENSITY_STR }, + { SEVERITY_INFO, MSG_GPUINT, PARAM_BOTH, "GPU %d set new intensity to %s" }, + { SEVERITY_SUCC, MSG_MINECONFIG,PARAM_NONE, "sgminer config" }, + { SEVERITY_ERR, MSG_GPUMERR, PARAM_BOTH, "Setting GPU %d memoryclock to (%s) reported failure" }, + { SEVERITY_SUCC, MSG_GPUMEM, PARAM_BOTH, "Setting GPU %d memoryclock to (%s) reported success" }, + { SEVERITY_ERR, MSG_GPUEERR, PARAM_BOTH, "Setting GPU %d clock to (%s) reported failure" }, + { SEVERITY_SUCC, MSG_GPUENG, PARAM_BOTH, "Setting GPU %d clock to (%s) reported success" }, + { SEVERITY_ERR, MSG_GPUVERR, PARAM_BOTH, "Setting GPU %d vddc to (%s) reported failure" }, + { SEVERITY_SUCC, MSG_GPUVDDC, PARAM_BOTH, "Setting GPU %d vddc to (%s) reported success" }, + { SEVERITY_ERR, MSG_GPUFERR, PARAM_BOTH, "Setting GPU %d fan to (%s) reported failure" }, + { SEVERITY_SUCC, MSG_GPUFAN, PARAM_BOTH, "Setting GPU %d fan to (%s) reported success" }, + { SEVERITY_ERR, MSG_MISFN, PARAM_NONE, "Missing save filename parameter" }, + { SEVERITY_ERR, MSG_BADFN, PARAM_STR, "Can't open or create save file '%s'" }, + { SEVERITY_SUCC, MSG_SAVED, PARAM_STR, "Configuration saved to file '%s'" }, + { SEVERITY_ERR, MSG_ACCDENY, PARAM_STR, "Access denied to '%s' command" }, + { SEVERITY_SUCC, MSG_ACCOK, PARAM_NONE, "Privileged access OK" }, + { SEVERITY_SUCC, MSG_ENAPOOL, PARAM_POOL, "Enabling pool %d:'%s'" }, + { SEVERITY_SUCC, MSG_POOLPRIO,PARAM_NONE, "Changed pool priorities" }, + { SEVERITY_ERR, MSG_DUPPID, PARAM_PID, "Duplicate pool specified %d" }, + { SEVERITY_SUCC, MSG_DISPOOL, PARAM_POOL, "Disabling pool %d:'%s'" }, + { SEVERITY_INFO, MSG_ALRENAP, PARAM_POOL, "Pool %d:'%s' already enabled" }, + { SEVERITY_INFO, MSG_ALRDISP, PARAM_POOL, "Pool %d:'%s' already disabled" }, + { SEVERITY_ERR, MSG_MISPDP, PARAM_NONE, "Missing addpool details" }, + { SEVERITY_ERR, MSG_INVPDP, PARAM_STR, "Invalid addpool details '%s'" }, + { SEVERITY_ERR, MSG_TOOMANYP,PARAM_NONE, "Reached maximum number of pools (%d)" }, + { SEVERITY_SUCC, MSG_ADDPOOL, PARAM_STR, "Added pool '%s'" }, + { SEVERITY_ERR, MSG_REMLASTP,PARAM_POOL, "Cannot remove last pool %d:'%s'" }, + { SEVERITY_ERR, MSG_ACTPOOL, PARAM_POOL, "Cannot remove active pool %d:'%s'" }, + { SEVERITY_SUCC, MSG_REMPOOL, PARAM_BOTH, "Removed pool %d:'%s'" }, + { SEVERITY_SUCC, MSG_NOTIFY, PARAM_NONE, "Notify" }, + { SEVERITY_SUCC, MSG_DEVDETAILS,PARAM_NONE, "Device Details" }, + { SEVERITY_SUCC, MSG_MINESTATS,PARAM_NONE, "sgminer stats" }, + { SEVERITY_ERR, MSG_MISCHK, PARAM_NONE, "Missing check cmd" }, + { SEVERITY_SUCC, MSG_CHECK, PARAM_NONE, "Check command" }, + { SEVERITY_ERR, MSG_MISBOOL, PARAM_NONE, "Missing parameter: true/false" }, + { SEVERITY_ERR, MSG_INVBOOL, PARAM_NONE, "Invalid parameter should be true or false" }, + { SEVERITY_SUCC, MSG_FOO, PARAM_BOOL, "Failover-Only set to %s" }, + { SEVERITY_SUCC, MSG_MINECOIN,PARAM_NONE, "sgminer coin" }, + { SEVERITY_SUCC, MSG_DEBUGSET,PARAM_NONE, "Debug settings" }, + { SEVERITY_SUCC, MSG_SETCONFIG,PARAM_SET, "Set config '%s' to %d" }, + { SEVERITY_ERR, MSG_UNKCON, PARAM_STR, "Unknown config '%s'" }, + { SEVERITY_ERR, MSG_INVNUM, PARAM_BOTH, "Invalid number (%d) for '%s' range is 0-9999" }, + { SEVERITY_ERR, MSG_INVNEG, PARAM_BOTH, "Invalid negative number (%d) for '%s'" }, + { SEVERITY_SUCC, MSG_SETQUOTA,PARAM_SET, "Set pool '%s' to quota %d'" }, + { SEVERITY_ERR, MSG_CONPAR, PARAM_NONE, "Missing config parameters 'name,N'" }, + { SEVERITY_ERR, MSG_CONVAL, PARAM_STR, "Missing config value N for '%s,N'" }, + { SEVERITY_INFO, MSG_NOUSTA, PARAM_NONE, "No USB Statistics" }, + { SEVERITY_ERR, MSG_ZERMIS, PARAM_NONE, "Missing zero parameters" }, + { SEVERITY_ERR, MSG_ZERINV, PARAM_STR, "Invalid zero parameter '%s'" }, + { SEVERITY_SUCC, MSG_ZERSUM, PARAM_STR, "Zeroed %s stats with summary" }, + { SEVERITY_SUCC, MSG_ZERNOSUM, PARAM_STR, "Zeroed %s stats without summary" }, + { SEVERITY_SUCC, MSG_LOCKOK, PARAM_NONE, "Lock stats created" }, + { SEVERITY_WARN, MSG_LOCKDIS, PARAM_NONE, "Lock stats not enabled" }, + { SEVERITY_SUCC, MSG_CHSTRAT, PARAM_STR, "Multipool strategy changed to '%s'" }, + { SEVERITY_ERR, MSG_MISSTRAT, PARAM_NONE, "Missing multipool strategy" }, + { SEVERITY_ERR, MSG_INVSTRAT, PARAM_NONE, "Invalid multipool strategy %d" }, + { SEVERITY_ERR, MSG_MISSTRATINT, PARAM_NONE, "Missing rotate interval" }, + { SEVERITY_SUCC, MSG_BYE, PARAM_STR, "%s" }, + { SEVERITY_FAIL, 0, (enum code_parameters)0, NULL } +}; + +struct IP4ACCESS { + in_addr_t ip; + in_addr_t mask; + char group; +}; + +#define GROUP(g) (toupper(g)) +#define PRIVGROUP GROUP('W') +#define NOPRIVGROUP GROUP('R') +#define ISPRIVGROUP(g) (GROUP(g) == PRIVGROUP) +#define GROUPOFFSET(g) (GROUP(g) - GROUP('A')) +#define VALIDGROUP(g) (GROUP(g) >= GROUP('A') && GROUP(g) <= GROUP('Z')) +#define COMMANDS(g) (apigroups[GROUPOFFSET(g)].commands) +#define DEFINEDGROUP(g) (ISPRIVGROUP(g) || COMMANDS(g) != NULL) + +struct APIGROUPS { + // This becomes a string like: "|cmd1|cmd2|cmd3|" so it's quick to search + char *commands; +} apigroups['Z' - 'A' + 1]; // only A=0 to Z=25 (R: noprivs, W: allprivs) + +struct io_data { + size_t siz; + char *ptr; + char *cur; + bool sock; + bool close; +}; + +struct io_list { + struct io_data *io_data; + struct io_list *prev; + struct io_list *next; +}; + +extern void message(struct io_data *io_data, int messageid, int paramid, char *param2, bool isjson); + +#define SOCKBUFALLOCSIZ 65536 + +#define io_new(init) _io_new(init, false) +#define sock_io_new() _io_new(SOCKBUFALLOCSIZ, true) + +#if LOCK_TRACKING + + #define LOCK_FMT_FFL " - called from %s %s():%d" + #define LOCKMSG(fmt, ...) fprintf(stderr, "APILOCK: " fmt "\n", ##__VA_ARGS__) + #define LOCKMSGMORE(fmt, ...) fprintf(stderr, " " fmt "\n", ##__VA_ARGS__) + #define LOCKMSGFFL(fmt, ...) fprintf(stderr, "APILOCK: " fmt LOCK_FMT_FFL "\n", ##__VA_ARGS__, file, func, linenum) + #define LOCKMSGFLUSH() fflush(stderr) + + typedef struct lockstat { + uint64_t lock_id; + const char *file; + const char *func; + int linenum; + struct timeval tv; + } LOCKSTAT; + + typedef struct lockline { + struct lockline *prev; + struct lockstat *stat; + struct lockline *next; + } LOCKLINE; + + typedef struct lockinfo { + void *lock; + enum cglock_typ typ; + const char *file; + const char *func; + int linenum; + uint64_t gets; + uint64_t gots; + uint64_t tries; + uint64_t dids; + uint64_t didnts; // should be tries - dids + uint64_t unlocks; + LOCKSTAT lastgot; + LOCKLINE *lockgets; + LOCKLINE *locktries; + } LOCKINFO; + + typedef struct locklist { + LOCKINFO *info; + struct locklist *next; + } LOCKLIST; +#endif + +#endif /* API_H */ \ No newline at end of file diff --git a/config_parser.c b/config_parser.c index 5065ae7f..9d26b538 100644 --- a/config_parser.c +++ b/config_parser.c @@ -7,7 +7,7 @@ * 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. + * any later version. See COPYING for more details. */ #include "config.h" @@ -47,20 +47,20 @@ #endif #if defined(unix) || defined(__APPLE__) - #include - #include - #include + #include + #include + #include #endif -char *cnfbuf = NULL; //config file loaded -int fileconf_load; //config file load status +char *cnfbuf = NULL; //config file loaded +int fileconf_load; //config file load status const char def_conf[] = "sgminer.conf"; char *default_config; bool config_loaded; //static int include_count; -int json_array_index = -1; //current array index being parsed -char *last_json_error = NULL; //last json_error +int json_array_index = -1; //current array index being parsed +char *last_json_error = NULL; //last json_error /*#define JSON_MAX_DEPTH 10 #define JSON_MAX_DEPTH_ERR "Too many levels of JSON includes (limit 10) or a loop"*/ @@ -73,279 +73,279 @@ int total_profiles; static struct profile *add_profile() { - struct profile *profile; - char buf[32]; + struct profile *profile; + char buf[32]; - if(!(profile = (struct profile *)calloc(sizeof(struct profile), 1))) - quit(1, "Failed to calloc profile in add_profile"); - profile->profile_no = total_profiles; + if(!(profile = (struct profile *)calloc(sizeof(struct profile), 1))) + quit(1, "Failed to calloc profile in add_profile"); + profile->profile_no = total_profiles; - //default profile name is the profile index - sprintf(buf, "%d", profile->profile_no); - profile->name = strdup(buf); + //default profile name is the profile index + sprintf(buf, "%d", profile->profile_no); + profile->name = strdup(buf); - profiles = (struct profile **)realloc(profiles, sizeof(struct profile *) * (total_profiles + 2)); - profiles[total_profiles++] = profile; + profiles = (struct profile **)realloc(profiles, sizeof(struct profile *) * (total_profiles + 2)); + profiles[total_profiles++] = profile; - return profile; + return profile; } //only used while loading config static struct profile *get_current_profile() { - while ((json_array_index + 1) > total_profiles) - add_profile(); + while ((json_array_index + 1) > total_profiles) + add_profile(); - if (json_array_index < 0) - { - if (!total_profiles) - add_profile(); - return profiles[total_profiles - 1]; - } + if (json_array_index < 0) + { + if (!total_profiles) + add_profile(); + return profiles[total_profiles - 1]; + } - return profiles[json_array_index]; + return profiles[json_array_index]; } //find a profile by name static struct profile *get_profile(char *name) { - int i; + int i; - for(i=total_profiles;i--;) - { - if(!strcasecmp(profiles[i]->name, name)) - return profiles[i]; - } + for(i=total_profiles;i--;) + { + if(!strcasecmp(profiles[i]->name, name)) + return profiles[i]; + } - return NULL; + return NULL; } /******* Default profile functions used during config parsing *****/ char *set_default_devices(const char *arg) { - default_profile.devices = arg; - return NULL; + default_profile.devices = arg; + return NULL; } char *set_default_lookup_gap(const char *arg) { - default_profile.lookup_gap = arg; - return NULL; + default_profile.lookup_gap = arg; + return NULL; } char *set_default_intensity(const char *arg) { - default_profile.intensity = arg; - return NULL; + default_profile.intensity = arg; + return NULL; } char *set_default_xintensity(const char *arg) { - default_profile.xintensity = arg; - return NULL; + default_profile.xintensity = arg; + return NULL; } char *set_default_rawintensity(const char *arg) { - default_profile.rawintensity = arg; - return NULL; + default_profile.rawintensity = arg; + return NULL; } char *set_default_thread_concurrency(const char *arg) { - default_profile.thread_concurrency = arg; - return NULL; + default_profile.thread_concurrency = arg; + return NULL; } #ifdef HAVE_ADL - char *set_default_gpu_engine(const char *arg) - { - default_profile.gpu_engine = arg; - return NULL; - } + char *set_default_gpu_engine(const char *arg) + { + default_profile.gpu_engine = arg; + return NULL; + } - char *set_default_gpu_memclock(const char *arg) - { - default_profile.gpu_memclock = arg; - return NULL; - } + char *set_default_gpu_memclock(const char *arg) + { + default_profile.gpu_memclock = arg; + return NULL; + } - char *set_default_gpu_threads(const char *arg) - { - default_profile.gpu_threads = arg; - return NULL; - } + char *set_default_gpu_threads(const char *arg) + { + default_profile.gpu_threads = arg; + return NULL; + } - char *set_default_gpu_fan(const char *arg) - { - default_profile.gpu_fan = arg; - return NULL; - } + char *set_default_gpu_fan(const char *arg) + { + default_profile.gpu_fan = arg; + return NULL; + } - char *set_default_gpu_powertune(const char *arg) - { - default_profile.gpu_powertune = arg; - return NULL; - } + char *set_default_gpu_powertune(const char *arg) + { + default_profile.gpu_powertune = arg; + return NULL; + } - char *set_default_gpu_vddc(const char *arg) - { - default_profile.gpu_vddc = arg; - return NULL; - } + char *set_default_gpu_vddc(const char *arg) + { + default_profile.gpu_vddc = arg; + return NULL; + } #endif char *set_default_profile(char *arg) { - default_profile.name = arg; - return NULL; + default_profile.name = arg; + return NULL; } char *set_default_shaders(const char *arg) { - default_profile.shaders = arg; - return NULL; + default_profile.shaders = arg; + return NULL; } char *set_default_worksize(const char *arg) { - default_profile.worksize = arg; - return NULL; + default_profile.worksize = arg; + return NULL; } /****** Profile functions used in during config parsing ********/ char *set_profile_name(const char *arg) { - struct profile *profile = get_current_profile(); + struct profile *profile = get_current_profile(); - applog(LOG_DEBUG, "Setting profile %i name to %s", profile->profile_no, arg); - opt_set_charp(arg, &profile->name); + applog(LOG_DEBUG, "Setting profile %i name to %s", profile->profile_no, arg); + opt_set_charp(arg, &profile->name); - return NULL; + return NULL; } char *set_profile_algorithm(const char *arg) { - struct profile *profile = get_current_profile(); + struct profile *profile = get_current_profile(); - //applog(LOG_DEBUG, "Setting profile %s algorithm to %s", profile->name, arg); - set_algorithm(&profile->algorithm, arg); + //applog(LOG_DEBUG, "Setting profile %s algorithm to %s", profile->name, arg); + set_algorithm(&profile->algorithm, arg); - return NULL; + return NULL; } char *set_profile_devices(const char *arg) { - struct profile *profile = get_current_profile(); - profile->devices = arg; - return NULL; + struct profile *profile = get_current_profile(); + profile->devices = arg; + return NULL; } char *set_profile_lookup_gap(const char *arg) { - struct profile *profile = get_current_profile(); - profile->lookup_gap = arg; - return NULL; + struct profile *profile = get_current_profile(); + profile->lookup_gap = arg; + return NULL; } char *set_profile_intensity(const char *arg) { - struct profile *profile = get_current_profile(); - profile->intensity = arg; - return NULL; + struct profile *profile = get_current_profile(); + profile->intensity = arg; + return NULL; } char *set_profile_xintensity(const char *arg) { - struct profile *profile = get_current_profile(); - profile->xintensity = arg; - return NULL; + struct profile *profile = get_current_profile(); + profile->xintensity = arg; + return NULL; } char *set_profile_rawintensity(const char *arg) { - struct profile *profile = get_current_profile(); - profile->rawintensity = arg; - return NULL; + struct profile *profile = get_current_profile(); + profile->rawintensity = arg; + return NULL; } char *set_profile_thread_concurrency(const char *arg) { - struct profile *profile = get_current_profile(); - profile->thread_concurrency = arg; - return NULL; + struct profile *profile = get_current_profile(); + profile->thread_concurrency = arg; + return NULL; } #ifdef HAVE_ADL - char *set_profile_gpu_engine(const char *arg) - { - struct profile *profile = get_current_profile(); - profile->gpu_engine = arg; - return NULL; - } + char *set_profile_gpu_engine(const char *arg) + { + struct profile *profile = get_current_profile(); + profile->gpu_engine = arg; + return NULL; + } - char *set_profile_gpu_memclock(const char *arg) - { - struct profile *profile = get_current_profile(); - profile->gpu_memclock = arg; - return NULL; - } + char *set_profile_gpu_memclock(const char *arg) + { + struct profile *profile = get_current_profile(); + profile->gpu_memclock = arg; + return NULL; + } - char *set_profile_gpu_threads(const char *arg) - { - struct profile *profile = get_current_profile(); - profile->gpu_threads = arg; - return NULL; - } + char *set_profile_gpu_threads(const char *arg) + { + struct profile *profile = get_current_profile(); + profile->gpu_threads = arg; + return NULL; + } - char *set_profile_gpu_fan(const char *arg) - { - struct profile *profile = get_current_profile(); - profile->gpu_fan = arg; - return NULL; - } + char *set_profile_gpu_fan(const char *arg) + { + struct profile *profile = get_current_profile(); + profile->gpu_fan = arg; + return NULL; + } - char *set_profile_gpu_powertune(const char *arg) - { - struct profile *profile = get_current_profile(); - profile->gpu_powertune = arg; - return NULL; - } + char *set_profile_gpu_powertune(const char *arg) + { + struct profile *profile = get_current_profile(); + profile->gpu_powertune = arg; + return NULL; + } - char *set_profile_gpu_vddc(const char *arg) - { - struct profile *profile = get_current_profile(); - profile->gpu_vddc = arg; - return NULL; - } + char *set_profile_gpu_vddc(const char *arg) + { + struct profile *profile = get_current_profile(); + profile->gpu_vddc = arg; + return NULL; + } #endif char *set_profile_nfactor(const char *arg) { - struct profile *profile = get_current_profile(); + struct profile *profile = get_current_profile(); - applog(LOG_DEBUG, "Setting profile %s N-factor to %s", profile->name, arg); - set_algorithm_nfactor(&profile->algorithm, (const uint8_t) atoi(arg)); + applog(LOG_DEBUG, "Setting profile %s N-factor to %s", profile->name, arg); + set_algorithm_nfactor(&profile->algorithm, (const uint8_t) atoi(arg)); - return NULL; + return NULL; } char *set_profile_shaders(const char *arg) { - struct profile *profile = get_current_profile(); - profile->shaders = arg; - return NULL; + struct profile *profile = get_current_profile(); + profile->shaders = arg; + return NULL; } char *set_profile_worksize(const char *arg) { - struct profile *profile = get_current_profile(); - profile->worksize = arg; - return NULL; + struct profile *profile = get_current_profile(); + profile->worksize = arg; + return NULL; } /*************************************** @@ -353,99 +353,99 @@ char *set_profile_worksize(const char *arg) ****************************************/ 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()."); + 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); + //zero out buffer + memset(buf, '\0', bufsize); - //get args again - va_start(args, fmt); - vsnprintf(buf, bufsize, fmt, args); - va_end(args); + //get args again + va_start(args, fmt); + vsnprintf(buf, bufsize, fmt, args); + va_end(args); - //return json string - return json_string(buf); + //return json string + return json_string(buf); } //set last json error char *set_last_json_error(const char *fmt, ...) { - va_list args; - size_t bufsize; - - //build args - va_start(args, fmt); - //get final string buffer size - 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))) - quit(1, "Malloc failure in config_parser::set_last_json_error()."); - } - else - { - 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); - - //get args again - va_start(args, fmt); - vsnprintf(last_json_error, bufsize, fmt, args); - va_end(args); - - return last_json_error; + va_list args; + size_t bufsize; + + //build args + va_start(args, fmt); + //get final string buffer size + 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))) + quit(1, "Malloc failure in config_parser::set_last_json_error()."); + } + else + { + 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); + + //get args again + va_start(args, fmt); + vsnprintf(last_json_error, bufsize, fmt, args); + va_end(args); + + return last_json_error; } //find opt by name in an opt table static struct opt_table *opt_find(struct opt_table *tbl, char *optname) { - struct opt_table *opt; - char *p, *name; + struct opt_table *opt; + char *p, *name; - for(opt = tbl;opt->type != OPT_END;opt++) - { - /* We don't handle subtables. */ - assert(!(opt->type & OPT_SUBTABLE)); + for(opt = tbl;opt->type != OPT_END;opt++) + { + /* We don't handle subtables. */ + assert(!(opt->type & OPT_SUBTABLE)); - if(!opt->names) - continue; + if(!opt->names) + continue; - /* Pull apart the option name(s). */ - name = strdup(opt->names); - for(p = strtok(name, "|");p;p = strtok(NULL, "|")) - { - /* Ignore short options. */ - if(p[1] != '-') - continue; - - //if this is the opt we're looking for, return it... - if(!strcasecmp(optname, p)) - { - free(name); - return opt; - } - } + /* Pull apart the option name(s). */ + name = strdup(opt->names); + for(p = strtok(name, "|");p;p = strtok(NULL, "|")) + { + /* Ignore short options. */ + if(p[1] != '-') + continue; + + //if this is the opt we're looking for, return it... + if(!strcasecmp(optname, p)) + { free(name); + return opt; + } } + free(name); + } - return NULL; + return NULL; } @@ -455,173 +455,173 @@ static struct opt_table *opt_find(struct opt_table *tbl, char *optname) //Handle parsing JSON objects void parse_config_object(json_t *obj, const char *parentkey, bool fileconf, int parent_iteration) { - //char *err = NULL; - const char *key; - json_t *val; - - json_object_foreach(obj, key, val) + //char *err = NULL; + const char *key; + json_t *val; + + json_object_foreach(obj, key, val) + { + //process include + if(!strcasecmp(key, "include")) { - //process include - if(!strcasecmp(key, "include")) - { - if(val && json_is_string(val)) - load_config(json_string_value(val), parentkey, NULL); - } - else - parse_config(val, key, parentkey, fileconf, parent_iteration); - /* - { - if((err = parse_config(val, key, parentkey, fileconf, parent_iteration))) - return err; - }*/ + if(val && json_is_string(val)) + load_config(json_string_value(val), parentkey, NULL); } + else + parse_config(val, key, parentkey, fileconf, parent_iteration); + /* + { + if((err = parse_config(val, key, parentkey, fileconf, parent_iteration))) + return err; + }*/ + } } //Handle parsing JSON arrays static char *parse_config_array(json_t *obj, char *parentkey, bool fileconf) { - char *err = NULL; - size_t idx; - json_t *val; - - //fix parent key - remove extra "s" to match opt names (e.g. --pool-gpu-memclock not --pools-gpu-memclock) - if(!strcasecmp(parentkey, "pools") || !strcasecmp(parentkey, "profiles")) - parentkey[(strlen(parentkey) - 1)] = '\0'; - - json_array_foreach(obj, idx, val) - { - //abort on error - if((err = parse_config(val, "", parentkey, fileconf, idx))) - return err; - } - - return NULL; + char *err = NULL; + size_t idx; + json_t *val; + + //fix parent key - remove extra "s" to match opt names (e.g. --pool-gpu-memclock not --pools-gpu-memclock) + if(!strcasecmp(parentkey, "pools") || !strcasecmp(parentkey, "profiles")) + parentkey[(strlen(parentkey) - 1)] = '\0'; + + json_array_foreach(obj, idx, val) + { + //abort on error + if((err = parse_config(val, "", parentkey, fileconf, idx))) + return err; + } + + return NULL; } //Parse JSON values from config file char *parse_config(json_t *val, const char *key, const char *parentkey, bool fileconf, int parent_iteration) { - static char err_buf[200]; - char *err = NULL; - struct opt_table *opt; - char optname[255]; - /*const char *key - json_t *val;*/ - - json_array_index = parent_iteration; - - if (fileconf && !fileconf_load) - fileconf_load = 1; - - /* - parse the json config items into opts instead of looking for opts in the json config... - This adds greater flexibility with config files. - */ - switch(json_typeof(val)) - { - //json value is an object - case JSON_OBJECT: - parse_config_object(val, parentkey, false, parent_iteration); - break; - - //json value is an array - case JSON_ARRAY: - err = parse_config_array(val, (char *)key, fileconf); - break; - - //other json types process here - default: - //convert json key to opt name - sprintf(optname, "--%s%s%s", ((!empty_string(parentkey))?parentkey:""), ((!empty_string(parentkey))?"-":""), key); - - //look up opt name in config table - if((opt = opt_find(opt_config_table, optname)) != NULL) - { - //strings - if ((opt->type & OPT_HASARG) && json_is_string(val)) - err = opt->cb_arg(json_string_value(val), opt->u.arg); - //boolean values - else if ((opt->type & OPT_NOARG) && json_is_true(val)) - err = opt->cb(opt->u.arg); - else - err = "Invalid value"; - } - else - err = "Invalid option"; - - break; - } - - //error processing JSON... - 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", optname+2, err); - fileconf_load = -1; - } + static char err_buf[200]; + char *err = NULL; + struct opt_table *opt; + char optname[255]; + /*const char *key + json_t *val;*/ + + json_array_index = parent_iteration; + + if (fileconf && !fileconf_load) + fileconf_load = 1; + + /* + parse the json config items into opts instead of looking for opts in the json config... + This adds greater flexibility with config files. + */ + switch(json_typeof(val)) + { + //json value is an object + case JSON_OBJECT: + parse_config_object(val, parentkey, false, parent_iteration); + break; + + //json value is an array + case JSON_ARRAY: + err = parse_config_array(val, (char *)key, fileconf); + break; + + //other json types process here + default: + //convert json key to opt name + sprintf(optname, "--%s%s%s", ((!empty_string(parentkey))?parentkey:""), ((!empty_string(parentkey))?"-":""), key); + + //look up opt name in config table + if((opt = opt_find(opt_config_table, optname)) != NULL) + { + //strings + if ((opt->type & OPT_HASARG) && json_is_string(val)) + err = opt->cb_arg(json_string_value(val), opt->u.arg); + //boolean values + else if ((opt->type & OPT_NOARG) && json_is_true(val)) + err = opt->cb(opt->u.arg); else - { - snprintf(err_buf, sizeof(err_buf), "Error parsing JSON option %s: %s", optname+2, err); - return err_buf; - } + err = "Invalid value"; + } + else + err = "Invalid option"; + + break; + } + + //error processing JSON... + 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", optname+2, err); + fileconf_load = -1; + } + else + { + snprintf(err_buf, sizeof(err_buf), "Error parsing JSON option %s: %s", optname+2, err); + return err_buf; } + } - return NULL; + return NULL; } char *load_config(const char *arg, const char *parentkey, void __maybe_unused *unused) { - json_error_t err; - json_t *config; + json_error_t err; + json_t *config; - //most likely useless but leaving it here for now... - if(!cnfbuf) - cnfbuf = strdup(arg); + //most likely useless but leaving it here for now... + if(!cnfbuf) + cnfbuf = strdup(arg); - //no need to restrict the number of includes... if it causes problems, restore it later - /*if(++include_count > JSON_MAX_DEPTH) - return JSON_MAX_DEPTH_ERR; - */ + //no need to restrict the number of includes... if it causes problems, restore it later + /*if(++include_count > JSON_MAX_DEPTH) + return JSON_MAX_DEPTH_ERR; + */ #if JANSSON_MAJOR_VERSION > 1 - config = json_load_file(arg, 0, &err); + config = json_load_file(arg, 0, &err); #else - config = json_load_file(arg, &err); + config = json_load_file(arg, &err); #endif - //if json root is not an object, error out - if(!json_is_object(config)) - return set_last_json_error("Error: JSON decode of file \"%s\" failed:\n %s", arg, err.text); + //if json root is not an object, error out + if(!json_is_object(config)) + return set_last_json_error("Error: JSON decode of file \"%s\" failed:\n %s", arg, err.text); - config_loaded = true; + 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, "", parentkey, true, -1); + /* Parse the config now, so we can override it. That can keep pointers + * so don't free config object. */ + return parse_config(config, "", parentkey, true, -1); } char *set_default_config(const char *arg) { - opt_set_charp(arg, &default_config); - return NULL; + opt_set_charp(arg, &default_config); + return NULL; } void load_default_config(void) { - cnfbuf = (char *)malloc(PATH_MAX); + cnfbuf = (char *)malloc(PATH_MAX); - default_save_file(cnfbuf); + default_save_file(cnfbuf); - if (!access(cnfbuf, R_OK)) - load_config(cnfbuf, "", NULL); - else { - free(cnfbuf); - cnfbuf = NULL; - } + if (!access(cnfbuf, R_OK)) + load_config(cnfbuf, "", NULL); + else { + free(cnfbuf); + cnfbuf = NULL; + } } /******************************************* @@ -631,1293 +631,1303 @@ void load_default_config(void) //assign default settings from default profile if set void load_default_profile() { - struct profile *profile; + struct profile *profile; - //if a default profile name is set - if(!empty_string(default_profile.name)) + //if a default profile name is set + if(!empty_string(default_profile.name)) + { + //find profile and copy settings + if((profile = get_profile(default_profile.name))) { - //find profile and copy settings - if((profile = get_profile(default_profile.name))) - { - default_profile.algorithm = profile->algorithm; - default_profile.devices = profile->devices; - default_profile.lookup_gap = profile->lookup_gap; - default_profile.intensity = profile->intensity; - default_profile.xintensity = profile->xintensity; - default_profile.rawintensity = profile->rawintensity; - default_profile.thread_concurrency = profile->thread_concurrency; + default_profile.algorithm = profile->algorithm; + default_profile.devices = profile->devices; + default_profile.lookup_gap = profile->lookup_gap; + default_profile.intensity = profile->intensity; + default_profile.xintensity = profile->xintensity; + default_profile.rawintensity = profile->rawintensity; + default_profile.thread_concurrency = profile->thread_concurrency; #ifdef HAVE_ADL - default_profile.gpu_engine = profile->gpu_engine; - default_profile.gpu_memclock = profile->gpu_memclock; - default_profile.gpu_threads = profile->gpu_threads; - default_profile.gpu_fan = profile->gpu_fan; - default_profile.gpu_powertune = profile->gpu_powertune; - default_profile.gpu_vddc = profile->gpu_vddc; + default_profile.gpu_engine = profile->gpu_engine; + default_profile.gpu_memclock = profile->gpu_memclock; + default_profile.gpu_threads = profile->gpu_threads; + default_profile.gpu_fan = profile->gpu_fan; + default_profile.gpu_powertune = profile->gpu_powertune; + default_profile.gpu_vddc = profile->gpu_vddc; #endif - default_profile.shaders = profile->shaders; - default_profile.worksize = profile->worksize; - } + default_profile.shaders = profile->shaders; + default_profile.worksize = profile->worksize; } + } } //apply default settings void apply_defaults() { - set_algorithm(opt_algorithm, default_profile.algorithm.name); + set_algorithm(opt_algorithm, default_profile.algorithm.name); - if(!empty_string(default_profile.devices)) - set_devices((char *)default_profile.devices); + if(!empty_string(default_profile.devices)) + set_devices((char *)default_profile.devices); - if(!empty_string(default_profile.intensity)) - set_intensity(default_profile.intensity); + if(!empty_string(default_profile.intensity)) + set_intensity(default_profile.intensity); - if(!empty_string(default_profile.xintensity)) - set_xintensity(default_profile.xintensity); + if(!empty_string(default_profile.xintensity)) + set_xintensity(default_profile.xintensity); - if(!empty_string(default_profile.rawintensity)) - set_rawintensity(default_profile.rawintensity); + if(!empty_string(default_profile.rawintensity)) + set_rawintensity(default_profile.rawintensity); - if(!empty_string(default_profile.lookup_gap)) - set_lookup_gap((char *)default_profile.lookup_gap); + if(!empty_string(default_profile.lookup_gap)) + set_lookup_gap((char *)default_profile.lookup_gap); - if(!empty_string(default_profile.thread_concurrency)) - set_thread_concurrency(default_profile.thread_concurrency); + if(!empty_string(default_profile.thread_concurrency)) + set_thread_concurrency(default_profile.thread_concurrency); #ifdef HAVE_ADL - if(!empty_string(default_profile.gpu_engine)) - set_gpu_engine(default_profile.gpu_engine); + if(!empty_string(default_profile.gpu_engine)) + set_gpu_engine(default_profile.gpu_engine); - if(!empty_string(default_profile.gpu_memclock)) - set_gpu_memclock(default_profile.gpu_memclock); + if(!empty_string(default_profile.gpu_memclock)) + set_gpu_memclock(default_profile.gpu_memclock); - if(!empty_string(default_profile.gpu_threads)) - set_gpu_threads(default_profile.gpu_threads); + if(!empty_string(default_profile.gpu_threads)) + set_gpu_threads(default_profile.gpu_threads); - if(!empty_string(default_profile.gpu_fan)) - set_gpu_fan(default_profile.gpu_fan); + if(!empty_string(default_profile.gpu_fan)) + set_gpu_fan(default_profile.gpu_fan); - if(!empty_string(default_profile.gpu_powertune)) - set_gpu_powertune((char *)default_profile.gpu_powertune); + if(!empty_string(default_profile.gpu_powertune)) + set_gpu_powertune((char *)default_profile.gpu_powertune); - if(!empty_string(default_profile.gpu_vddc)) - set_gpu_vddc((char *)default_profile.gpu_vddc); + if(!empty_string(default_profile.gpu_vddc)) + set_gpu_vddc((char *)default_profile.gpu_vddc); #endif - if(!empty_string(default_profile.shaders)) - set_shaders((char *)default_profile.shaders); + if(!empty_string(default_profile.shaders)) + set_shaders((char *)default_profile.shaders); - if(!empty_string(default_profile.worksize)) - set_worksize((char *)default_profile.worksize); + if(!empty_string(default_profile.worksize)) + set_worksize((char *)default_profile.worksize); } //apply profile settings to pools void apply_pool_profiles() { - struct profile *profile; - int i; + int i; + + for(i=total_pools;i--;) + { + apply_pool_profile(pools[i]); + } +} + +void apply_pool_profile(struct pool *pool) +{ + struct profile *profile; + + //if the pool has a profile set + if(!empty_string(pool->profile)) + { + applog(LOG_DEBUG, "Loading settings from profile \"%s\" for pool %i", pool->profile, pool->pool_no); - for(i=total_pools;i--;) + //find profile and apply settings to the pool + if((profile = get_profile(pool->profile))) { - //if the pool has a profile set - if(!empty_string(pools[i]->profile)) - { - applog(LOG_DEBUG, "Loading settings from profile \"%s\" for pool %i", pools[i]->profile, pools[i]->pool_no); - - //find profile and apply settings to the pool - if((profile = get_profile(pools[i]->profile))) - { - pools[i]->algorithm = profile->algorithm; - applog(LOG_DEBUG, "Pool %i Algorithm set to \"%s\"", pools[i]->pool_no, pools[i]->algorithm.name); - - if(!empty_string(profile->devices)) - { - pools[i]->devices = profile->devices; - applog(LOG_DEBUG, "Pool %i devices set to \"%s\"", pools[i]->pool_no, pools[i]->devices); - } - - if(!empty_string(profile->lookup_gap)) - { - pools[i]->lookup_gap = profile->lookup_gap; - applog(LOG_DEBUG, "Pool %i lookup gap set to \"%s\"", pools[i]->pool_no, pools[i]->lookup_gap); - } - - if(!empty_string(profile->intensity)) - { - pools[i]->intensity = profile->intensity; - applog(LOG_DEBUG, "Pool %i Intensity set to \"%s\"", pools[i]->pool_no, pools[i]->intensity); - } - - if(!empty_string(profile->xintensity)) - { - pools[i]->xintensity = profile->xintensity; - applog(LOG_DEBUG, "Pool %i XIntensity set to \"%s\"", pools[i]->pool_no, pools[i]->xintensity); - } - - if(!empty_string(profile->rawintensity)) - { - pools[i]->rawintensity = profile->rawintensity; - applog(LOG_DEBUG, "Pool %i Raw Intensity set to \"%s\"", pools[i]->pool_no, pools[i]->rawintensity); - } - - if(!empty_string(profile->thread_concurrency)) - { - pools[i]->thread_concurrency = profile->thread_concurrency; - applog(LOG_DEBUG, "Pool %i Thread Concurrency set to \"%s\"", pools[i]->pool_no, pools[i]->thread_concurrency); - } + pool->algorithm = profile->algorithm; + applog(LOG_DEBUG, "Pool %i Algorithm set to \"%s\"", pool->pool_no, pool->algorithm.name); + + if(!empty_string(profile->devices)) + { + pool->devices = profile->devices; + applog(LOG_DEBUG, "Pool %i devices set to \"%s\"", pool->pool_no, pool->devices); + } + + if(!empty_string(profile->lookup_gap)) + { + pool->lookup_gap = profile->lookup_gap; + applog(LOG_DEBUG, "Pool %i lookup gap set to \"%s\"", pool->pool_no, pool->lookup_gap); + } + + if(!empty_string(profile->intensity)) + { + pool->intensity = profile->intensity; + applog(LOG_DEBUG, "Pool %i Intensity set to \"%s\"", pool->pool_no, pool->intensity); + } + + if(!empty_string(profile->xintensity)) + { + pool->xintensity = profile->xintensity; + applog(LOG_DEBUG, "Pool %i XIntensity set to \"%s\"", pool->pool_no, pool->xintensity); + } + + if(!empty_string(profile->rawintensity)) + { + pool->rawintensity = profile->rawintensity; + applog(LOG_DEBUG, "Pool %i Raw Intensity set to \"%s\"", pool->pool_no, pool->rawintensity); + } + + if(!empty_string(profile->thread_concurrency)) + { + pool->thread_concurrency = profile->thread_concurrency; + applog(LOG_DEBUG, "Pool %i Thread Concurrency set to \"%s\"", pool->pool_no, pool->thread_concurrency); + } #ifdef HAVE_ADL - if(!empty_string(profile->gpu_engine)) - { - pools[i]->gpu_engine = profile->gpu_engine; - applog(LOG_DEBUG, "Pool %i GPU Clock set to \"%s\"", pools[i]->pool_no, pools[i]->gpu_engine); - } - - if(!empty_string(profile->gpu_memclock)) - { - pools[i]->gpu_memclock = profile->gpu_memclock; - applog(LOG_DEBUG, "Pool %i GPU Memory clock set to \"%s\"", pools[i]->pool_no, pools[i]->gpu_memclock); - } - - if(!empty_string(profile->gpu_threads)) - { - pools[i]->gpu_threads = profile->gpu_threads; - applog(LOG_DEBUG, "Pool %i GPU Threads set to \"%s\"", pools[i]->pool_no, pools[i]->gpu_threads); - } - - if(!empty_string(profile->gpu_fan)) - { - pools[i]->gpu_fan = profile->gpu_fan; - applog(LOG_DEBUG, "Pool %i GPU Fan set to \"%s\"", pools[i]->pool_no, pools[i]->gpu_fan); - } - - if(!empty_string(profile->gpu_powertune)) - { - pools[i]->gpu_powertune = profile->gpu_powertune; - applog(LOG_DEBUG, "Pool %i GPU Powertune set to \"%s\"", pools[i]->pool_no, pools[i]->gpu_powertune); - } - - if(!empty_string(profile->gpu_vddc)) - { - pools[i]->gpu_vddc = profile->gpu_vddc; - applog(LOG_DEBUG, "Pool %i GPU Vddc set to \"%s\"", pools[i]->pool_no, pools[i]->gpu_vddc); - } + if(!empty_string(profile->gpu_engine)) + { + pool->gpu_engine = profile->gpu_engine; + applog(LOG_DEBUG, "Pool %i GPU Clock set to \"%s\"", pool->pool_no, pool->gpu_engine); + } + + if(!empty_string(profile->gpu_memclock)) + { + pool->gpu_memclock = profile->gpu_memclock; + applog(LOG_DEBUG, "Pool %i GPU Memory clock set to \"%s\"", pool->pool_no, pool->gpu_memclock); + } + + if(!empty_string(profile->gpu_threads)) + { + pool->gpu_threads = profile->gpu_threads; + applog(LOG_DEBUG, "Pool %i GPU Threads set to \"%s\"", pool->pool_no, pool->gpu_threads); + } + + if(!empty_string(profile->gpu_fan)) + { + pool->gpu_fan = profile->gpu_fan; + applog(LOG_DEBUG, "Pool %i GPU Fan set to \"%s\"", pool->pool_no, pool->gpu_fan); + } + + if(!empty_string(profile->gpu_powertune)) + { + pool->gpu_powertune = profile->gpu_powertune; + applog(LOG_DEBUG, "Pool %i GPU Powertune set to \"%s\"", pool->pool_no, pool->gpu_powertune); + } + + if(!empty_string(profile->gpu_vddc)) + { + pool->gpu_vddc = profile->gpu_vddc; + applog(LOG_DEBUG, "Pool %i GPU Vddc set to \"%s\"", pool->pool_no, pool->gpu_vddc); + } #endif - if(!empty_string(profile->shaders)) - { - pools[i]->shaders = profile->shaders; - applog(LOG_DEBUG, "Pool %i Shaders set to \"%s\"", pools[i]->pool_no, pools[i]->shaders); - } - - if(!empty_string(profile->worksize)) - { - pools[i]->worksize = profile->worksize; - applog(LOG_DEBUG, "Pool %i Worksize set to \"%s\"", pools[i]->pool_no, pools[i]->worksize); - } - } - else - applog(LOG_DEBUG, "Profile load failed for pool %i: profile %s not found.", pools[i]->pool_no, pools[i]->profile); - } + if(!empty_string(profile->shaders)) + { + pool->shaders = profile->shaders; + applog(LOG_DEBUG, "Pool %i Shaders set to \"%s\"", pool->pool_no, pool->shaders); + } + + if(!empty_string(profile->worksize)) + { + pool->worksize = profile->worksize; + applog(LOG_DEBUG, "Pool %i Worksize set to \"%s\"", pool->pool_no, pool->worksize); + } } + else + { + applog(LOG_DEBUG, "Profile load failed for pool %i: profile %s not found.", pool->pool_no, pool->profile); + //remove profile name + pool->profile[0] = '\0'; + } + } } //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; + 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; + } + } - //create the "pools" array - if(!(pool_array = json_array())) + //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 { - set_last_json_error("json_array() failed on pools"); + 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; } - //process pool entries - for(i=0;irpc_pass)) == -1) { - pool = pools[i]; + set_last_json_error("json_object_set() failed on pool(%d):pass", pool->pool_no); + return NULL; + } - //create a new object - if(!(obj = json_object())) - { - set_last_json_error("json_object() failed on pool %d", 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... + } - //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 pool and profile value doesn't match below, add it + //devices + if(!empty_string(pool->devices)) + { + if(strcmp(pool->devices, profile->devices)) + { + if(json_object_set(obj, "devices", json_string(pool->devices)) == -1) { - 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; - } + set_last_json_error("json_object_set() failed on pool(%d):device", 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) + //lookup-gap + if(!empty_string(pool->lookup_gap)) + { + if(strcmp(pool->lookup_gap, profile->lookup_gap)) + { + if(json_object_set(obj, "lookup-gap", json_string(pool->lookup_gap)) == -1) { - set_last_json_error("json_object_set() failed on pool(%d):pass", pool->pool_no); - return NULL; + set_last_json_error("json_object_set() failed on pool(%d):lookup-gap", 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)) + //intensity + if(!empty_string(pool->intensity)) + { + if(strcmp(pool->intensity, profile->intensity)) + { + if(json_object_set(obj, "intensity", json_string(pool->intensity)) == -1) { - 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; - } + set_last_json_error("json_object_set() failed on pool(%d):intensity", pool->pool_no); + return NULL; } - - //if priority isnt the same as array index, specify it - if(pool->prio != i) + } + } + + //xintensity + if(!empty_string(pool->xintensity)) + { + if(strcmp(pool->xintensity, profile->xintensity) != 0) + { + if(json_object_set(obj, "xintensity", json_string(pool->xintensity)) == -1) { - 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; - } + set_last_json_error("json_object_set() failed on pool(%d):xintensity", 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)) + } + } + + //rawintensity + if(!empty_string(pool->rawintensity)) + { + if(strcmp(pool->rawintensity, profile->rawintensity) != 0) + { + if(json_object_set(obj, "rawintensity", json_string(pool->rawintensity)) == -1) { - 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; + set_last_json_error("json_object_set() failed on pool(%d):rawintensity", pool->pool_no); + return NULL; } - //or select default profile - else - profile = &default_profile; - - //if algorithm is different than profile, add it - if(!cmp_algorithm(&pool->algorithm, &profile->algorithm)) + } + } + + //shaders + if(!empty_string(pool->shaders)) + { + if(strcmp(pool->shaders, profile->shaders) != 0) + { + if(json_object_set(obj, "shaders", json_string(pool->shaders)) == -1) { - //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... + set_last_json_error("json_object_set() failed on pool(%d):shaders", pool->pool_no); + return NULL; } + } + } - //if pool and profile value doesn't match below, add it - //devices - if(!empty_string(pool->devices)) + //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) { - if(strcmp(pool->devices, profile->devices)) - { - if(json_object_set(obj, "devices", json_string(pool->devices)) == -1) - { - set_last_json_error("json_object_set() failed on pool(%d):device", pool->pool_no); - return NULL; - } - } + set_last_json_error("json_object_set() failed on pool(%d):thread-concurrency", pool->pool_no); + return NULL; } + } + } - //lookup-gap - if(!empty_string(pool->lookup_gap)) + //worksize + if(!empty_string(pool->worksize)) + { + if(strcmp(pool->worksize, profile->worksize) != 0) + { + if(json_object_set(obj, "worksize", json_string(pool->worksize)) == -1) { - if(strcmp(pool->lookup_gap, profile->lookup_gap)) - { - if(json_object_set(obj, "lookup-gap", json_string(pool->lookup_gap)) == -1) - { - set_last_json_error("json_object_set() failed on pool(%d):lookup-gap", pool->pool_no); - return NULL; - } - } + set_last_json_error("json_object_set() failed on pool(%d):worksize", pool->pool_no); + return NULL; } - - //intensity - if(!empty_string(pool->intensity)) + } + } +#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) { - 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; - } - } + set_last_json_error("json_object_set() failed on pool(%d):gpu-engine", 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)) + //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) { - 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; - } - } + set_last_json_error("json_object_set() failed on pool(%d):gpu-memclock", pool->pool_no); + return NULL; } - - //shaders - if(!empty_string(pool->shaders)) + } + } + + //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) { - if(strcmp(pool->shaders, profile->shaders) != 0) - { - if(json_object_set(obj, "shaders", json_string(pool->shaders)) == -1) - { - set_last_json_error("json_object_set() failed on pool(%d):shaders", pool->pool_no); - return NULL; - } - } + set_last_json_error("json_object_set() failed on pool(%d):gpu-threads", pool->pool_no); + return NULL; } + } + } - //thread_concurrency - if(!empty_string(pool->thread_concurrency)) + //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) { - 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; - } - } + set_last_json_error("json_object_set() failed on pool(%d):gpu-fan", pool->pool_no); + return NULL; } + } + } - //worksize - if(!empty_string(pool->worksize)) + //gpu-powertune + if(!empty_string(pool->gpu_powertune)) + { + if(strcmp(pool->gpu_powertune, profile->gpu_powertune) != 0) + { + if(json_object_set(obj, "gpu-powertune", json_string(pool->gpu_powertune)) == -1) { - if(strcmp(pool->worksize, profile->worksize) != 0) - { - if(json_object_set(obj, "worksize", json_string(pool->worksize)) == -1) - { - set_last_json_error("json_object_set() failed on pool(%d):worksize", pool->pool_no); - return NULL; - } - } + set_last_json_error("json_object_set() failed on pool(%d):gpu-powertune", pool->pool_no); + return NULL; } -#ifdef HAVE_ADL - //gpu_engine - if(!empty_string(pool->gpu_engine)) + } + } + + //gpu-vddc + if(!empty_string(pool->gpu_vddc)) + { + if(strcmp(pool->gpu_vddc, profile->gpu_vddc) != 0) + { + if(json_object_set(obj, "gpu-vddc", json_string(pool->gpu_vddc)) == -1) { - 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; - } - } - } - - //gpu-powertune - if(!empty_string(pool->gpu_powertune)) - { - if(strcmp(pool->gpu_powertune, profile->gpu_powertune) != 0) - { - if(json_object_set(obj, "gpu-powertune", json_string(pool->gpu_powertune)) == -1) - { - set_last_json_error("json_object_set() failed on pool(%d):gpu-powertune", pool->pool_no); - return NULL; - } - } - } - - //gpu-vddc - if(!empty_string(pool->gpu_vddc)) - { - if(strcmp(pool->gpu_vddc, profile->gpu_vddc) != 0) - { - if(json_object_set(obj, "gpu-vddc", json_string(pool->gpu_vddc)) == -1) - { - set_last_json_error("json_object_set() failed on pool(%d):gpu-vddc", 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; + set_last_json_error("json_object_set() failed on pool(%d):gpu-vddc", pool->pool_no); + return NULL; } + } } +#endif - return pool_array; + //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())) + 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)) { - set_last_json_error("json_array() failed on profiles"); + 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; + } } - //process pool entries - for(i=0;ialgorithm) || !strcasecmp(default_profile.name, profile->name)) { - profile = profiles[i]; - - //create a new object - if(!(obj = json_object())) - { - set_last_json_error("json_object() failed on profile %d", profile->profile_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 default profile is the current profile, always add - if(!cmp_algorithm(&default_profile.algorithm, &profile->algorithm) || !strcasecmp(default_profile.name, profile->name)) - { - //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... - } + //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 - //devices - if(!empty_string(profile->devices)) + //if pool and profile value doesn't match below, add it + //devices + if(!empty_string(profile->devices)) + { + //always add if default profile is this profile + if(strcmp(default_profile.devices, profile->devices) != 0 || !strcasecmp(default_profile.name, profile->name)) + { + if(json_object_set(obj, "devices", json_string(profile->devices)) == -1) { - //always add if default profile is this profile - if(strcmp(default_profile.devices, profile->devices) != 0 || !strcasecmp(default_profile.name, profile->name)) - { - if(json_object_set(obj, "devices", json_string(profile->devices)) == -1) - { - set_last_json_error("json_object_set() failed on profile(%d):device", profile->profile_no); - return NULL; - } - } + set_last_json_error("json_object_set() failed on profile(%d):device", profile->profile_no); + return NULL; } + } + } - //lookup-gap - if(!empty_string(profile->lookup_gap)) + //lookup-gap + if(!empty_string(profile->lookup_gap)) + { + //always add if default profile is this profile + if(strcmp(default_profile.lookup_gap, profile->lookup_gap) != 0 || !strcasecmp(default_profile.name, profile->name)) + { + if(json_object_set(obj, "lookup-gap", json_string(profile->lookup_gap)) == -1) { - //always add if default profile is this profile - if(strcmp(default_profile.lookup_gap, profile->lookup_gap) != 0 || !strcasecmp(default_profile.name, profile->name)) - { - if(json_object_set(obj, "lookup-gap", json_string(profile->lookup_gap)) == -1) - { - set_last_json_error("json_object_set() failed on profile(%d):lookup-gap", profile->profile_no); - return NULL; - } - } + set_last_json_error("json_object_set() failed on profile(%d):lookup-gap", profile->profile_no); + return NULL; } + } + } - //intensity - if(!empty_string(profile->intensity)) + //intensity + if(!empty_string(profile->intensity)) + { + //always add if default profile is this profile + if(strcmp(default_profile.intensity, profile->intensity) != 0 || !strcasecmp(default_profile.name, profile->name)) + { + if(json_object_set(obj, "intensity", json_string(profile->intensity)) == -1) { - //always add if default profile is this profile - if(strcmp(default_profile.intensity, profile->intensity) != 0 || !strcasecmp(default_profile.name, profile->name)) - { - 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; - } - } + set_last_json_error("json_object_set() failed on profile(%d):intensity", profile->profile_no); + return NULL; } + } + } - //xintensity - if(!empty_string(profile->xintensity)) + //xintensity + if(!empty_string(profile->xintensity)) + { + if(strcmp(default_profile.xintensity, profile->xintensity) != 0 || !strcasecmp(default_profile.name, profile->name)) + { + if(json_object_set(obj, "xintensity", json_string(profile->xintensity)) == -1) { - if(strcmp(default_profile.xintensity, profile->xintensity) != 0 || !strcasecmp(default_profile.name, profile->name)) - { - 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; - } - } + set_last_json_error("json_object_set() failed on profile(%d):xintensity", profile->profile_no); + return NULL; } - - //rawintensity - if(!empty_string(profile->rawintensity)) + } + } + + //rawintensity + if(!empty_string(profile->rawintensity)) + { + if(strcmp(default_profile.rawintensity, profile->rawintensity) != 0 || !strcasecmp(default_profile.name, profile->name)) + { + if(json_object_set(obj, "rawintensity", json_string(profile->rawintensity)) == -1) { - if(strcmp(default_profile.rawintensity, profile->rawintensity) != 0 || !strcasecmp(default_profile.name, profile->name)) - { - 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; - } - } + set_last_json_error("json_object_set() failed on profile(%d):rawintensity", profile->profile_no); + return NULL; } - - //shaders - if(!empty_string(profile->shaders)) + } + } + + //shaders + if(!empty_string(profile->shaders)) + { + if(strcmp(default_profile.shaders, profile->shaders) != 0 || !strcasecmp(default_profile.name, profile->name)) + { + if(json_object_set(obj, "shaders", json_string(profile->shaders)) == -1) { - if(strcmp(default_profile.shaders, profile->shaders) != 0 || !strcasecmp(default_profile.name, profile->name)) - { - if(json_object_set(obj, "shaders", json_string(profile->shaders)) == -1) - { - set_last_json_error("json_object_set() failed on profile(%d):shaders", profile->profile_no); - return NULL; - } - } + set_last_json_error("json_object_set() failed on profile(%d):shaders", profile->profile_no); + return NULL; } + } + } - //thread_concurrency - if(!empty_string(profile->thread_concurrency)) + //thread_concurrency + if(!empty_string(profile->thread_concurrency)) + { + if(strcmp(default_profile.thread_concurrency, profile->thread_concurrency) != 0 || !strcasecmp(default_profile.name, profile->name)) + { + if(json_object_set(obj, "thread-concurrency", json_string(profile->thread_concurrency)) == -1) { - if(strcmp(default_profile.thread_concurrency, profile->thread_concurrency) != 0 || !strcasecmp(default_profile.name, profile->name)) - { - 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; - } - } + set_last_json_error("json_object_set() failed on profile(%d):thread_concurrency", profile->profile_no); + return NULL; } + } + } - //worksize - if(!empty_string(profile->worksize)) + //worksize + if(!empty_string(profile->worksize)) + { + if(strcmp(default_profile.worksize, profile->worksize) != 0 || !strcasecmp(default_profile.name, profile->name)) + { + if(json_object_set(obj, "worksize", json_string(profile->worksize)) == -1) { - if(strcmp(default_profile.worksize, profile->worksize) != 0 || !strcasecmp(default_profile.name, profile->name)) - { - if(json_object_set(obj, "worksize", json_string(profile->worksize)) == -1) - { - set_last_json_error("json_object_set() failed on profile(%d):worksize", profile->profile_no); - return NULL; - } - } + set_last_json_error("json_object_set() failed on profile(%d):worksize", profile->profile_no); + return NULL; } + } + } -#ifdef HAVE_ADL - //gpu_engine - if(!empty_string(profile->gpu_engine)) +#ifdef HAVE_ADL + //gpu_engine + if(!empty_string(profile->gpu_engine)) + { + if(strcmp(default_profile.gpu_engine, profile->gpu_engine) != 0 || !strcasecmp(default_profile.name, profile->name)) + { + if(json_object_set(obj, "gpu-engine", json_string(profile->gpu_engine)) == -1) { - if(strcmp(default_profile.gpu_engine, profile->gpu_engine) != 0 || !strcasecmp(default_profile.name, profile->name)) - { - 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; - } - } + 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)) + //gpu_memclock + if(!empty_string(profile->gpu_memclock)) + { + if(strcmp(default_profile.gpu_memclock, profile->gpu_memclock) != 0 || !strcasecmp(default_profile.name, profile->name)) + { + if(json_object_set(obj, "gpu-memclock", json_string(profile->gpu_memclock)) == -1) { - if(strcmp(default_profile.gpu_memclock, profile->gpu_memclock) != 0 || !strcasecmp(default_profile.name, profile->name)) - { - 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; - } - } + 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)) + //gpu_threads + if(!empty_string(profile->gpu_threads)) + { + if(strcmp(default_profile.gpu_threads, profile->gpu_threads) != 0 || !strcasecmp(default_profile.name, profile->name)) + { + if(json_object_set(obj, "gpu-threads", json_string(profile->gpu_threads)) == -1) { - if(strcmp(default_profile.gpu_threads, profile->gpu_threads) != 0 || !strcasecmp(default_profile.name, profile->name)) - { - 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; - } - } + 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)) + //gpu_fan + if(!empty_string(profile->gpu_fan)) + { + if(strcmp(default_profile.gpu_fan, profile->gpu_fan) != 0 || !strcasecmp(default_profile.name, profile->name)) + { + if(json_object_set(obj, "gpu-fan", json_string(profile->gpu_fan)) == -1) { - if(strcmp(default_profile.gpu_fan, profile->gpu_fan) != 0 || !strcasecmp(default_profile.name, profile->name)) - { - 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; - } - } + set_last_json_error("json_object_set() failed on profile(%d):gpu-fan", profile->profile_no); + return NULL; } + } + } - //gpu-powertune - if(!empty_string(profile->gpu_powertune)) + //gpu-powertune + if(!empty_string(profile->gpu_powertune)) + { + if(strcmp(default_profile.gpu_powertune, profile->gpu_powertune) != 0 || !strcasecmp(default_profile.name, profile->name)) + { + if(json_object_set(obj, "gpu-powertune", json_string(profile->gpu_powertune)) == -1) { - if(strcmp(default_profile.gpu_powertune, profile->gpu_powertune) != 0 || !strcasecmp(default_profile.name, profile->name)) - { - if(json_object_set(obj, "gpu-powertune", json_string(profile->gpu_powertune)) == -1) - { - set_last_json_error("json_object_set() failed on profile(%d):gpu-powertune", profile->profile_no); - return NULL; - } - } + set_last_json_error("json_object_set() failed on profile(%d):gpu-powertune", profile->profile_no); + return NULL; } + } + } - //gpu-vddc - if(!empty_string(profile->gpu_vddc)) - { - if(strcmp(default_profile.gpu_vddc, profile->gpu_vddc) != 0 || !strcasecmp(default_profile.name, profile->name)) - { - if(json_object_set(obj, "gpu-vddc", json_string(profile->gpu_vddc)) == -1) - { - set_last_json_error("json_object_set() failed on profile(%d):gpu-vddc", profile->profile_no); - return NULL; - } - } - } -#endif - - //all done, add pool to array... - if(json_array_append_new(profile_array, obj) == -1) + //gpu-vddc + if(!empty_string(profile->gpu_vddc)) + { + if(strcmp(default_profile.gpu_vddc, profile->gpu_vddc) != 0 || !strcasecmp(default_profile.name, profile->name)) + { + if(json_object_set(obj, "gpu-vddc", json_string(profile->gpu_vddc)) == -1) { - set_last_json_error("json_array_append() failed on profile %d", profile->profile_no); - return NULL; + set_last_json_error("json_object_set() failed on profile(%d):gpu-vddc", profile->profile_no); + return NULL; } + } } +#endif - return profile_array; + //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."); + 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; } - - //build pools - if(!(obj = build_pool_json())) + } + //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 %s.", last_json_error); - return; + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on algorithm"); + return; } - - //add pools to config - if(json_object_set(config, "pools", obj) == -1) + //TODO: add other options like nfactor etc... + + //devices + if(!empty_string(default_profile.devices)) { - applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set(pools) failed."); + if(json_object_set(config, "devices", json_string(default_profile.devices)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on devices"); return; + } } - - //build profiles - if(!(obj = build_profile_json())) + + //lookup-gap + if(!empty_string(default_profile.lookup_gap)) { - applog(LOG_ERR, "Error: config_parser::write_config():\n %s.", last_json_error); + if(json_object_set(config, "lookup-gap", json_string(default_profile.lookup_gap)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on lookup-gap"); return; + } } - - //add profiles to config - if(json_object_set(config, "profiles", obj) == -1) + + //intensity + if(!empty_string(default_profile.intensity)) { - applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set(profiles) failed."); + 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; + } } - //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; + //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; + } } - - //if using a specific profile as default, set it - if(!empty_string(default_profile.name)) + + //rawintensity + if(!empty_string(default_profile.rawintensity)) { - 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; - } + 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; + } } - //otherwise save default profile values - else + + //shaders + if(!empty_string(default_profile.shaders)) { - //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... + if(json_object_set(config, "shaders", json_string(default_profile.shaders)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on shaders"); + return; + } + } - //devices - if(!empty_string(default_profile.devices)) - { - if(json_object_set(config, "devices", json_string(default_profile.devices)) == -1) - { - applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on devices"); - 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; + } + } - //lookup-gap - if(!empty_string(default_profile.lookup_gap)) - { - if(json_object_set(config, "lookup-gap", json_string(default_profile.lookup_gap)) == -1) - { - applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on lookup-gap"); - return; - } - } + //worksize + if(!empty_string(default_profile.worksize)) + { + if(json_object_set(config, "worksize", json_string(default_profile.worksize)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on worksize"); + return; + } + } - //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; - } - } +#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; + } + } - //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; - } - } - - //shaders - if(!empty_string(default_profile.shaders)) - { - if(json_object_set(config, "shaders", json_string(default_profile.shaders)) == -1) - { - applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on shaders"); - 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; + } + } - //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; - } - } + //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; + } + } - //worksize - if(!empty_string(default_profile.worksize)) - { - if(json_object_set(config, "worksize", json_string(default_profile.worksize)) == -1) - { - applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on worksize"); - 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; + } + } -#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-powertune + if(!empty_string(default_profile.gpu_powertune)) + { + if(json_object_set(config, "gpu-powertune", json_string(default_profile.gpu_powertune)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-powertune"); + 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-vddc + if(!empty_string(default_profile.gpu_vddc)) + { + if(json_object_set(config, "gpu-vddc", json_string(default_profile.gpu_vddc)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-vddc"); + return; + } + } +#endif + } - //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; - } - } + //devices + /*if(opt_devs_enabled) + { + bool extra_devs = false; + obj = json_string(""); - //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; - } - } + for(i = 0; i < MAX_DEVICES; i++) + { + if(devices_enabled[i]) + { + int startd = i; - //gpu-powertune - if(!empty_string(default_profile.gpu_powertune)) - { - if(json_object_set(config, "gpu-powertune", json_string(default_profile.gpu_powertune)) == -1) - { - applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-powertune"); - return; - } - } + if(extra_devs) + obj = json_sprintf("%s%s", json_string_value(obj), ","); - //gpu-vddc - if(!empty_string(default_profile.gpu_vddc)) - { - if(json_object_set(config, "gpu-vddc", json_string(default_profile.gpu_vddc)) == -1) - { - applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-vddc"); - return; - } - } -#endif + 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; + } + + } - //devices - /*if(opt_devs_enabled) + //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) { - bool extra_devs = false; - obj = json_string(""); + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on temp-cutoff"); + return; + } - 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) + //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) { - 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; - } - + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on temp-overheat"); + return; } - //write gpu settings that aren't part of profiles -- only write if gpus are available - if(nDevs) + //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; + } -#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; - } - } - - //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; - } -#endif + //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; + } } - //add other misc options - //shares - if(json_object_set(config, "shares", json_sprintf("%d", opt_shares)) == -1) + //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 shares"); - return; + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-memdiff"); + 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) + //monitor + if(opt_stderr_cmd && *opt_stderr_cmd) + { + if(json_object_set(config, "monitor", json_string(opt_stderr_cmd)) == -1) { - 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; - } + 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) + //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) { - //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; - } + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on kernel-path"); + return; } - - //sched-time - if(schedstart.enable) + } + + //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) { - 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; - } + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on sched-time"); + return; } - - //stop-time - if(schedstop.enable) + } + + //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) { - 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; - } + 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) + } + + //socks-proxy + if(opt_socks_proxy && *opt_socks_proxy) + { + if(json_object_set(config, "socks-proxy", json_string(opt_socks_proxy)) == -1) { - 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; - } + 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) + //api stuff + //api-allow + if(opt_api_allow) + { + if(json_object_set(config, "api-allow", json_string(opt_api_allow)) == -1) { - 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; - } + 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) + } + + //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) { - 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; - } + 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) + //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) { - 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; - } + 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) + //api-mcast-des + if(*opt_api_mcast_des) + { + if(json_object_set(config, "api-mcast-des", json_string(opt_api_mcast_des)) == -1) { - 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; - } + 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) + //api-description + if(strcmp(opt_api_description, PACKAGE_STRING) != 0) + { + if(json_object_set(config, "api-description", json_string(opt_api_description)) == -1) { - 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; - } + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on api-description"); + return; } - - //api-groups - if(opt_api_groups) + } + + //api-groups + if(opt_api_groups) + { + if(json_object_set(config, "api-groups", json_string(opt_api_groups)) == -1) { - 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; - } + 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++) + //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-")) { - 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 - } - } + //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)); + json_dump_file(config, filename, JSON_PRESERVE_ORDER|JSON_INDENT(4)); } diff --git a/config_parser.h b/config_parser.h index 8cbba73b..8926546e 100644 --- a/config_parser.h +++ b/config_parser.h @@ -8,34 +8,34 @@ //helper to check for empty or NULL strings #ifndef empty_string - #define empty_string(str) ((str && str[0] != '\0')?0:1) + #define empty_string(str) ((str && str[0] != '\0')?0:1) #endif //helper function to get a gpu option value #ifndef gpu_opt - #define gpu_opt(i,optname) gpus[i].optname + #define gpu_opt(i,optname) gpus[i].optname #endif //profile structure struct profile { - int profile_no; - char *name; + int profile_no; + char *name; - algorithm_t algorithm; - const char *devices; - const char *intensity; - const char *xintensity; - const char *rawintensity; - const char *lookup_gap; - const char *gpu_engine; - const char *gpu_memclock; - const char *gpu_threads; - const char *gpu_fan; - const char *gpu_powertune; - const char *gpu_vddc; - const char *shaders; - const char *thread_concurrency; - const char *worksize; + algorithm_t algorithm; + const char *devices; + const char *intensity; + const char *xintensity; + const char *rawintensity; + const char *lookup_gap; + const char *gpu_engine; + const char *gpu_memclock; + const char *gpu_threads; + const char *gpu_fan; + const char *gpu_powertune; + const char *gpu_vddc; + const char *shaders; + const char *thread_concurrency; + const char *worksize; }; /* globals needed outside */ @@ -57,12 +57,12 @@ extern char *set_default_xintensity(const char *arg); extern char *set_default_rawintensity(const char *arg); extern char *set_default_thread_concurrency(const char *arg); #ifdef HAVE_ADL - extern char *set_default_gpu_engine(const char *arg); - extern char *set_default_gpu_memclock(const char *arg); - extern char *set_default_gpu_threads(const char *arg); - extern char *set_default_gpu_fan(const char *arg); - extern char *set_default_gpu_powertune(const char *arg); - extern char *set_default_gpu_vddc(const char *arg); + extern char *set_default_gpu_engine(const char *arg); + extern char *set_default_gpu_memclock(const char *arg); + extern char *set_default_gpu_threads(const char *arg); + extern char *set_default_gpu_fan(const char *arg); + extern char *set_default_gpu_powertune(const char *arg); + extern char *set_default_gpu_vddc(const char *arg); #endif extern char *set_default_profile(char *arg); extern char *set_default_shaders(const char *arg); @@ -77,12 +77,12 @@ extern char *set_profile_xintensity(const char *arg); extern char *set_profile_rawintensity(const char *arg); extern char *set_profile_thread_concurrency(const char *arg); #ifdef HAVE_ADL - extern char *set_profile_gpu_engine(const char *arg); - extern char *set_profile_gpu_memclock(const char *arg); - extern char *set_profile_gpu_threads(const char *arg); - extern char *set_profile_gpu_fan(const char *arg); - extern char *set_profile_gpu_powertune(const char *arg); - extern char *set_profile_gpu_vddc(const char *arg); + extern char *set_profile_gpu_engine(const char *arg); + extern char *set_profile_gpu_memclock(const char *arg); + extern char *set_profile_gpu_threads(const char *arg); + extern char *set_profile_gpu_fan(const char *arg); + extern char *set_profile_gpu_powertune(const char *arg); + extern char *set_profile_gpu_vddc(const char *arg); #endif extern char *set_profile_nfactor(const char *arg); extern char *set_profile_shaders(const char *arg); @@ -98,6 +98,7 @@ extern void load_default_config(void); extern void load_default_profile(); extern void apply_defaults(); extern void apply_pool_profiles(); +extern void apply_pool_profile(struct pool *pool); /* config writer */ extern void write_config(const char *filename); diff --git a/doc/API b/doc/API.md similarity index 99% rename from doc/API rename to doc/API.md index ecab03c7..e6b12806 100644 --- a/doc/API +++ b/doc/API.md @@ -207,13 +207,13 @@ The list of requests - a (*) means it requires privileged access - and replies: stating the results of enabling pool N The Msg includes the pool URL - addpool|URL,USR,PASS[,NAME,DESC,ALGO] (*) + addpool|URL,USR,PASS[,NAME,DESC,PROFILE,ALGO] (*) none There is no reply section just the STATUS section stating the results of attempting to add pool N The Msg includes the pool URL Use '\\' to get a '\' and '\,' to include a comma inside URL, USR or PASS - Name, description and algorithm are optional + Name, description, profile and algorithm are optional poolpriority|N,... (*) none There is no reply section just the STATUS section @@ -235,6 +235,13 @@ The list of requests - a (*) means it requires privileged access - and replies: The Msg includes the pool URL N.B. all details for the pool will be lost + changestrategy|STRAT,INT (*) + none There is no reply section just the STATUS section + stating the results of changing multipool strategy + to STRAT. If the strategy requested is "rotate", + the interval INT must be specified as a number + between 0 and 9999 seconds. INT is not required + otherwise. gpuenable|N (*) none There is no reply section just the STATUS section stating the results of the enable request diff --git a/doc/GPU b/doc/GPU.md similarity index 100% rename from doc/GPU rename to doc/GPU.md diff --git a/miner.h b/miner.h index e8773694..07aa1021 100644 --- a/miner.h +++ b/miner.h @@ -253,7 +253,6 @@ enum alive { LIFE_INIT, }; - enum pool_strategy { POOL_FAILOVER, POOL_ROUNDROBIN, @@ -268,6 +267,9 @@ struct strategies { const char *s; }; +extern enum pool_strategy pool_strategy; +extern struct strategies strategies[]; + struct cgpu_info; #ifdef HAVE_ADL @@ -1044,7 +1046,7 @@ extern bool detect_stratum(struct pool *pool, char *url); extern void print_summary(void); extern void adjust_quota_gcd(void); extern struct pool *add_pool(void); -extern bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass, char *name, char *desc, char *algo); +extern bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass, char *name, char *desc, char *profile, char *algo); #define MAX_GPUDEVICES 16 #define MAX_DEVICES 4096 diff --git a/sgminer.c b/sgminer.c index 14d7c421..beb9b027 100644 --- a/sgminer.c +++ b/sgminer.c @@ -71,14 +71,6 @@ char *curly = ":D"; #define VERSION GIT_VERSION #endif -struct strategies strategies[] = { - { "Failover" }, - { "Round Robin" }, - { "Rotate" }, - { "Load Balance" }, - { "Balance" }, -}; - static char packagename[256]; bool opt_work_update; @@ -230,6 +222,14 @@ unsigned int total_go, total_ro; struct pool **pools; static struct pool *currentpool = NULL; +struct strategies strategies[] = { + { "Failover" }, + { "Round Robin" }, + { "Rotate" }, + { "Load Balance" }, + { "Balance" }, +}; + int total_pools, enabled_pools; enum pool_strategy pool_strategy = POOL_FAILOVER; int opt_rotate_period; @@ -1390,6 +1390,16 @@ struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--more-notices", opt_set_bool, &opt_morenotices, "Shows work restart and new block notices, hidden by default"), + OPT_WITH_ARG("--intensity|-I", + set_default_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, + set_default_xintensity, NULL, NULL, + "Shader based intensity of GPU scanning (" MIN_XINTENSITY_STR " to " + MAX_XINTENSITY_STR "), overridden --xintensity|-X and --rawintensity."), OPT_WITH_ARG("--xintensity|-X", // set_xintensity, NULL, NULL, set_default_xintensity, NULL, NULL, @@ -1449,7 +1459,7 @@ struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--no-submit-stale", opt_set_invbool, &opt_submit_stale, "Don't submit shares if they are detected as stale"), - OPT_WITHOUT_ARG("--no-extranonce-subscribe", + OPT_WITHOUT_ARG("--no-extranonce|--pool-no-extranonce", set_no_extranonce_subscribe, NULL, "Disable 'extranonce' stratum subscribe for pool"), OPT_WITH_ARG("--pass|--pool-pass|-p", @@ -1628,7 +1638,7 @@ struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--show-coindiff", opt_set_bool, &opt_show_coindiff, "Show coin difficulty rather than hash value of a share"), - OPT_WITH_ARG("--state", + OPT_WITH_ARG("--state|--pool-state", set_pool_state, NULL, NULL, "Specify pool state at startup (default: enabled)"), #ifdef HAVE_SYSLOG_H @@ -1689,7 +1699,7 @@ struct opt_table opt_config_table[] = { OPT_WITH_ARG("--worksize|-w", set_default_worksize, NULL, NULL, "Override detected optimal worksize - one value or comma separated list"), - OPT_WITH_ARG("--userpass|-O", + OPT_WITH_ARG("--userpass|--pool-userpass|-O", set_userpass, NULL, NULL, "Username:Password pair for bitcoin JSON-RPC server"), OPT_WITHOUT_ARG("--worktime", @@ -7200,7 +7210,7 @@ static void *test_pool_thread(void *arg) /* Always returns true that the pool details were added unless we are not * live, implying this is the only pool being added, so if no pools are * active it returns false. */ -bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass, char *name, char *desc, char *algo) +bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass, char *name, char *desc, char *profile, char *algo) { size_t siz; @@ -7211,7 +7221,20 @@ bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char pool->rpc_pass = pass; pool->name = name; pool->description = desc; - set_algorithm(&pool->algorithm, algo); + pool->profile = profile; + + //if a profile was supplied, apply pool properties from profile + if(!empty_string(profile)) + apply_pool_profile(pool); //remove profile if was invalid + + //if profile is empty, assign algorithm or default algorithm + if(empty_string(pool->profile)) + { + if(!empty_string(algo)) + set_algorithm(&pool->algorithm, algo); + else + set_algorithm(&pool->algorithm, default_profile.algorithm.name); + } siz = strlen(pool->rpc_user) + strlen(pool->rpc_pass) + 2; pool->rpc_userpass = (char *)malloc(siz); @@ -7236,7 +7259,7 @@ bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char static bool input_pool(bool live) { char *url = NULL, *user = NULL, *pass = NULL; - char *name = NULL, *desc = NULL, *algo = NULL; + char *name = NULL, *desc = NULL, *profile = NULL, *algo = NULL; struct pool *pool; bool ret = false; @@ -7254,8 +7277,10 @@ static bool input_pool(bool live) if (strcmp(name, "-1") == 0) strcpy(name, ""); desc = curses_input("Description (optional)"); if (strcmp(desc, "-1") == 0) strcpy(desc, ""); + algo = curses_input("Profile (optional)"); + if (strcmp(profile, "-1") == 0) profile[0] = '\0'; algo = curses_input("Algorithm (optional)"); - if (strcmp(algo, "-1") == 0) strcpy(algo, opt_algorithm.name); + if (strcmp(algo, "-1") == 0) algo[0] = '\0'; pool = add_pool(); @@ -7273,7 +7298,7 @@ static bool input_pool(bool live) } ret = add_pool_details(pool, live, url, user, pass, - name, desc, algo); + name, desc, profile, algo); out: immedok(logwin, false);