potential fix for subprocess execution (exit code was wonky)
parent
07a850dcae
commit
6fd80a31c5
|
@ -1,7 +1,7 @@
|
||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(ftests)
|
project(ftests)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++1z -O0 -DDEBUG=1")
|
||||||
set(SOURCE_FILES examplar.cpp src/loaders/loaders.cpp src/loaders/loaders.h src/json/jsoncpp.cpp src/loaders/JSON_Loader.cpp src/loaders/JSON_Loader.h src/loaders/helpers.cpp src/loaders/helpers.h src/loaders/Suite.cpp src/loaders/Suite.h src/loaders/Plan.cpp src/loaders/Plan.h src/loaders/Conf.cpp src/loaders/Conf.h src/loaders/Unit.cpp src/loaders/Unit.h src/loaders/Task.cpp src/loaders/Task.h src/sproc/Sproc.cpp src/sproc/Sproc.h)
|
set(SOURCE_FILES examplar.cpp src/loaders/loaders.cpp src/loaders/loaders.h src/json/jsoncpp.cpp src/loaders/JSON_Loader.cpp src/loaders/JSON_Loader.h src/loaders/helpers.cpp src/loaders/helpers.h src/loaders/Suite.cpp src/loaders/Suite.h src/loaders/Plan.cpp src/loaders/Plan.h src/loaders/Conf.cpp src/loaders/Conf.h src/loaders/Unit.cpp src/loaders/Unit.h src/loaders/Task.cpp src/loaders/Task.h src/sproc/Sproc.cpp src/sproc/Sproc.h)
|
||||||
|
|
||||||
add_executable(ftests ${SOURCE_FILES})
|
add_executable(ftests ${SOURCE_FILES})
|
|
@ -6,7 +6,7 @@
|
||||||
"rectifier": "/usr/bin/true",
|
"rectifier": "/usr/bin/true",
|
||||||
"active": true,
|
"active": true,
|
||||||
"required": true,
|
"required": true,
|
||||||
"rectify": false
|
"rectify": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "independent test 2",
|
"name": "independent test 2",
|
||||||
|
|
|
@ -114,12 +114,17 @@ void Plan::load_definitions( Suite unit_definitions, bool verbose )
|
||||||
void Plan::execute( bool verbose )
|
void Plan::execute( bool verbose )
|
||||||
{
|
{
|
||||||
// for each task in this plan
|
// for each task in this plan
|
||||||
for ( int i = 0; i < this->tasks.size(); i++ )
|
// for ( int i = 0; i < this->tasks.size(); i++ )
|
||||||
{
|
// {
|
||||||
if ( verbose ) {
|
// if ( verbose ) {
|
||||||
std::cout << "Executing task \"" << this->tasks[i].get_name() << "\"." << std::endl;
|
// std::cout << "Executing task \"" << this->tasks[i].get_name() << "\"." << std::endl;
|
||||||
}
|
std::cout << "Executing task \"" << this->tasks[0].get_name() << "\"." << std::endl;
|
||||||
this->tasks[i].execute( verbose );
|
// }
|
||||||
}
|
// this->tasks[i].execute( verbose );
|
||||||
|
this->tasks[0].execute( verbose );
|
||||||
|
|
||||||
|
// for testing a logic issue in Task.execute(), remove when done
|
||||||
|
// throw Plan_InvalidTaskIndex();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,12 +48,14 @@ void Suite::load_units_file( std::string filename, bool verbose )
|
||||||
{
|
{
|
||||||
// assemble the unit from json_root using the built-in value operator
|
// assemble the unit from json_root using the built-in value operator
|
||||||
tmp_U.load_root( this->json_root[ index ] );
|
tmp_U.load_root( this->json_root[ index ] );
|
||||||
|
if ( tmp_U.get_active() ) {
|
||||||
// append to this->units
|
// append to this->units
|
||||||
this->units.push_back( tmp_U );
|
this->units.push_back( tmp_U );
|
||||||
if ( verbose ) {
|
if ( verbose ) {
|
||||||
std::cout << "Added unit \"" << tmp_U.get_name() << "\" to Suite." << std::endl;
|
std::cout << "Added unit \"" << tmp_U.get_name() << "\" to Suite." << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Suite::get_unit - returns a contained Unit identified by name attribute.
|
/// Suite::get_unit - returns a contained Unit identified by name attribute.
|
||||||
|
|
|
@ -4,28 +4,33 @@
|
||||||
#include "../sproc/Sproc.h"
|
#include "../sproc/Sproc.h"
|
||||||
|
|
||||||
/// Task_InvalidDataStructure - Exception thrown when a Task is defined with invalid JSON.
|
/// Task_InvalidDataStructure - Exception thrown when a Task is defined with invalid JSON.
|
||||||
class Task_InvalidDataStructure: public std::runtime_error { public:
|
class Task_InvalidDataStructure: public std::runtime_error {
|
||||||
|
public:
|
||||||
Task_InvalidDataStructure(): std::runtime_error("Task: Attempted to access a member of a Task that is not set.") {}
|
Task_InvalidDataStructure(): std::runtime_error("Task: Attempted to access a member of a Task that is not set.") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Task_InvalidDataStructure - Exception thrown when a Task is defined with invalid JSON.
|
/// Task_InvalidDataStructure - Exception thrown when a Task is defined with invalid JSON.
|
||||||
class Task_NotReady: public std::runtime_error { public:
|
class Task_NotReady: public std::runtime_error {
|
||||||
|
public:
|
||||||
Task_NotReady(): std::runtime_error("Task: Attempted to access a unit of a Task that is not defined.") {}
|
Task_NotReady(): std::runtime_error("Task: Attempted to access a unit of a Task that is not defined.") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Task_RequiredButFailedTask - Exception thrown when a Task is failed but required, and rectification also failed.
|
/// Task_RequiredButFailedTask - Exception thrown when a Task is failed but required, and rectification also failed.
|
||||||
class Task_RequiredButFailedTask: public std::runtime_error { public:
|
class Task_RequiredButFailedTask: public std::runtime_error {
|
||||||
Task_RequiredButFailedTask(): std::runtime_error("Task: Attempted to access a unit of a Task that failed, but was required, and the corresponding rectification target also failed..") {}
|
public:
|
||||||
|
Task_RequiredButFailedTask(): std::runtime_error("Task: Attempted to execute a Task that failed and was required.") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Task_RequiredButFailedTask - Exception thrown when a Task is failed but required, and rectification also failed but returned with a zero exit code (dont try to fool the check).
|
/// Task_RequiredButFailedTask - Exception thrown when a Task is failed but required, and rectification also failed but returned with a zero exit code (dont try to fool the check).
|
||||||
class Task_RequiredButRectifierDoesNotHeal: public std::runtime_error { public:
|
class Task_RequiredButRectifierDoesNotHeal: public std::runtime_error {
|
||||||
|
public:
|
||||||
Task_RequiredButRectifierDoesNotHeal(): std::runtime_error("Task: The rectification script was executed and reported success, but did not actually heal the faulty condition of the Task target.") {}
|
Task_RequiredButRectifierDoesNotHeal(): std::runtime_error("Task: The rectification script was executed and reported success, but did not actually heal the faulty condition of the Task target.") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Task::Task() - Constructor for the Task class. The Task is the building block of a Plan indicating of which Unit to
|
/// Task::Task() - Constructor for the Task class. The Task is the building block of a Plan indicating of which Unit to
|
||||||
/// execute, and its dependencies on other units to have already been completed successfully.
|
/// execute, and its dependencies on other units to have already been completed successfully.
|
||||||
Task::Task() {
|
Task::Task()
|
||||||
|
{
|
||||||
// it hasn't executed yet.
|
// it hasn't executed yet.
|
||||||
this->complete = false;
|
this->complete = false;
|
||||||
|
|
||||||
|
@ -39,10 +44,10 @@ Task::Task() {
|
||||||
/// \param verbose - Whether to print verbose information to STDOUT.
|
/// \param verbose - Whether to print verbose information to STDOUT.
|
||||||
void Task::load_root(Json::Value loader_root, bool verbose )
|
void Task::load_root(Json::Value loader_root, bool verbose )
|
||||||
{
|
{
|
||||||
if ( loader_root.isMember("name") )
|
if ( loader_root.isMember("name") ) {
|
||||||
{
|
|
||||||
this->name = loader_root.get("name", "?").asString();
|
this->name = loader_root.get("name", "?").asString();
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
throw Task_InvalidDataStructure();
|
throw Task_InvalidDataStructure();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,14 +55,11 @@ void Task::load_root(Json::Value loader_root, bool verbose )
|
||||||
Json::Value des_dep_root = loader_root.get("dependencies", 0);
|
Json::Value des_dep_root = loader_root.get("dependencies", 0);
|
||||||
|
|
||||||
// iterate through each member of that obj
|
// iterate through each member of that obj
|
||||||
for ( int i = 0; i < des_dep_root.size(); i++ )
|
for ( int i = 0; i < des_dep_root.size(); i++ ) {
|
||||||
{
|
|
||||||
// add each string to dependencies
|
// add each string to dependencies
|
||||||
if ( des_dep_root[i].asString() != "" )
|
if ( des_dep_root[i].asString() != "" ) {
|
||||||
{
|
|
||||||
this->dependencies.push_back( des_dep_root[i].asString() );
|
this->dependencies.push_back( des_dep_root[i].asString() );
|
||||||
if ( verbose )
|
if ( verbose ) {
|
||||||
{
|
|
||||||
std::cout << "Added dependency \"" << des_dep_root[i].asString() << "\" to task \"" << this->get_name() << "\"." << std::endl;
|
std::cout << "Added dependency \"" << des_dep_root[i].asString() << "\" to task \"" << this->get_name() << "\"." << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,20 +79,21 @@ std::string Task::get_name()
|
||||||
void Task::load_definition( Unit selected_unit, bool verbose )
|
void Task::load_definition( Unit selected_unit, bool verbose )
|
||||||
{
|
{
|
||||||
this->definition = selected_unit;
|
this->definition = selected_unit;
|
||||||
if ( verbose )
|
if ( verbose ) {
|
||||||
{
|
|
||||||
std::cout << "Loaded definition \"" << selected_unit.get_name() << "\" for task \"" << this->get_name() << "\"." << std::endl;
|
std::cout << "Loaded definition \"" << selected_unit.get_name() << "\" for task \"" << this->get_name() << "\"." << std::endl;
|
||||||
}
|
}
|
||||||
this->defined = true;
|
this->defined = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Task::is_complete - Indicator if the task executed successfully.
|
/// Task::is_complete - Indicator if the task executed successfully.
|
||||||
bool Task::is_complete() {
|
bool Task::is_complete()
|
||||||
|
{
|
||||||
return this->complete;
|
return this->complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Task::has_definition - Indicator if the task has attached its definition from a Suite.
|
/// Task::has_definition - Indicator if the task has attached its definition from a Suite.
|
||||||
bool Task::has_definition() {
|
bool Task::has_definition()
|
||||||
|
{
|
||||||
return this->defined;
|
return this->defined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +106,9 @@ void Task::execute( bool verbose )
|
||||||
|
|
||||||
// PREWORK
|
// PREWORK
|
||||||
// throw if unit not coupled to all necessary values since Task is stateful (stateful is okay)
|
// throw if unit not coupled to all necessary values since Task is stateful (stateful is okay)
|
||||||
if (! this->has_definition() ) { throw Task_NotReady(); }
|
if (! this->has_definition() ) {
|
||||||
|
throw Task_NotReady();
|
||||||
|
}
|
||||||
|
|
||||||
// get the name
|
// get the name
|
||||||
std::string task_name = this->definition.get_name();
|
std::string task_name = this->definition.get_name();
|
||||||
|
@ -114,8 +119,7 @@ void Task::execute( bool verbose )
|
||||||
std::string target_command = this->definition.get_target();
|
std::string target_command = this->definition.get_target();
|
||||||
|
|
||||||
// if we're in verbose mode, do some verbose things
|
// if we're in verbose mode, do some verbose things
|
||||||
if ( verbose )
|
if ( verbose ) {
|
||||||
{
|
|
||||||
std::cout << "\tUsing unit \"" << task_name << "\"." << std::endl;
|
std::cout << "\tUsing unit \"" << task_name << "\"." << std::endl;
|
||||||
std::cout << "\tExecuting target \"" << target_command << "\"." << std::endl;
|
std::cout << "\tExecuting target \"" << target_command << "\"." << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -124,23 +128,18 @@ void Task::execute( bool verbose )
|
||||||
int return_code = Sproc::execute( target_command );
|
int return_code = Sproc::execute( target_command );
|
||||||
|
|
||||||
// d[0] check exit code of target
|
// d[0] check exit code of target
|
||||||
if (return_code == 0)
|
if (return_code == 0) {
|
||||||
{
|
|
||||||
// Zero d[0] return from target execution, good to return
|
// Zero d[0] return from target execution, good to return
|
||||||
if ( verbose )
|
if ( verbose ) {
|
||||||
{
|
|
||||||
std::cout << "\tTarget " << task_name << " succeeded." << std::endl;
|
std::cout << "\tTarget " << task_name << " succeeded." << std::endl;
|
||||||
}
|
}
|
||||||
// next
|
// next
|
||||||
return;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Non-Zero d[0] from initial target execution, get to d[1]
|
// Non-Zero d[0] from initial target execution, get to d[1]
|
||||||
std::cout << "\tTarget \"" << task_name << "\" failed with exit code " << return_code << "." << std::endl;
|
std::cout << "\tTarget \"" << task_name << "\" failed with exit code " << return_code << "." << std::endl;
|
||||||
|
|
||||||
// check if rectify pattern is enabled d[1]
|
// check if rectify pattern is enabled d[1]
|
||||||
if ( this->definition.get_rectify() )
|
if ( this->definition.get_rectify() ) {
|
||||||
{
|
|
||||||
// yes d[1]
|
// yes d[1]
|
||||||
std::cout << "\tRectification pattern is enabled for \"" << task_name << "\"." << std::endl;
|
std::cout << "\tRectification pattern is enabled for \"" << task_name << "\"." << std::endl;
|
||||||
// execute RECTIFIER
|
// execute RECTIFIER
|
||||||
|
@ -149,23 +148,19 @@ void Task::execute( bool verbose )
|
||||||
int rectifier_error = Sproc::execute( rectifier_command );
|
int rectifier_error = Sproc::execute( rectifier_command );
|
||||||
|
|
||||||
// d[3] check exit code of rectifier
|
// d[3] check exit code of rectifier
|
||||||
if ( rectifier_error )
|
if (rectifier_error) {
|
||||||
{
|
|
||||||
//d[3] non-zero
|
//d[3] non-zero
|
||||||
|
|
||||||
std::cout << "\tRectification of \"" << task_name << "\" failed with exit code " << rectifier_error << "." << std::endl;
|
std::cout << "\tRectification of \"" << task_name << "\" failed with exit code " << rectifier_error << "." << std::endl;
|
||||||
// d[2] check if REQUIRED
|
// d[2] check if REQUIRED
|
||||||
if ( this->definition.get_required() )
|
if ( this->definition.get_required() ) {
|
||||||
{
|
|
||||||
// d[2] yes
|
// d[2] yes
|
||||||
// halt/exception
|
// halt/exception
|
||||||
throw Task_RequiredButFailedTask();
|
throw Task_RequiredButFailedTask();
|
||||||
} else {
|
}
|
||||||
// d[2] no
|
// d[2] no
|
||||||
// next
|
// next
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// d[3] zero
|
// d[3] zero
|
||||||
|
|
||||||
// execute target
|
// execute target
|
||||||
|
@ -175,38 +170,27 @@ void Task::execute( bool verbose )
|
||||||
// d[4] exit code of target retry
|
// d[4] exit code of target retry
|
||||||
if (retry_code == 0) {
|
if (retry_code == 0) {
|
||||||
// d[4] zero
|
// d[4] zero
|
||||||
return;
|
}
|
||||||
} else {
|
|
||||||
// d[4] non-zero
|
// d[4] non-zero
|
||||||
// d[5] required check
|
// d[5] required check
|
||||||
if ( this->definition.get_required() )
|
if ( this->definition.get_required() ) {
|
||||||
{
|
|
||||||
// d[5] yes
|
// d[5] yes
|
||||||
|
std::cout << "\tTask \"" << task_name << "\" is required but rectification did not heal." << std::endl;
|
||||||
throw Task_RequiredButRectifierDoesNotHeal();
|
throw Task_RequiredButRectifierDoesNotHeal();
|
||||||
} else {
|
}
|
||||||
// d[5] no
|
// d[5] no
|
||||||
// next
|
// next
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// no d[1]
|
// no d[1]
|
||||||
std::cout << "\tRectification is not enabled for \"" << task_name << "\"." << std::endl;
|
std::cout << "\tRectification is not enabled for \"" << task_name << "\"." << std::endl;
|
||||||
// required d[2]
|
// required d[2]
|
||||||
if ( this->definition.get_required() )
|
if ( this->definition.get_required() ) {
|
||||||
{
|
|
||||||
// d[2] yes
|
// d[2] yes
|
||||||
// This is executing.....
|
// This is executing.....
|
||||||
std::cout << "\tThis task is required to continue the plan." << std::endl;
|
std::cout << "\tThis task is required to continue the plan." << std::endl;
|
||||||
// but these are NOT executing?????
|
// but these are NOT executing?????
|
||||||
throw Task_RequiredButFailedTask();
|
throw Task_RequiredButFailedTask();
|
||||||
return;
|
} // d[2] no
|
||||||
} else {
|
|
||||||
// d[2] no
|
|
||||||
std::cout << "\tThis task is not required to continue the plan." << std::endl;
|
std::cout << "\tThis task is not required to continue the plan." << std::endl;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
#include "Sproc.h"
|
#include "Sproc.h"
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <wait.h>
|
||||||
|
|
||||||
/// Sproc::execute
|
/// Sproc::execute
|
||||||
///
|
///
|
||||||
|
@ -13,14 +14,17 @@ int Sproc::execute(std::string input) {
|
||||||
int stdin_pipe[2];
|
int stdin_pipe[2];
|
||||||
int stderr_pipe[2];
|
int stderr_pipe[2];
|
||||||
int stdout_pipe[2];
|
int stdout_pipe[2];
|
||||||
int child_pid;
|
pid_t child_pid, w;
|
||||||
char nChar;
|
char nChar;
|
||||||
int child_exit_code;
|
int child_exit_code = -666;
|
||||||
|
|
||||||
|
// experimental
|
||||||
|
int status;
|
||||||
|
|
||||||
if ( pipe(stdin_pipe) < 0 )
|
if ( pipe(stdin_pipe) < 0 )
|
||||||
{
|
{
|
||||||
perror("allocating pipe for child input redirect");
|
perror("allocating pipe for child input redirect");
|
||||||
return -1;
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( pipe(stdout_pipe) < 0 )
|
if ( pipe(stdout_pipe) < 0 )
|
||||||
|
@ -28,14 +32,14 @@ int Sproc::execute(std::string input) {
|
||||||
close(stdin_pipe[PIPE_READ]);
|
close(stdin_pipe[PIPE_READ]);
|
||||||
close(stdin_pipe[PIPE_WRITE]);
|
close(stdin_pipe[PIPE_WRITE]);
|
||||||
perror("allocating pipe for child output redirect");
|
perror("allocating pipe for child output redirect");
|
||||||
return -1;
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( pipe(stderr_pipe) < 0 ) {
|
if ( pipe(stderr_pipe) < 0 ) {
|
||||||
close(stderr_pipe[PIPE_READ]);
|
close(stderr_pipe[PIPE_READ]);
|
||||||
close(stderr_pipe[PIPE_WRITE]);
|
close(stderr_pipe[PIPE_WRITE]);
|
||||||
perror("allocating pipe for error redirect");
|
perror("allocating pipe for error redirect");
|
||||||
return -1;
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,13 +78,31 @@ int Sproc::execute(std::string input) {
|
||||||
// replace this with any exec* function find easier to use ("man exec")
|
// replace this with any exec* function find easier to use ("man exec")
|
||||||
child_exit_code = system( input.c_str() );
|
child_exit_code = system( input.c_str() );
|
||||||
|
|
||||||
|
|
||||||
// if we get here at all, an error occurred, but we are in the child
|
// if we get here at all, an error occurred, but we are in the child
|
||||||
// process, so just exit
|
// process, so just exit
|
||||||
return WEXITSTATUS(child_exit_code);
|
exit(WEXITSTATUS(child_exit_code));
|
||||||
} else if (child_pid > 0) {
|
} else if (child_pid > 0) {
|
||||||
// parent continues here
|
// parent continues here
|
||||||
|
|
||||||
|
do {
|
||||||
|
w = waitpid(child_pid, &child_exit_code, WUNTRACED | WCONTINUED);
|
||||||
|
if (w == -1) {
|
||||||
|
perror("waitpid");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WIFEXITED(child_exit_code)) {
|
||||||
|
;;
|
||||||
|
//printf("exited, status=%d\n", WEXITSTATUS(child_exit_code));
|
||||||
|
} else if (WIFSIGNALED(child_exit_code)) {
|
||||||
|
printf("killed by signal %d\n", WTERMSIG(child_exit_code));
|
||||||
|
} else if (WIFSTOPPED(child_exit_code)) {
|
||||||
|
printf("stopped by signal %d\n", WSTOPSIG(child_exit_code));
|
||||||
|
} else if (WIFCONTINUED(child_exit_code)) {
|
||||||
|
printf("continued\n");
|
||||||
|
}
|
||||||
|
} while (!WIFEXITED(child_exit_code) && !WIFSIGNALED(child_exit_code));
|
||||||
|
|
||||||
// close unused file descriptors, these are for child only
|
// close unused file descriptors, these are for child only
|
||||||
close(stdin_pipe[PIPE_READ]);
|
close(stdin_pipe[PIPE_READ]);
|
||||||
close(stdout_pipe[PIPE_WRITE]);
|
close(stdout_pipe[PIPE_WRITE]);
|
||||||
|
@ -100,6 +122,7 @@ int Sproc::execute(std::string input) {
|
||||||
close(stderr_pipe[PIPE_READ]);
|
close(stderr_pipe[PIPE_READ]);
|
||||||
} else {
|
} else {
|
||||||
// failed to create child
|
// failed to create child
|
||||||
|
std::cout << "Failed to create child." << std::endl;
|
||||||
close(stdin_pipe[PIPE_READ]);
|
close(stdin_pipe[PIPE_READ]);
|
||||||
close(stdin_pipe[PIPE_WRITE]);
|
close(stdin_pipe[PIPE_WRITE]);
|
||||||
|
|
||||||
|
@ -109,6 +132,7 @@ int Sproc::execute(std::string input) {
|
||||||
close(stderr_pipe[PIPE_READ]);
|
close(stderr_pipe[PIPE_READ]);
|
||||||
close(stderr_pipe[PIPE_WRITE]);
|
close(stderr_pipe[PIPE_WRITE]);
|
||||||
}
|
}
|
||||||
|
child_exit_code = WEXITSTATUS( child_exit_code );
|
||||||
|
|
||||||
return WEXITSTATUS(child_exit_code);
|
return child_exit_code;
|
||||||
}
|
}
|
Loading…
Reference in New Issue