diff --git a/include/actions.hpp b/include/actions.hpp index d7fa8d8c1..3a543cc30 100644 --- a/include/actions.hpp +++ b/include/actions.hpp @@ -57,6 +57,7 @@ class CAction E_AT_LOG_WARNING, E_AT_LOG_ERROR, E_AT_EXECUTE_CMD, + E_AT_VERIFY_CMD, E_AT_EXEC_INTCMD, E_AT_VAR_ADD, E_AT_VAR_SUBTRACT, diff --git a/src/actions.cpp b/src/actions.cpp index a216f4c51..ce7b1661b 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -111,6 +111,8 @@ void CAction::afficheInfo() } } else if (M_action == E_AT_EXECUTE_CMD) { printf("Type[%d] - command[%-32.32s]", M_action, M_message_str[0]); + } else if (M_action == E_AT_VERIFY_CMD) { + printf("Type[%d] - verify[%-32.32s]", M_action, M_message_str[0]); } else if (M_action == E_AT_EXEC_INTCMD) { printf("Type[%d] - intcmd[%-32.32s]", M_action, strIntCmd(M_IntCmd)); } else if (M_action == E_AT_LOG_TO_FILE) { diff --git a/src/call.cpp b/src/call.cpp index a44573db0..0be13506c 100644 --- a/src/call.cpp +++ b/src/call.cpp @@ -3243,6 +3243,29 @@ double call::get_rhs(CAction *currentAction) } } +void execute_system_shell_and_exit(char *x) +{ +// Execute shell in different ways via compiler check. +// This is required because cygwin wrongly returns true for system(0) +// even when the shell is not available +// For some reason if system is invoked when sh is not available the program seg faults. +// This is avoided by ifdef'ing out the system() call in favor of exec of cmd.exe on Windows. +#ifndef __CYGWIN + int ret = system(x); // second child runs + if(ret == -1) { + WARNING("system call error for %s",x); + } + TRACE_MSG("Exec of '%s' returned %d", x, WEXITSTATUS(ret)); + exit(WEXITSTATUS(ret)); + +#else + // sh not available, use exec(command) + int ret = execlp("cmd.exe", "cmd.exe", "/c", x, (char *) NULL); + ERROR_NO("Exec of 'cmd.exe /c %s' failed", x); +#endif + +} + call::T_ActionResult call::executeAction(const char* msg, message* curmsg) { CActions* actions; @@ -3671,8 +3694,11 @@ call::T_ActionResult call::executeAction(const char* msg, message* curmsg) } else if (currentAction->getActionType() == CAction::E_AT_LOG_ERROR) { char* x = createSendingMessage(currentAction->getMessage(), -2 /* do not add crlf*/); ERROR("%s", x); - } else if (currentAction->getActionType() == CAction::E_AT_EXECUTE_CMD) { + } else if ((currentAction->getActionType() == CAction::E_AT_EXECUTE_CMD) || + (currentAction->getActionType() == CAction::E_AT_VERIFY_CMD)) { char* x = createSendingMessage(currentAction->getMessage(), -2 /* do not add crlf*/); + bool verify_result = (currentAction->getActionType() == CAction::E_AT_VERIFY_CMD); + // TRACE_MSG("Trying to execute [%s]", x); pid_t l_pid; switch(l_pid = fork()) { @@ -3683,41 +3709,42 @@ call::T_ActionResult call::executeAction(const char* msg, message* curmsg) case 0: // first child process - execute the command - if((l_pid = fork()) < 0) { - ERROR_NO("Forking error child"); + if (verify_result) { + /* run command in this process and return exit code to waiting main sipp process */ + execute_system_shell_and_exit(x); } else { - if( l_pid == 0) { - int ret; - ret = system(x); // second child runs - if(ret == -1) { - WARNING("system call error for %s", x); + if((l_pid = fork()) < 0) { + ERROR_NO("Forking error child"); + } else { + if( l_pid == 0) { + int ret; + ret = system(x); // second child runs + if(ret == -1) { + WARNING("system call error for %s", x); + } } + exit(EXIT_OTHER); } - exit(EXIT_OTHER); } break; default: // parent process continue // reap first child immediately pid_t ret; - while ((ret=waitpid(l_pid, NULL, 0)) != l_pid) { + int status; + while ((ret=waitpid(l_pid, &status, 0)) != l_pid) { if (ret != -1) { - ERROR("waitpid returns %1ld for child %1ld", (long) ret, (long) l_pid); + ERROR("waitpid returns %1d for child %1d", ret,l_pid); } } - break; - } - } else if (currentAction->getActionType() == CAction::E_AT_EXEC_INTCMD) { - switch (currentAction->getIntCmd()) { - case CAction::E_INTCMD_STOP_ALL: - quitting = 1; - break; - case CAction::E_INTCMD_STOP_NOW: - sipp_exit(EXIT_TEST_RES_INTERNAL); - break; - case CAction::E_INTCMD_STOPCALL: - default: - return(call::E_AR_STOP_CALL); + if (verify_result) { + if (!WIFEXITED(status)) { + ERROR("'%s' did not exit normally (status = %d)", x, status); + } else if (WEXITSTATUS(status) != EXIT_SUCCESS) { + ERROR("'%s' returned result code %d", x, WEXITSTATUS(status)); + } + } + break; } #ifdef PCAPPLAY diff --git a/src/scenario.cpp b/src/scenario.cpp index 4236820aa..ada25728e 100644 --- a/src/scenario.cpp +++ b/src/scenario.cpp @@ -1618,6 +1618,9 @@ void scenario::parseAction(CActions *actions) if ((cptr = xp_get_value("command"))) { tmpAction->setActionType(CAction::E_AT_EXECUTE_CMD); tmpAction->setMessage(cptr); + } else if((cptr = xp_get_value((char *)"verify"))) { + tmpAction->setActionType(CAction::E_AT_VERIFY_CMD); + tmpAction->setMessage(cptr); } else if((cptr = xp_get_value("int_cmd"))) { CAction::T_IntCmdType type(CAction::E_INTCMD_STOPCALL); /* assume the default */