cleaning up
parent
3d421b1ca0
commit
4b3a9170bf
|
@ -1,15 +1,26 @@
|
||||||
#include "Sproc.h"
|
#include "Sproc.h"
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <grp.h>
|
|
||||||
#include <fstream>
|
|
||||||
#include "../Logger/Logger.h"
|
|
||||||
#include "errno.h"
|
|
||||||
#include <cstring>
|
|
||||||
#include "fcntl.h"
|
|
||||||
|
|
||||||
#define PARENT default
|
#define PARENT default
|
||||||
|
|
||||||
|
enum PIPE_FILE_DESCRIPTORS {
|
||||||
|
READ_END = 0,
|
||||||
|
WRITE_END = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum READ_RESULTS {
|
||||||
|
READ_EOF = 0,
|
||||||
|
READ_PIPEOPEN_O_NONBLOCK = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FORK_STATES {
|
||||||
|
FORK_FAILURE = -1,
|
||||||
|
CHILD = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ------------------
|
||||||
|
* HELPERS
|
||||||
|
* ------------------ */
|
||||||
|
|
||||||
// converts username to UID
|
// converts username to UID
|
||||||
// returns false on failure
|
// returns false on failure
|
||||||
int username_to_uid( std::string username, int & uid )
|
int username_to_uid( std::string username, int & uid )
|
||||||
|
@ -77,33 +88,7 @@ int teebuf::sync()
|
||||||
teestream::teestream(std::ostream &o1, std::ostream &o2) : std::ostream( &tbuf), tbuf( o1.rdbuf(), o2.rdbuf() )
|
teestream::teestream(std::ostream &o1, std::ostream &o2) : std::ostream( &tbuf), tbuf( o1.rdbuf(), o2.rdbuf() )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
enum PIPE_FILE_DESCRIPTORS {
|
// SET PROCESS TO A CERTAIN IDENTITY CONTEXT
|
||||||
READ_END = 0,
|
|
||||||
WRITE_END = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum READ_RESULTS {
|
|
||||||
READ_EOF = 0,
|
|
||||||
READ_PIPEOPEN_O_NONBLOCK = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
enum SPROC_RETURN_CODES {
|
|
||||||
SUCCESS = true,
|
|
||||||
UID_NOT_FOUND = -404,
|
|
||||||
GID_NOT_FOUND = -405,
|
|
||||||
SET_GID_FAILED = -401,
|
|
||||||
SET_UID_FAILED = -404,
|
|
||||||
EXEC_FAILURE_GENERAL = -666,
|
|
||||||
DUP2_FAILED = -999,
|
|
||||||
PIPE_FAILED = -998
|
|
||||||
};
|
|
||||||
|
|
||||||
enum FORK_STATES {
|
|
||||||
FORK_FAILURE = -1,
|
|
||||||
CHILD = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
int set_identity_context( std::string task_name, std::string user_name, std::string group_name, Logger slog ) {
|
int set_identity_context( std::string task_name, std::string user_name, std::string group_name, Logger slog ) {
|
||||||
// the UID and GID for the username and groupname provided for context setting
|
// the UID and GID for the username and groupname provided for context setting
|
||||||
int context_user_id;
|
int context_user_id;
|
||||||
|
@ -180,7 +165,6 @@ int Sproc::execute(std::string shell, std::string environment_file, std::string
|
||||||
// in as hands off a way as possible with as few assumptions as possible, while still doing this in a somewhat C++-y
|
// in as hands off a way as possible with as few assumptions as possible, while still doing this in a somewhat C++-y
|
||||||
// way.
|
// way.
|
||||||
|
|
||||||
|
|
||||||
// set up the "Tee" with the parent
|
// set up the "Tee" with the parent
|
||||||
std::string child_stdout_log_path = "./stdout.log";
|
std::string child_stdout_log_path = "./stdout.log";
|
||||||
std::string child_stderr_log_path = "./stderr.log";
|
std::string child_stderr_log_path = "./stderr.log";
|
||||||
|
@ -191,17 +175,14 @@ int Sproc::execute(std::string shell, std::string environment_file, std::string
|
||||||
stdout_log.open( child_stdout_log_path.c_str(), std::ofstream::out | std::ofstream::app );
|
stdout_log.open( child_stdout_log_path.c_str(), std::ofstream::out | std::ofstream::app );
|
||||||
stderr_log.open( child_stderr_log_path.c_str(), std::ofstream::out | std::ofstream::app );
|
stderr_log.open( child_stderr_log_path.c_str(), std::ofstream::out | std::ofstream::app );
|
||||||
|
|
||||||
|
|
||||||
// avoid cyclic dependencies between stdout and tee_out
|
// avoid cyclic dependencies between stdout and tee_out
|
||||||
std::ostream tmp_stdout( std::cout.rdbuf() );
|
std::ostream tmp_stdout( std::cout.rdbuf() );
|
||||||
std::ostream tmp_stderr( std::cerr.rdbuf() );
|
std::ostream tmp_stderr( std::cerr.rdbuf() );
|
||||||
|
|
||||||
|
|
||||||
// writing to this ostream derivative will write to stdout log file and std::cout
|
// writing to this ostream derivative will write to stdout log file and std::cout
|
||||||
teestream tee_out(tmp_stdout, stdout_log);
|
teestream tee_out(tmp_stdout, stdout_log);
|
||||||
teestream tee_err(tmp_stderr, stderr_log);
|
teestream tee_err(tmp_stderr, stderr_log);
|
||||||
|
|
||||||
|
|
||||||
// pop the cout/cerr buffers to the appropriate Tees' buffers
|
// pop the cout/cerr buffers to the appropriate Tees' buffers
|
||||||
|
|
||||||
// These cause a segfault when used with the I/O redirection happening around fork, pipe, dup2, execl...
|
// These cause a segfault when used with the I/O redirection happening around fork, pipe, dup2, execl...
|
||||||
|
@ -209,7 +190,6 @@ int Sproc::execute(std::string shell, std::string environment_file, std::string
|
||||||
//std::cerr.rdbuf( tee_err.rdbuf() );
|
//std::cerr.rdbuf( tee_err.rdbuf() );
|
||||||
// ....and I don't know why.
|
// ....and I don't know why.
|
||||||
|
|
||||||
|
|
||||||
// build the command to execute in the shell
|
// build the command to execute in the shell
|
||||||
std::string sourcer = ". " + environment_file + " && " + command;
|
std::string sourcer = ". " + environment_file + " && " + command;
|
||||||
// Show the user a debug print of what is going to be executed in the shell.
|
// Show the user a debug print of what is going to be executed in the shell.
|
||||||
|
@ -246,6 +226,7 @@ int Sproc::execute(std::string shell, std::string environment_file, std::string
|
||||||
{
|
{
|
||||||
// fork failed
|
// fork failed
|
||||||
slog.log(E_FATAL, "[ '" + task_name + "' ] Fork Failed.");
|
slog.log(E_FATAL, "[ '" + task_name + "' ] Fork Failed.");
|
||||||
|
exit( FORK_FAILED );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FORK_STATES::CHILD:
|
case FORK_STATES::CHILD:
|
||||||
|
@ -262,7 +243,6 @@ int Sproc::execute(std::string shell, std::string environment_file, std::string
|
||||||
close( child_stderr_pipe[WRITE_END] );
|
close( child_stderr_pipe[WRITE_END] );
|
||||||
close( child_stderr_pipe[READ_END] );
|
close( child_stderr_pipe[READ_END] );
|
||||||
|
|
||||||
|
|
||||||
slog.log(E_INFO, "[ '" + task_name + "' ] TEE Logging enabled.");
|
slog.log(E_INFO, "[ '" + task_name + "' ] TEE Logging enabled.");
|
||||||
slog.log(E_DEBUG, "[ '" + task_name + "' ] DUP2: child_*_pipe[1]->STD*_FILENO");
|
slog.log(E_DEBUG, "[ '" + task_name + "' ] DUP2: child_*_pipe[1]->STD*_FILENO");
|
||||||
|
|
||||||
|
@ -292,16 +272,13 @@ int Sproc::execute(std::string shell, std::string environment_file, std::string
|
||||||
close(child_stdout_pipe[WRITE_END]);
|
close(child_stdout_pipe[WRITE_END]);
|
||||||
close(child_stderr_pipe[WRITE_END]);
|
close(child_stderr_pipe[WRITE_END]);
|
||||||
|
|
||||||
|
// buffers for reading from child fd's
|
||||||
char stdout_buf[1000] = {0};
|
char stdout_buf[1000] = {0};
|
||||||
char stderr_buf[1000] = {0};
|
char stderr_buf[1000] = {0};
|
||||||
|
|
||||||
|
|
||||||
// will contain a set of file descriptors to monitor representing stdout and stderr of the child process
|
// will contain a set of file descriptors to monitor representing stdout and stderr of the child process
|
||||||
fd_set readfds;
|
fd_set readfds;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// loop completion flags
|
// loop completion flags
|
||||||
bool set_stdout_break = false;
|
bool set_stdout_break = false;
|
||||||
bool set_stderr_break = false;
|
bool set_stderr_break = false;
|
||||||
|
@ -315,28 +292,24 @@ int Sproc::execute(std::string shell, std::string environment_file, std::string
|
||||||
FD_SET( child_stdout_pipe[READ_END], & readfds );
|
FD_SET( child_stdout_pipe[READ_END], & readfds );
|
||||||
FD_SET( child_stderr_pipe[READ_END], & readfds );
|
FD_SET( child_stderr_pipe[READ_END], & readfds );
|
||||||
|
|
||||||
|
// for some reason select needs the highest number of the fd +1 of its own input
|
||||||
int highest_fd = child_stderr_pipe[READ_END] > child_stdout_pipe[READ_END] ? child_stderr_pipe[READ_END] : child_stdout_pipe[READ_END];
|
int highest_fd = child_stderr_pipe[READ_END] > child_stdout_pipe[READ_END] ? child_stderr_pipe[READ_END] : child_stdout_pipe[READ_END];
|
||||||
|
|
||||||
|
// wait for one of the fd's to become readable
|
||||||
if ( select( highest_fd + 1, &readfds, NULL, NULL, NULL ) >= 0 )
|
if ( select( highest_fd + 1, &readfds, NULL, NULL, NULL ) >= 0 )
|
||||||
{ // can read any
|
{ // can read any
|
||||||
if ( FD_ISSET( child_stdout_pipe[READ_END], &readfds ) )
|
if ( FD_ISSET( child_stdout_pipe[READ_END], &readfds ) )
|
||||||
{
|
{ // can read child stdout pipe
|
||||||
// can read child stdout pipe
|
|
||||||
// so do so
|
|
||||||
|
|
||||||
// read and return the byte size of what was read
|
// read and return the byte size of what was read
|
||||||
int stdout_count = read(child_stdout_pipe[READ_END], stdout_buf, sizeof(stdout_buf) - 1);
|
int stdout_count = read(child_stdout_pipe[READ_END], stdout_buf, sizeof(stdout_buf) - 1);
|
||||||
|
|
||||||
// switch on the count size to allow for error return handling
|
switch(stdout_count) { // switch on the count size to allow for error return handling
|
||||||
switch(stdout_count) {
|
|
||||||
case READ_PIPEOPEN_O_NONBLOCK:
|
case READ_PIPEOPEN_O_NONBLOCK:
|
||||||
if ( errno == EINTR ) {
|
if ( errno == EINTR ) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
perror("read stdout");
|
slog.log(E_FATAL, "Pipe reading issue with child STDOUT.");
|
||||||
slog.log(E_FATAL, "PIPE ISSUE with STDOUT");
|
exit( PIPE_FAILED2 );
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
case READ_EOF:
|
case READ_EOF:
|
||||||
// signal that STDOUT is complete
|
// signal that STDOUT is complete
|
||||||
|
@ -345,6 +318,7 @@ int Sproc::execute(std::string shell, std::string environment_file, std::string
|
||||||
default:
|
default:
|
||||||
tee_out.write( stdout_buf, stdout_count );
|
tee_out.write( stdout_buf, stdout_count );
|
||||||
tee_out.flush();
|
tee_out.flush();
|
||||||
|
|
||||||
// clear the buffer to prevent artifacts from previous loop
|
// clear the buffer to prevent artifacts from previous loop
|
||||||
memset( &stdout_buf[0], 0, sizeof( stdout_buf ) -1 );
|
memset( &stdout_buf[0], 0, sizeof( stdout_buf ) -1 );
|
||||||
}
|
}
|
||||||
|
@ -363,19 +337,21 @@ int Sproc::execute(std::string shell, std::string environment_file, std::string
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
perror( "read stderr" );
|
perror( "read stderr" );
|
||||||
slog.log( E_FATAL, "PIPE ISSUE WITH STDERR" );
|
slog.log( E_FATAL, "Pipe reading issue with child STDERR." );
|
||||||
exit(1);
|
exit( PIPE_FAILED3 );
|
||||||
}
|
}
|
||||||
case READ_RESULTS::READ_EOF:
|
case READ_RESULTS::READ_EOF:
|
||||||
|
// let the loop know the STDERR criteria has been met
|
||||||
set_stderr_break = true;
|
set_stderr_break = true;
|
||||||
//break;
|
// continue the loop
|
||||||
continue;
|
continue;
|
||||||
default:
|
default:
|
||||||
|
// write the buffer contents to the STDERR Tee
|
||||||
tee_err.write( stderr_buf, stderr_count );
|
tee_err.write( stderr_buf, stderr_count );
|
||||||
|
// flush the TEE
|
||||||
tee_err.flush();
|
tee_err.flush();
|
||||||
// clear the buffer to prevent artifacts from previous loop
|
// clear the buffer to prevent artifacts from previous loop
|
||||||
memset( &stderr_buf[0], 0, sizeof( stderr_buf ) -1 );
|
memset( &stderr_buf[0], 0, sizeof( stderr_buf ) -1 );
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -384,9 +360,8 @@ int Sproc::execute(std::string shell, std::string environment_file, std::string
|
||||||
} // end select/if
|
} // end select/if
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wait for the child to exit
|
||||||
while ( ( pid = waitpid(pid, &exit_code_raw, 0 ) ) == -1 ) {}
|
while ( ( pid = waitpid(pid, &exit_code_raw, 0 ) ) == -1 ) {}
|
||||||
//waitpid( pid, &exit_code_raw, 0 );
|
|
||||||
|
|
||||||
// clean up Tee
|
// clean up Tee
|
||||||
stdout_log.close();
|
stdout_log.close();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
Examplar - An automation and testing framework.
|
Rex - An automation and testing system.
|
||||||
|
|
||||||
© SURRO INDUSTRIES and Chris Punches, 2017.
|
SILO GROUP© and Chris Punches, 2017.
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Affero General Public License as
|
it under the terms of the GNU Affero General Public License as
|
||||||
|
@ -15,30 +15,56 @@
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
You should have received a copy of the GNU Affero General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FTESTS_SPROC_H
|
#ifndef FTESTS_SPROC_H
|
||||||
#define FTESTS_SPROC_H
|
#define FTESTS_SPROC_H
|
||||||
|
|
||||||
#include <string>
|
#include "../Logger/Logger.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "../Logger/Logger.h"
|
#include "errno.h"
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
#include <streambuf>
|
#include <streambuf>
|
||||||
#include "unistd.h"
|
#include "unistd.h"
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include "fcntl.h"
|
||||||
|
|
||||||
|
// exit codes for Rex
|
||||||
|
enum SPROC_RETURN_CODES {
|
||||||
|
SUCCESS = true,
|
||||||
|
UID_NOT_FOUND = -404,
|
||||||
|
GID_NOT_FOUND = -405,
|
||||||
|
SET_GID_FAILED = -401,
|
||||||
|
SET_UID_FAILED = -404,
|
||||||
|
EXEC_FAILURE_GENERAL = -666,
|
||||||
|
PIPE_FAILED3 = -996,
|
||||||
|
PIPE_FAILED2 = -997,
|
||||||
|
PIPE_FAILED = -998,
|
||||||
|
DUP2_FAILED = -999,
|
||||||
|
FORK_FAILED = -1000
|
||||||
|
};
|
||||||
|
|
||||||
// executes a subprocess and captures STDOUT, STDERR, and return code.
|
// executes a subprocess and captures STDOUT, STDERR, and return code.
|
||||||
// should be able to recieve path of binary to be executed as well as any parameters
|
// should be able to receive path of binary to be executed as well as any parameters
|
||||||
class Sproc {
|
class Sproc {
|
||||||
public:
|
public:
|
||||||
// call the object. return value is enum representing external execution attempt not binary exit code
|
// call the object. return value is enum representing external execution attempt not binary exit code
|
||||||
static int execute(std::string shell, std::string enviornment_file, std::string user_name, std::string group_name, std::string command, int LOG_LEVEL, std::string task_name );
|
static int execute(
|
||||||
|
std::string shell,
|
||||||
|
std::string environment_file,
|
||||||
|
std::string user_name,
|
||||||
|
std::string group_name,
|
||||||
|
std::string command,
|
||||||
|
int LOG_LEVEL,
|
||||||
|
std::string task_name
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// mostly lifted from:
|
|
||||||
// http://wordaligned.org/articles/cpp-streambufs
|
|
||||||
// a teebuff implementation
|
// a teebuff implementation
|
||||||
class teebuf: public std::streambuf
|
class teebuf: public std::streambuf
|
||||||
{
|
{
|
||||||
|
@ -63,4 +89,3 @@ class teestream : public std::ostream
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //FTESTS_SPROC_H
|
#endif //FTESTS_SPROC_H
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue