/* Copyright (C) 2003 MySQL AB 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 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "CommandInterpreter.hpp" #include <string.h> #include <ctype.h> #include "MgmtSrvr.hpp" #include "MgmtErrorReporter.hpp" #include <NdbOut.hpp> #include "convertStrToInt.hpp" #include <EventLogger.hpp> #include <signaldata/SetLogLevelOrd.hpp> #include "ConfigInfo.hpp" #include <version.h> #include <m_string.h> //****************************************************************************** //****************************************************************************** CommandInterpreter::CommandInterpreter(MgmtSrvr& mgmtSrvr) : _mgmtSrvr(mgmtSrvr) { } bool emptyString(const char* s) { if (s == NULL) { return true; } for (unsigned int i = 0; i < strlen(s); ++i) { if (! isspace(s[i])) { return false; } } return true; } class AutoPtr { public: AutoPtr(void * ptr) : m_ptr(ptr) {} ~AutoPtr() { free(m_ptr);} private: void * m_ptr; }; const char *CommandInterpreter::get_error_text(int err_no) { return _mgmtSrvr.getErrorText(err_no, m_err_str, sizeof(m_err_str)); } //***************************************************************************** //***************************************************************************** int CommandInterpreter::readAndExecute() { char* _line = readline_gets(); char * line; if(_line == NULL) { ndbout << endl; return true; } line = strdup(_line); AutoPtr ptr(line); if (emptyString(line)) { return true; } for (unsigned int i = 0; i < strlen(line); ++i) { line[i] = toupper(line[i]); } // if there is anything in the line proceed char* firstToken = strtok(line, " "); char* allAfterFirstToken = strtok(NULL, "\0"); if (strcmp(firstToken, "ALL") == 0) { analyseAfterFirstToken(-1, allAfterFirstToken); } else if(strcmp(firstToken, "QUIT") == 0 || strcmp(firstToken, "EXIT") == 0 || strcmp(firstToken, "BYE") == 0){ return false; } else { // First token should be a digit, process ID int processId; if (! convert(firstToken, processId)) { ndbout << "Invalid command: " << _line << "." << endl; return true; } if (processId < 0) { ndbout << "Invalid process ID: " << firstToken << "." << endl; return true; } analyseAfterFirstToken(processId, allAfterFirstToken); } // else return true; } static const CommandInterpreter::CommandFunctionPair commands[] = { { "TRACE", &CommandInterpreter::executeTrace } ,{ "LOGIN", &CommandInterpreter::executeLogIn } ,{ "LOGOUT", &CommandInterpreter::executeLogOut } ,{ "LOGOFF", &CommandInterpreter::executeLogOff } }; //***************************************************************************** //***************************************************************************** void CommandInterpreter::analyseAfterFirstToken(int processId, char* allAfterFirstToken) { if (emptyString(allAfterFirstToken)) { if (processId == -1) { ndbout << "Expected a command after ALL." << endl; } else { ndbout << "Expected a command after process ID." << endl; } return; } char* secondToken = strtok(allAfterFirstToken, " "); char* allAfterSecondToken = strtok(NULL, "\0"); const int tmpSize = sizeof(commands)/sizeof(CommandFunctionPair); ExecuteFunction fun = 0; const char * command = 0; for(int i = 0; i<tmpSize; i++){ if(strcmp(secondToken, commands[i].command) == 0){ fun = commands[i].executeFunction; command = commands[i].command; break; } } if(fun == 0){ ndbout << "Invalid command: " << secondToken << "." << endl; return; } if(processId == -1){ executeForAll(command, fun, allAfterSecondToken); } else { ndbout << "Executing " << command << " on node: " << processId << endl << endl; (this->*fun)(processId, allAfterSecondToken, false); ndbout << endl; } } void CommandInterpreter::executeForAll(const char * cmd, ExecuteFunction fun, const char * allAfterSecondToken){ NodeId nodeId = 0; while(_mgmtSrvr.getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)){ ndbout << "Executing " << cmd << " on node: " << nodeId << endl << endl; (this->*fun)(nodeId, allAfterSecondToken, true); ndbout << endl; } } //***************************************************************************** //***************************************************************************** bool CommandInterpreter::parseBlockSpecification(const char* allAfterLog, Vector<BaseString>& blocks) { // Parse: [BLOCK = {ALL|<blockName>+}] if (emptyString(allAfterLog)) { return true; } // Copy allAfterLog since strtok will modify it char* newAllAfterLog = strdup(allAfterLog); char* firstTokenAfterLog = strtok(newAllAfterLog, " "); for (unsigned int i = 0; i < strlen(firstTokenAfterLog); ++i) { firstTokenAfterLog[i] = toupper(firstTokenAfterLog[i]); } if (strcmp(firstTokenAfterLog, "BLOCK") != 0) { ndbout << "Unexpected value: " << firstTokenAfterLog << ". Expected BLOCK." << endl; free(newAllAfterLog); return false; } char* allAfterFirstToken = strtok(NULL, "\0"); if (emptyString(allAfterFirstToken)) { ndbout << "Expected =." << endl; free(newAllAfterLog); return false; } char* secondTokenAfterLog = strtok(allAfterFirstToken, " "); if (strcmp(secondTokenAfterLog, "=") != 0) { ndbout << "Unexpected value: " << secondTokenAfterLog << ". Expected =." << endl; free(newAllAfterLog); return false; } char* blockName = strtok(NULL, " "); bool all = false; if (blockName != NULL && (strcmp(blockName, "ALL") == 0)) { all = true; } while (blockName != NULL) { blocks.push_back(BaseString(blockName)); blockName = strtok(NULL, " "); } if (blocks.size() == 0) { ndbout << "No block specified." << endl; free(newAllAfterLog); return false; } if (blocks.size() > 1 && all) { // More than "ALL" specified ndbout << "Nothing expected after ALL." << endl; free(newAllAfterLog); return false; } free(newAllAfterLog); return true; } void CommandInterpreter::executeLogIn(int processId, const char* parameters, bool all) { (void)all; // Don't want compiler warning Vector<BaseString> blocks; if (! parseBlockSpecification(parameters, blocks)) { return; } int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::In, blocks); if (result != 0) { ndbout << get_error_text(result) << endl; } } //****************************************************************************** //****************************************************************************** void CommandInterpreter::executeLogOut(int processId, const char* parameters, bool all) { (void)all; // Don't want compiler warning Vector<BaseString> blocks; if (! parseBlockSpecification(parameters, blocks)) { return; } int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::Out, blocks); if (result != 0) { ndbout << get_error_text(result) << endl; } } //****************************************************************************** //****************************************************************************** void CommandInterpreter::executeLogOff(int processId, const char* parameters, bool all) { (void)all; // Don't want compiler warning Vector<BaseString> blocks; if (! parseBlockSpecification(parameters, blocks)) { return; } int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::Off, blocks); if (result != 0) { ndbout << get_error_text(result) << endl; } } void CommandInterpreter::executeTrace(int processId, const char* parameters, bool all) { (void)all; // Don't want compiler warning if (emptyString(parameters)) { ndbout << "Missing trace number." << endl; return; } char* newpar = strdup(parameters); char* firstParameter = strtok(newpar, " "); int traceNo; if (! convert(firstParameter, traceNo)) { ndbout << "Expected an integer." << endl; free(newpar); return; } char* allAfterFirstParameter = strtok(NULL, "\0"); if (! emptyString(allAfterFirstParameter)) { ndbout << "Nothing expected after trace number." << endl; free(newpar); return; } int result = _mgmtSrvr.setTraceNo(processId, traceNo); if (result != 0) { ndbout << get_error_text(result) << endl; } free(newpar); }