"Fossies" - the Fresh Open Source Software Archive

Member "netxms-3.1.300/src/agent/core/actions.cpp" (7 Jan 2020, 14415 Bytes) of package /linux/misc/netxms-3.1.300.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "actions.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.0.2357_vs_3.1.241.

    1 /*
    2 ** NetXMS multiplatform core agent
    3 ** Copyright (C) 2003-2014 Victor Kirhenshtein
    4 **
    5 ** This program is free software; you can redistribute it and/or modify
    6 ** it under the terms of the GNU General Public License as published by
    7 ** the Free Software Foundation; either version 2 of the License, or
    8 ** (at your option) any later version.
    9 **
   10 ** This program is distributed in the hope that it will be useful,
   11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
   12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13 ** GNU General Public License for more details.
   14 **
   15 ** You should have received a copy of the GNU General Public License
   16 ** along with this program; if not, write to the Free Software
   17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   18 **
   19 ** File: actions.cpp
   20 **
   21 **/
   22 
   23 #include "nxagentd.h"
   24 
   25 
   26 //
   27 // Static data
   28 //
   29 
   30 static ACTION *m_pActionList = NULL;
   31 static UINT32 m_dwNumActions = 0;
   32 
   33 /**
   34  * Agent command executor default constructor
   35  */
   36 AgentActionExecutor::AgentActionExecutor() : ProcessExecutor(NULL)
   37 {
   38    m_requestId = 0;
   39    m_session = NULL;
   40    m_args = NULL;
   41 }
   42 
   43 /**
   44  * Agent command executor destructor
   45  */
   46 AgentActionExecutor::~AgentActionExecutor()
   47 {
   48    delete(m_args);
   49    if (m_session != NULL)
   50       m_session->decRefCount();
   51 }
   52 
   53 /**
   54  * Agent action executor creator
   55  */
   56 AgentActionExecutor *AgentActionExecutor::createAgentExecutor(const TCHAR *cmd, const StringList *args)
   57 {
   58    AgentActionExecutor *executor = new AgentActionExecutor();
   59    executor->m_cmd = MemCopyString(cmd);
   60    executor->m_args = new StringList(args);
   61    executor->m_session = new VirtualSession(0);
   62 
   63    UINT32 rcc = executor->findAgentAction();
   64 
   65    if (rcc == ERR_SUCCESS)
   66    {
   67       delete(executor);
   68       return NULL;
   69    }
   70 
   71    return executor;
   72 }
   73 
   74 /**
   75  * Agent action executor creator
   76  */
   77 AgentActionExecutor *AgentActionExecutor::createAgentExecutor(NXCPMessage *request, AbstractCommSession *session, UINT32 *rcc)
   78 {
   79    AgentActionExecutor *executor = new AgentActionExecutor();
   80    executor->m_sendOutput = request->getFieldAsBoolean(VID_RECEIVE_OUTPUT);
   81    executor->m_requestId = request->getId();
   82    executor->m_session = session;
   83    executor->m_session->incRefCount();
   84    executor->m_cmd = request->getFieldAsString(VID_ACTION_NAME);
   85 
   86    UINT32 count = request->getFieldAsUInt32(VID_NUM_ARGS);
   87    if (count > 0)
   88    {
   89       executor->m_args = new StringList();
   90       UINT32 fieldId = VID_ACTION_ARG_BASE;
   91       for(UINT32 i = 0; i < count; i++)
   92          executor->m_args->addPreallocated(request->getFieldAsString(fieldId++));
   93    }
   94    *rcc = executor->findAgentAction();
   95 
   96    if (*rcc == ERR_SUCCESS)
   97    {
   98       delete executor;
   99       return NULL;
  100    }
  101 
  102    return executor;
  103 }
  104 
  105 UINT32 AgentActionExecutor::findAgentAction()
  106 {
  107    UINT32 rcc = ERR_UNKNOWN_PARAMETER;
  108    for(UINT32 i = 0; i < m_dwNumActions; i++)
  109    {
  110       if (!_tcsicmp(m_pActionList[i].szName, m_cmd))
  111       {
  112          MemFree(m_cmd);
  113          m_cmd = MemCopyString(m_pActionList[i].handler.pszCmdLine);
  114          switch(m_pActionList[i].iType)
  115          {
  116             case AGENT_ACTION_EXEC:
  117             case AGENT_ACTION_SHELLEXEC:
  118                rcc = ERR_PROCESSING;
  119                substituteArgs();
  120                break;
  121             case AGENT_ACTION_SUBAGENT:
  122                rcc = m_pActionList[i].handler.sa.fpHandler(m_cmd, m_args, m_pActionList[i].handler.sa.pArg, m_session);
  123                break;
  124             default:
  125                rcc = ERR_NOT_IMPLEMENTED;
  126                break;
  127          }
  128          DebugPrintf(4, _T("Executing action %s of type %d"), m_cmd, m_pActionList[i].iType);
  129          break;
  130       }
  131    }
  132 
  133    if (rcc == ERR_UNKNOWN_PARAMETER)
  134       rcc = ExecuteActionByExtSubagent(m_cmd, m_args, m_session, 0, false);
  135 
  136    return rcc;
  137 }
  138 
  139 void AgentActionExecutor::stopAction(AgentActionExecutor *executor)
  140 {
  141    if (executor->isRunning())
  142    {
  143       executor->stop();
  144       DebugPrintf(6, _T("Agent action: %s timed out"), executor->getCommand());
  145    }
  146    delete(executor);
  147 }
  148 
  149 /**
  150  * Substitute agent action arguments
  151  */
  152 void AgentActionExecutor::substituteArgs()
  153 {
  154    if (m_args != NULL && m_args->size() > 0)
  155    {
  156       StringBuffer cmd(m_cmd);
  157       TCHAR macro[3];
  158       for(int i = 0; i < m_args->size() && i <= 9; i++)
  159       {
  160          _sntprintf(macro, 3, _T("$%d"), i + 1);
  161          cmd.replace(macro, m_args->get(i));
  162       }
  163       MemFree(m_cmd);
  164       m_cmd = MemCopyString(cmd);
  165    }
  166 }
  167 
  168 /**
  169  * Send output to console
  170  */
  171 void AgentActionExecutor::onOutput(const char *text)
  172 {
  173    NXCPMessage msg(m_session->getProtocolVersion());
  174    msg.setId(m_requestId);
  175    msg.setCode(CMD_COMMAND_OUTPUT);
  176 #ifdef UNICODE
  177    TCHAR *buffer = WideStringFromMBStringSysLocale(text);
  178    msg.setField(VID_MESSAGE, buffer);
  179    m_session->sendMessage(&msg);
  180    MemFree(buffer);
  181 #else
  182    msg.setField(VID_MESSAGE, text);
  183    m_session->sendMessage(&msg);
  184 #endif
  185 }
  186 
  187 /**
  188  * Send message to make console stop listening to output
  189  */
  190 void AgentActionExecutor::endOfOutput()
  191 {
  192    NXCPMessage msg(m_session->getProtocolVersion());
  193    msg.setId(m_requestId);
  194    msg.setCode(CMD_COMMAND_OUTPUT);
  195    msg.setEndOfSequence();
  196    m_session->sendMessage(&msg);
  197 }
  198 
  199 /**
  200  * Add action
  201  */
  202 BOOL AddAction(const TCHAR *pszName, int iType, const TCHAR *pArg,
  203                LONG (*fpHandler)(const TCHAR *, const StringList *, const TCHAR *, AbstractCommSession *),
  204                const TCHAR *pszSubAgent, const TCHAR *pszDescription)
  205 {
  206    UINT32 i;
  207 
  208    // Check if action with given name already registered
  209    for(i = 0; i < m_dwNumActions; i++)
  210       if (!_tcsicmp(m_pActionList[i].szName, pszName))
  211          break;
  212 
  213    if (i == m_dwNumActions)
  214    {
  215       // Create new entry in action list
  216       m_dwNumActions++;
  217       m_pActionList = (ACTION *)realloc(m_pActionList, sizeof(ACTION) * m_dwNumActions);
  218       _tcslcpy(m_pActionList[i].szName, pszName, MAX_PARAM_NAME);
  219       m_pActionList[i].iType = iType;
  220       nx_strncpy(m_pActionList[i].szDescription, pszDescription, MAX_DB_STRING);
  221       switch(iType)
  222       {
  223          case AGENT_ACTION_EXEC:
  224          case AGENT_ACTION_SHELLEXEC:
  225             m_pActionList[i].handler.pszCmdLine = _tcsdup(pArg);
  226             break;
  227          case AGENT_ACTION_SUBAGENT:
  228             m_pActionList[i].handler.sa.fpHandler = fpHandler;
  229             m_pActionList[i].handler.sa.pArg = pArg;
  230             _tcslcpy(m_pActionList[i].handler.sa.szSubagentName, pszSubAgent,MAX_PATH);
  231             break;
  232          default:
  233             break;
  234       }
  235    }
  236    else
  237    {
  238       // Update existing entry in action list
  239       _tcslcpy(m_pActionList[i].szDescription, pszDescription, MAX_DB_STRING);
  240       if ((m_pActionList[i].iType == AGENT_ACTION_EXEC) || (m_pActionList[i].iType == AGENT_ACTION_SHELLEXEC))
  241          MemFree(m_pActionList[i].handler.pszCmdLine);
  242       m_pActionList[i].iType = iType;
  243       switch(iType)
  244       {
  245          case AGENT_ACTION_EXEC:
  246          case AGENT_ACTION_SHELLEXEC:
  247             m_pActionList[i].handler.pszCmdLine = _tcsdup(pArg);
  248             break;
  249          case AGENT_ACTION_SUBAGENT:
  250             m_pActionList[i].handler.sa.fpHandler = fpHandler;
  251             m_pActionList[i].handler.sa.pArg = pArg;
  252             _tcslcpy(m_pActionList[i].handler.sa.szSubagentName, pszSubAgent,MAX_PATH);
  253             break;
  254          default:
  255             break;
  256       }
  257    }
  258    return TRUE;
  259 }
  260 
  261 /**
  262  * Add action from config record
  263  * Accepts string of format <action_name>:<command_line>
  264  */
  265 BOOL AddActionFromConfig(TCHAR *pszLine, BOOL bShellExec) //to be TCHAR
  266 {
  267    TCHAR *pCmdLine;
  268 
  269    pCmdLine = _tcschr(pszLine, _T(':'));
  270    if (pCmdLine == NULL)
  271       return FALSE;
  272    *pCmdLine = 0;
  273    pCmdLine++;
  274    StrStrip(pszLine);
  275    StrStrip(pCmdLine);
  276    return AddAction(pszLine, bShellExec ? AGENT_ACTION_SHELLEXEC : AGENT_ACTION_EXEC, pCmdLine, NULL, NULL, _T(""));
  277 }
  278 
  279 /**
  280  * Execute action
  281  */
  282 UINT32 ExecAction(const TCHAR *action, const StringList *args, AbstractCommSession *session)
  283 {
  284    UINT32 rcc = ERR_UNKNOWN_PARAMETER;
  285 
  286    for(UINT32 i = 0; i < m_dwNumActions; i++)
  287       if (!_tcsicmp(m_pActionList[i].szName, action))
  288       {
  289          DebugPrintf(4, _T("Executing action %s of type %d"), action, m_pActionList[i].iType);
  290          switch(m_pActionList[i].iType)
  291          {
  292             case AGENT_ACTION_EXEC:
  293                rcc = ExecuteCommand(m_pActionList[i].handler.pszCmdLine, args, NULL);
  294                break;
  295             case AGENT_ACTION_SHELLEXEC:
  296                rcc = ExecuteShellCommand(m_pActionList[i].handler.pszCmdLine, args);
  297                break;
  298             case AGENT_ACTION_SUBAGENT:
  299                rcc = m_pActionList[i].handler.sa.fpHandler(action, args, m_pActionList[i].handler.sa.pArg, session);
  300                break;
  301             default:
  302                rcc = ERR_NOT_IMPLEMENTED;
  303                break;
  304          }
  305          break;
  306       }
  307 
  308    if (rcc == ERR_UNKNOWN_PARAMETER)
  309       rcc = ExecuteActionByExtSubagent(action, args, session, 0, false);
  310 
  311    return rcc;
  312 }
  313 
  314 /**
  315  * Action executor data
  316  */
  317 class ActionExecutorData
  318 {
  319 public:
  320    TCHAR *m_cmdLine;
  321    StringList *m_args;
  322    AbstractCommSession *m_session;
  323    UINT32 m_requestId;
  324 
  325    ActionExecutorData(const TCHAR *cmd, StringList *args, AbstractCommSession *session, UINT32 requestId)
  326    {
  327       m_cmdLine = _tcsdup(cmd);
  328       m_args = args;
  329       m_session = session;
  330       m_session->incRefCount();
  331       m_requestId = requestId;
  332    }
  333 
  334    ~ActionExecutorData()
  335    {
  336       m_session->decRefCount();
  337       free(m_cmdLine);
  338       delete m_args;
  339    }
  340 };
  341 
  342 /**
  343  * Action executor (for actions with output)
  344  */
  345 static THREAD_RESULT THREAD_CALL ActionExecutionThread(void *arg)
  346 {
  347    ActionExecutorData *data = (ActionExecutorData *)arg;
  348 
  349    NXCPMessage msg(data->m_session->getProtocolVersion());
  350    msg.setCode(CMD_REQUEST_COMPLETED);
  351    msg.setId(data->m_requestId);
  352    msg.setField(VID_RCC, ERR_SUCCESS);
  353    data->m_session->sendMessage(&msg);
  354 
  355    msg.setCode(CMD_COMMAND_OUTPUT);
  356    msg.deleteAllFields();
  357 
  358    DebugPrintf(4, _T("ActionExecutionThread: Expanding command \"%s\""), data->m_cmdLine);
  359 
  360    // Substitute $1 .. $9 with actual arguments
  361    if (data->m_args != NULL)
  362    {
  363       StringBuffer cmdLine;
  364       for(const TCHAR *sptr = data->m_cmdLine; *sptr != 0; sptr++)
  365          if (*sptr == _T('$'))
  366          {
  367             sptr++;
  368             if (*sptr == 0)
  369                break;   // Single $ character at the end of line
  370             if ((*sptr >= _T('1')) && (*sptr <= _T('9')))
  371             {
  372                int argNum = *sptr - _T('1');
  373                if (argNum < data->m_args->size())
  374                {
  375                   cmdLine.append(data->m_args->get(argNum));
  376                }
  377             }
  378             else
  379             {
  380                cmdLine.append(*sptr);
  381             }
  382          }
  383          else
  384          {
  385             cmdLine.append(*sptr);
  386          }
  387       free(data->m_cmdLine);
  388       data->m_cmdLine = _tcsdup(cmdLine.getBuffer());
  389    }
  390 
  391    data->m_session->debugPrintf(4, _T("ActionExecutionThread: Executing \"%s\""), data->m_cmdLine);
  392    FILE *pipe = _tpopen(data->m_cmdLine, _T("r"));
  393    if (pipe != NULL)
  394    {
  395       while(true)
  396       {
  397          TCHAR line[4096];
  398 
  399          TCHAR *ret = safe_fgetts(line, 4096, pipe);
  400          if (ret == NULL)
  401             break;
  402 
  403          msg.setField(VID_MESSAGE, line);
  404          data->m_session->sendMessage(&msg);
  405          msg.deleteAllFields();
  406       }
  407       _pclose(pipe);
  408       data->m_session->debugPrintf(4, _T("ActionExecutionThread: command completed"));
  409    }
  410    else
  411    {
  412       data->m_session->debugPrintf(4, _T("ActionExecutionThread: popen() failed"));
  413 
  414       TCHAR buffer[1024];
  415       _sntprintf(buffer, 1024, _T("Failed to execute command %s"), data->m_cmdLine);
  416       msg.setField(VID_MESSAGE, buffer);
  417    }
  418 
  419    msg.setEndOfSequence();
  420    data->m_session->sendMessage(&msg);
  421    data->m_session->decRefCount();
  422 
  423    delete data;
  424    return THREAD_OK;
  425 }
  426 
  427 /**
  428  * Execute action and send output to server
  429  */
  430 UINT32 ExecActionWithOutput(AbstractCommSession *session, UINT32 requestId, const TCHAR *action, StringList *args)
  431 {
  432    UINT32 rcc = ERR_UNKNOWN_PARAMETER;
  433 
  434    for(UINT32 i = 0; i < m_dwNumActions; i++)
  435    {
  436       if (!_tcsicmp(m_pActionList[i].szName, action))
  437       {
  438          session->debugPrintf(4, _T("Executing action %s of type %d with output"), action, m_pActionList[i].iType);
  439          switch(m_pActionList[i].iType)
  440          {
  441             case AGENT_ACTION_EXEC:
  442             case AGENT_ACTION_SHELLEXEC:
  443                session->incRefCount();
  444                ThreadCreate(ActionExecutionThread, 0, new ActionExecutorData(m_pActionList[i].handler.pszCmdLine, args, session, requestId));
  445                rcc = ERR_SUCCESS;
  446                break;
  447             case AGENT_ACTION_SUBAGENT:
  448                rcc = ERR_INTERNAL_ERROR;
  449                break;
  450             default:
  451                rcc = ERR_NOT_IMPLEMENTED;
  452                break;
  453          }
  454          break;
  455       }
  456    }
  457 
  458    if (rcc == ERR_UNKNOWN_PARAMETER)
  459    {
  460       rcc = ExecuteActionByExtSubagent(action, args, session, requestId, true);
  461       delete args;
  462    }
  463    else if (rcc != ERR_SUCCESS)
  464    {
  465       delete args;
  466    }
  467    return rcc;
  468 }
  469 
  470 /**
  471  * List of available actions
  472  */
  473 LONG H_ActionList(const TCHAR *cmd, const TCHAR *arg, StringList *value, AbstractCommSession *session)
  474 {
  475    TCHAR szBuffer[1024];
  476    for(UINT32 i = 0; i < m_dwNumActions; i++)
  477    {
  478       _sntprintf(szBuffer, 1024, _T("%s %d \"%s\""), m_pActionList[i].szName, m_pActionList[i].iType,
  479                  m_pActionList[i].iType == AGENT_ACTION_SUBAGENT ?
  480                     m_pActionList[i].handler.sa.szSubagentName :    
  481                     m_pActionList[i].handler.pszCmdLine);
  482         value->add(szBuffer);
  483    }
  484    ListActionsFromExtSubagents(value);
  485    return SYSINFO_RC_SUCCESS;
  486 }
  487 
  488 /**
  489  * Put list of supported actions into NXCP message
  490  */
  491 void GetActionList(NXCPMessage *msg)
  492 {
  493    UINT32 fieldId = VID_ACTION_LIST_BASE;
  494    for(UINT32 i = 0; i < m_dwNumActions; i++)
  495    {
  496       msg->setField(fieldId++, m_pActionList[i].szName);
  497       msg->setField(fieldId++, m_pActionList[i].szDescription);
  498       msg->setField(fieldId++, (INT16)m_pActionList[i].iType);
  499       msg->setField(fieldId++, (m_pActionList[i].iType == AGENT_ACTION_SUBAGENT) ? m_pActionList[i].handler.sa.szSubagentName : m_pActionList[i].handler.pszCmdLine);
  500    }
  501 
  502    UINT32 count = m_dwNumActions;
  503     ListActionsFromExtSubagents(msg, &fieldId, &count);
  504    msg->setField(VID_NUM_ACTIONS, count);
  505 }