int CommandLineRPC(int argc, char *argv[]) { std::string strPrint; int nRet = 0; try { // Skip switches while (argc > 1 && IsSwitchChar(argv[1][0])) { argc--; argv++; } std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]); if (gArgs.GetBoolArg("-stdin", false)) { // Read one arg per line from stdin and append std::string line; while (std::getline(std::cin,line)) args.push_back(line); } if (args.size() < 1) throw std::runtime_error("too few parameters (need at least command)"); std::string strMethod = args[0]; args.erase(args.begin()); // Remove trailing method name from arguments vector UniValue params; if(gArgs.GetBoolArg("-named", DEFAULT_NAMED)) { params = RPCConvertNamedValues(strMethod, args); } else { params = RPCConvertValues(strMethod, args); } // Execute and handle connection failures with -rpcwait const bool fWait = gArgs.GetBoolArg("-rpcwait", false); do { try { const UniValue reply = CallRPC(strMethod, params); // Parse reply const UniValue& result = find_value(reply, "result"); const UniValue& error = find_value(reply, "error"); if (!error.isNull()) { // Error int code = error["code"].get_int(); if (fWait && code == RPC_IN_WARMUP) throw CConnectionFailed("server in warmup"); strPrint = "error: " + error.write(); nRet = abs(code); if (error.isObject()) { UniValue errCode = find_value(error, "code"); UniValue errMsg = find_value(error, "message"); strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n"; if (errMsg.isStr()) strPrint += "error message:\n"+errMsg.get_str(); if (errCode.isNum() && errCode.get_int() == RPC_WALLET_NOT_SPECIFIED) { strPrint += "\nTry adding \"-rpcwallet=<filename>\" option to batamcoin-cli command line."; } } } else { // Result if (result.isNull()) strPrint = ""; else if (result.isStr()) strPrint = result.get_str(); else strPrint = result.write(2); } // Connection succeeded, no need to retry. break; } catch (const CConnectionFailed&) { if (fWait) MilliSleep(1000); else throw; } } while (fWait); } catch (const boost::thread_interrupted&) { throw; } catch (const std::exception& e) { strPrint = std::string("error: ") + e.what(); nRet = EXIT_FAILURE; } catch (...) { PrintExceptionContinue(nullptr, "CommandLineRPC()"); throw; } if (strPrint != "") { fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str()); } return nRet; }
void ThreadCli() { // - Simple persistent cli // TODO: // unbuffered terminal input on linux // format help text char buffer[4096]; size_t n; fd_set rfds; struct timeval tv; printf("Shadow CLI ready:\n> "); fflush(stdout); for (;;) { boost::this_thread::interruption_point(); // - must be set every iteration FD_ZERO(&rfds); FD_SET(STDIN_FILENO, &rfds); tv.tv_sec = 0; tv.tv_usec = 200000; if (select(1, &rfds, NULL, NULL, &tv) < 1) // read blocks thread from interrupt continue; if ((n = read(STDIN_FILENO, buffer, sizeof(buffer))) < 1) continue; buffer[n] = '\0'; for ( ; n > 0 && (buffer[n-1] == '\n' || buffer[n-1] == '\r'); --n) buffer[n-1] = '\0'; if (strcmp(buffer, "stop") == 0 || strcmp(buffer, "exit") == 0 || strcmp(buffer, "quit") == 0 || strcmp(buffer, "q") == 0) { puts("Exiting..."); break; }; std::string strMethod; std::vector<std::string> strParams; char *p; if ((p = strchr(buffer, ' '))) { strMethod = std::string(buffer, p); char *pPS = p+1; char *pPE = p+1; while (*pPS && ((pPE = strchr(pPS, ' ')) || (pPE = strchr(pPS, '\0')))) { strParams.push_back(std::string(pPS, pPE)); pPS = pPE+1; }; } else { strMethod = std::string(buffer); }; std::string strReply; JSONRequest jreq; try { json_spirit::Array params = RPCConvertValues(strMethod, strParams); json_spirit::Value result = tableRPC.execute(strMethod, params); strReply = json_spirit::write_string(result, true); ReplaceStrInPlace(strReply, "\\n", "\n"); // format help msg if (write(STDOUT_FILENO, strReply.data(), strReply.length()) != (uint32_t) strReply.length()) throw std::runtime_error("write failed."); printf("\n> "); fflush(stdout); } catch (json_spirit::Object& objError) { std::string strReply = JSONRPCReply(json_spirit::Value::null, objError, 0); printf("Error: %s\n> ", strReply.c_str()); fflush(stdout); } catch (std::exception& e) { printf("Error: %s\n> ", e.what()); fflush(stdout); }; fflush(stdout); }; StartShutdown(); };
bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand) { std::vector< std::vector<std::string> > stack; stack.push_back(std::vector<std::string>()); enum CmdParseState { STATE_EATING_SPACES, STATE_EATING_SPACES_IN_ARG, STATE_EATING_SPACES_IN_BRACKETS, STATE_ARGUMENT, STATE_SINGLEQUOTED, STATE_DOUBLEQUOTED, STATE_ESCAPE_OUTER, STATE_ESCAPE_DOUBLEQUOTED, STATE_COMMAND_EXECUTED, STATE_COMMAND_EXECUTED_INNER } state = STATE_EATING_SPACES; std::string curarg; UniValue lastResult; std::string strCommandTerminated = strCommand; if (strCommandTerminated.back() != '\n') strCommandTerminated += "\n"; for(char ch: strCommandTerminated) { switch(state) { case STATE_COMMAND_EXECUTED_INNER: case STATE_COMMAND_EXECUTED: { bool breakParsing = true; switch(ch) { case '[': curarg.clear(); state = STATE_COMMAND_EXECUTED_INNER; break; default: if (state == STATE_COMMAND_EXECUTED_INNER) { if (ch != ']') { // append char to the current argument (which is also used for the query command) curarg += ch; break; } if (curarg.size()) { // if we have a value query, query arrays with index and objects with a string key UniValue subelement; if (lastResult.isArray()) { for(char argch: curarg) if (!std::isdigit(argch)) throw std::runtime_error("Invalid result query"); subelement = lastResult[atoi(curarg.c_str())]; } else if (lastResult.isObject()) subelement = find_value(lastResult, curarg); else throw std::runtime_error("Invalid result query"); //no array or object: abort lastResult = subelement; } state = STATE_COMMAND_EXECUTED; break; } // don't break parsing when the char is required for the next argument breakParsing = false; // pop the stack and return the result to the current command arguments stack.pop_back(); // don't stringify the json in case of a string to avoid doublequotes if (lastResult.isStr()) curarg = lastResult.get_str(); else curarg = lastResult.write(2); // if we have a non empty result, use it as stack argument otherwise as general result if (curarg.size()) { if (stack.size()) stack.back().push_back(curarg); else strResult = curarg; } curarg.clear(); // assume eating space state state = STATE_EATING_SPACES; } if (breakParsing) break; } case STATE_ARGUMENT: // In or after argument case STATE_EATING_SPACES_IN_ARG: case STATE_EATING_SPACES_IN_BRACKETS: case STATE_EATING_SPACES: // Handle runs of whitespace switch(ch) { case '"': state = STATE_DOUBLEQUOTED; break; case '\'': state = STATE_SINGLEQUOTED; break; case '\\': state = STATE_ESCAPE_OUTER; break; case '(': case ')': case '\n': if (state == STATE_EATING_SPACES_IN_ARG) throw std::runtime_error("Invalid Syntax"); if (state == STATE_ARGUMENT) { if (ch == '(' && stack.size() && stack.back().size() > 0) stack.push_back(std::vector<std::string>()); // don't allow commands after executed commands on baselevel if (!stack.size()) throw std::runtime_error("Invalid Syntax"); stack.back().push_back(curarg); curarg.clear(); state = STATE_EATING_SPACES_IN_BRACKETS; } if ((ch == ')' || ch == '\n') && stack.size() > 0) { std::string strPrint; // Convert argument list to JSON objects in method-dependent way, // and pass it along with the method name to the dispatcher. JSONRPCRequest req; req.params = RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end())); req.strMethod = stack.back()[0]; lastResult = tableRPC.execute(req); state = STATE_COMMAND_EXECUTED; curarg.clear(); } break; case ' ': case ',': case '\t': if(state == STATE_EATING_SPACES_IN_ARG && curarg.empty() && ch == ',') throw std::runtime_error("Invalid Syntax"); else if(state == STATE_ARGUMENT) // Space ends argument { stack.back().push_back(curarg); curarg.clear(); } if ((state == STATE_EATING_SPACES_IN_BRACKETS || state == STATE_ARGUMENT) && ch == ',') { state = STATE_EATING_SPACES_IN_ARG; break; } state = STATE_EATING_SPACES; break; default: curarg += ch; state = STATE_ARGUMENT; } break; case STATE_SINGLEQUOTED: // Single-quoted string switch(ch) { case '\'': state = STATE_ARGUMENT; break; default: curarg += ch; } break; case STATE_DOUBLEQUOTED: // Double-quoted string switch(ch) { case '"': state = STATE_ARGUMENT; break; case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break; default: curarg += ch; } break; case STATE_ESCAPE_OUTER: // '\' outside quotes curarg += ch; state = STATE_ARGUMENT; break; case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself curarg += ch; state = STATE_DOUBLEQUOTED; break; } } switch(state) // final state { case STATE_COMMAND_EXECUTED: if (lastResult.isStr()) strResult = lastResult.get_str(); else strResult = lastResult.write(2); case STATE_ARGUMENT: case STATE_EATING_SPACES: return true; default: // ERROR to end in one of the other states return false; } }
int CommandLineRPC(int argc, char *argv[]) { std::string strPrint; int nRet = 0; try { // Skip switches while (argc > 1 && IsSwitchChar(argv[1][0])) { argc--; argv++; } // Method if (argc < 2) throw std::runtime_error("too few parameters"); std::string strMethod = argv[1]; // Parameters default to strings std::vector<std::string> strParams(&argv[2], &argv[argc]); json_spirit::Array params = RPCConvertValues(strMethod, strParams); // Execute json_spirit::Object reply = CallRPC(strMethod, params); // Parse reply const json_spirit::Value& result = find_value(reply, "result"); const json_spirit::Value& error = find_value(reply, "error"); if (error.type() != json_spirit::null_type) { // Error strPrint = "error: " + write_string(error, false); int code = find_value(error.get_obj(), "code").get_int(); nRet = abs(code); } else { // Result if (result.type() == json_spirit::null_type) strPrint = ""; else if (result.type() == json_spirit::str_type) strPrint = result.get_str(); else strPrint = write_string(result, true); } } catch (boost::thread_interrupted) { throw; } catch (std::exception& e) { strPrint = std::string("error: ") + e.what(); nRet = abs(RPC_MISC_ERROR); } catch (...) { PrintExceptionContinue(NULL, "CommandLineRPC()"); throw; } if (strPrint != "") { fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str()); } return nRet; }
bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut) { std::vector< std::vector<std::string> > stack; stack.push_back(std::vector<std::string>()); enum CmdParseState { STATE_EATING_SPACES, STATE_EATING_SPACES_IN_ARG, STATE_EATING_SPACES_IN_BRACKETS, STATE_ARGUMENT, STATE_SINGLEQUOTED, STATE_DOUBLEQUOTED, STATE_ESCAPE_OUTER, STATE_ESCAPE_DOUBLEQUOTED, STATE_COMMAND_EXECUTED, STATE_COMMAND_EXECUTED_INNER } state = STATE_EATING_SPACES; std::string curarg; UniValue lastResult; unsigned nDepthInsideSensitive = 0; size_t filter_begin_pos = 0, chpos; std::vector<std::pair<size_t, size_t>> filter_ranges; auto add_to_current_stack = [&](const std::string& strArg) { if (stack.back().empty() && (!nDepthInsideSensitive) && historyFilter.contains(QString::fromStdString(strArg), Qt::CaseInsensitive)) { nDepthInsideSensitive = 1; filter_begin_pos = chpos; } // Make sure stack is not empty before adding something if (stack.empty()) { stack.push_back(std::vector<std::string>()); } stack.back().push_back(strArg); }; auto close_out_params = [&]() { if (nDepthInsideSensitive) { if (!--nDepthInsideSensitive) { assert(filter_begin_pos); filter_ranges.push_back(std::make_pair(filter_begin_pos, chpos)); filter_begin_pos = 0; } } stack.pop_back(); }; std::string strCommandTerminated = strCommand; if (strCommandTerminated.back() != '\n') strCommandTerminated += "\n"; for (chpos = 0; chpos < strCommandTerminated.size(); ++chpos) { char ch = strCommandTerminated[chpos]; switch(state) { case STATE_COMMAND_EXECUTED_INNER: case STATE_COMMAND_EXECUTED: { bool breakParsing = true; switch(ch) { case '[': curarg.clear(); state = STATE_COMMAND_EXECUTED_INNER; break; default: if (state == STATE_COMMAND_EXECUTED_INNER) { if (ch != ']') { // append char to the current argument (which is also used for the query command) curarg += ch; break; } if (curarg.size() && fExecute) { // if we have a value query, query arrays with index and objects with a string key UniValue subelement; if (lastResult.isArray()) { for(char argch: curarg) if (!std::isdigit(argch)) throw std::runtime_error("Invalid result query"); subelement = lastResult[atoi(curarg.c_str())]; } else if (lastResult.isObject()) subelement = find_value(lastResult, curarg); else throw std::runtime_error("Invalid result query"); //no array or object: abort lastResult = subelement; } state = STATE_COMMAND_EXECUTED; break; } // don't break parsing when the char is required for the next argument breakParsing = false; // pop the stack and return the result to the current command arguments close_out_params(); // don't stringify the json in case of a string to avoid doublequotes if (lastResult.isStr()) curarg = lastResult.get_str(); else curarg = lastResult.write(2); // if we have a non empty result, use it as stack argument otherwise as general result if (curarg.size()) { if (stack.size()) add_to_current_stack(curarg); else strResult = curarg; } curarg.clear(); // assume eating space state state = STATE_EATING_SPACES; } if (breakParsing) break; } case STATE_ARGUMENT: // In or after argument case STATE_EATING_SPACES_IN_ARG: case STATE_EATING_SPACES_IN_BRACKETS: case STATE_EATING_SPACES: // Handle runs of whitespace switch(ch) { case '"': state = STATE_DOUBLEQUOTED; break; case '\'': state = STATE_SINGLEQUOTED; break; case '\\': state = STATE_ESCAPE_OUTER; break; case '(': case ')': case '\n': if (state == STATE_EATING_SPACES_IN_ARG) throw std::runtime_error("Invalid Syntax"); if (state == STATE_ARGUMENT) { if (ch == '(' && stack.size() && stack.back().size() > 0) { if (nDepthInsideSensitive) { ++nDepthInsideSensitive; } stack.push_back(std::vector<std::string>()); } // don't allow commands after executed commands on baselevel if (!stack.size()) throw std::runtime_error("Invalid Syntax"); add_to_current_stack(curarg); curarg.clear(); state = STATE_EATING_SPACES_IN_BRACKETS; } if ((ch == ')' || ch == '\n') && stack.size() > 0) { if (fExecute) { // Convert argument list to JSON objects in method-dependent way, // and pass it along with the method name to the dispatcher. JSONRPCRequest req; req.params = RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end())); req.strMethod = stack.back()[0]; lastResult = tableRPC.execute(req); } state = STATE_COMMAND_EXECUTED; curarg.clear(); } break; case ' ': case ',': case '\t': if(state == STATE_EATING_SPACES_IN_ARG && curarg.empty() && ch == ',') throw std::runtime_error("Invalid Syntax"); else if(state == STATE_ARGUMENT) // Space ends argument { add_to_current_stack(curarg); curarg.clear(); } if ((state == STATE_EATING_SPACES_IN_BRACKETS || state == STATE_ARGUMENT) && ch == ',') { state = STATE_EATING_SPACES_IN_ARG; break; } state = STATE_EATING_SPACES; break; default: curarg += ch; state = STATE_ARGUMENT; } break; case STATE_SINGLEQUOTED: // Single-quoted string switch(ch) { case '\'': state = STATE_ARGUMENT; break; default: curarg += ch; } break; case STATE_DOUBLEQUOTED: // Double-quoted string switch(ch) { case '"': state = STATE_ARGUMENT; break; case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break; default: curarg += ch; } break; case STATE_ESCAPE_OUTER: // '\' outside quotes curarg += ch; state = STATE_ARGUMENT; break; case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself curarg += ch; state = STATE_DOUBLEQUOTED; break; } } if (pstrFilteredOut) { if (STATE_COMMAND_EXECUTED == state) { assert(!stack.empty()); close_out_params(); } *pstrFilteredOut = strCommand; for (auto i = filter_ranges.rbegin(); i != filter_ranges.rend(); ++i) { pstrFilteredOut->replace(i->first, i->second - i->first, "(…)"); } } switch(state) // final state { case STATE_COMMAND_EXECUTED: if (lastResult.isStr()) strResult = lastResult.get_str(); else strResult = lastResult.write(2); case STATE_ARGUMENT: case STATE_EATING_SPACES: return true; default: // ERROR to end in one of the other states return false; } }