early rex, finally
parent
31ed2feb7f
commit
dce543a15d
|
@ -8,6 +8,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "fcntl.h"
|
#include "fcntl.h"
|
||||||
|
|
||||||
|
#define PARENT default
|
||||||
|
|
||||||
// converts username to UID
|
// converts username to UID
|
||||||
// returns false on failure
|
// returns false on failure
|
||||||
|
@ -77,8 +78,13 @@ teestream::teestream(std::ostream &o1, std::ostream &o2) : std::ostream( &tbuf),
|
||||||
{}
|
{}
|
||||||
|
|
||||||
enum PIPE_FILE_DESCRIPTORS {
|
enum PIPE_FILE_DESCRIPTORS {
|
||||||
READ_FD = 0,
|
READ_END = 0,
|
||||||
WRITE_FD = 1
|
WRITE_END = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum READ_RESULTS {
|
||||||
|
READ_EOF = 0,
|
||||||
|
READ_PIPEOPEN_O_NONBLOCK = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -185,19 +191,23 @@ 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
|
||||||
std::cout.rdbuf( tee_out.rdbuf() );
|
|
||||||
std::cerr.rdbuf( tee_err.rdbuf() );
|
// These cause a segfault when used with the I/O redirection happening around fork, pipe, dup2, execl...
|
||||||
// end - "set up the 'Tee' with the parent"
|
//std::cout.rdbuf( tee_out.rdbuf() );
|
||||||
slog.log( E_INFO, "Tee Logging enabled for \"" + task_name + "\"");
|
//std::cerr.rdbuf( tee_err.rdbuf() );
|
||||||
|
// ....and I don't know why.
|
||||||
|
|
||||||
|
|
||||||
// build the command to execute in the shell
|
// build the command to execute in the shell
|
||||||
|
@ -206,29 +216,31 @@ int Sproc::execute(std::string shell, std::string environment_file, std::string
|
||||||
slog.log(E_DEBUG, "[ '" + task_name + "' ] Shell call for loading: ``" + sourcer + "``.");
|
slog.log(E_DEBUG, "[ '" + task_name + "' ] Shell call for loading: ``" + sourcer + "``.");
|
||||||
|
|
||||||
// file descriptors for parent/child i/o
|
// file descriptors for parent/child i/o
|
||||||
int stdout_filedes[2];
|
int child_stdout_pipe[2];
|
||||||
|
int child_stderr_pipe[2];
|
||||||
|
|
||||||
slog.log( E_DEBUG, "[ '" + task_name + "' ] STDIN/STDOUT/STDERR file descriptors created." );
|
slog.log( E_DEBUG, "[ '" + task_name + "' ] STDIN/STDOUT/STDERR file descriptors created." );
|
||||||
|
|
||||||
// man 3 pipe
|
// man 3 pipe
|
||||||
if (pipe(stdout_filedes) == -1 ) {
|
if (pipe(child_stdout_pipe) == -1 ) {
|
||||||
slog.log(E_FATAL, "[ '" + task_name + "' ] PIPE FAILED");
|
slog.log(E_FATAL, "[ '" + task_name + "' ] STDOUT PIPE FAILED");
|
||||||
return SPROC_RETURN_CODES::PIPE_FAILED;
|
return SPROC_RETURN_CODES::PIPE_FAILED;
|
||||||
} else {
|
} else {
|
||||||
slog.log(E_DEBUG, "[ '" + task_name + "' ] file descriptors piped.");
|
slog.log(E_DEBUG, "[ '" + task_name + "' ] file descriptors piped.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// man 3 pipe
|
||||||
// // avoids the need to take any explicit action within the child process to close file descriptors
|
if (pipe(child_stderr_pipe) == -1 ) {
|
||||||
// if (fcntl(stdout_filedes[READ_FD], F_SETFD, FD_CLOEXEC) == -1) {
|
slog.log(E_FATAL, "[ '" + task_name + "' ] STDERR PIPE FAILED");
|
||||||
// perror("fcntl");
|
return SPROC_RETURN_CODES::PIPE_FAILED;
|
||||||
// exit(1);
|
} else {
|
||||||
// }
|
slog.log(E_DEBUG, "[ '" + task_name + "' ] file descriptors piped.");
|
||||||
|
}
|
||||||
|
|
||||||
// fork a process
|
// fork a process
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
slog.log( E_DEBUG, "[ '" + task_name + "' ] Process forked. Reporting. (PID: " + std::to_string(pid) + ")" );
|
slog.log( E_DEBUG, "[ '" + task_name + "' ] Process forked. Reporting. (PID: " + std::to_string(pid) + ")" );
|
||||||
|
|
||||||
|
|
||||||
switch ( pid ) {
|
switch ( pid ) {
|
||||||
case FORK_STATES::FORK_FAILURE:
|
case FORK_STATES::FORK_FAILURE:
|
||||||
{
|
{
|
||||||
|
@ -241,22 +253,30 @@ int Sproc::execute(std::string shell, std::string environment_file, std::string
|
||||||
// enter child process
|
// enter child process
|
||||||
slog.log(E_DEBUG, "[ '" + task_name + "' ] Entering child process.");
|
slog.log(E_DEBUG, "[ '" + task_name + "' ] Entering child process.");
|
||||||
|
|
||||||
while ((dup2(stdout_filedes[WRITE_FD], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
|
while ((dup2(child_stdout_pipe[WRITE_END], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
|
||||||
close( stdout_filedes[WRITE_FD] );
|
while ((dup2(child_stderr_pipe[WRITE_END], STDERR_FILENO) == -1) && (errno == EINTR)) {}
|
||||||
close( stdout_filedes[READ_FD] );
|
|
||||||
slog.log(E_DEBUG, "[ '" + task_name + "' ] DUP2 on stdout_filedes[1]->STDOUT_FILENO in child.");
|
|
||||||
|
|
||||||
|
close(child_stdout_pipe[WRITE_END] );
|
||||||
|
close(child_stdout_pipe[READ_END] );
|
||||||
|
|
||||||
|
close(child_stderr_pipe[WRITE_END] );
|
||||||
|
close(child_stderr_pipe[READ_END] );
|
||||||
|
|
||||||
|
|
||||||
|
slog.log(E_INFO, "[ '" + task_name + "' ] TEE Logging enabled.");
|
||||||
|
slog.log(E_DEBUG, "[ '" + task_name + "' ] DUP2: child_*_pipe[1]->STD*_FILENO");
|
||||||
|
|
||||||
// set identity context
|
// set identity context
|
||||||
// set gid and uid
|
// set gid and uid
|
||||||
int context_status = set_identity_context(task_name, user_name, group_name, slog);
|
int context_status = set_identity_context(task_name, user_name, group_name, slog);
|
||||||
if (!(context_status)) {
|
if (!(context_status)) {
|
||||||
slog.log(E_FATAL, "[ '" + task_name + "' ] Identity context switch failed.");
|
slog.log(E_FATAL, "[ '" + task_name + "' ] Identity context set failed.");
|
||||||
return context_status;
|
return context_status;
|
||||||
|
} else {
|
||||||
|
slog.log( E_INFO, "[ '" + task_name + "' ] Identity context set as user '" + user_name + "' and group '" + group_name + "'." );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// execute our big nasty thing
|
||||||
// exit_code_raw = system( sourcer.c_str() );
|
|
||||||
int ret = execl("/bin/sh", "/bin/sh", "-c", sourcer.c_str(), (char *) NULL);
|
int ret = execl("/bin/sh", "/bin/sh", "-c", sourcer.c_str(), (char *) NULL);
|
||||||
|
|
||||||
// print something useful to debug with if execl fails
|
// print something useful to debug with if execl fails
|
||||||
|
@ -266,45 +286,76 @@ int Sproc::execute(std::string shell, std::string environment_file, std::string
|
||||||
exit(exit_code_raw);
|
exit(exit_code_raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
PARENT:
|
||||||
{
|
{
|
||||||
// parent process
|
// enter the parent process
|
||||||
close(stdout_filedes[WRITE_FD]);
|
close(child_stdout_pipe[WRITE_END]);
|
||||||
// ---
|
close(child_stderr_pipe[WRITE_END]);
|
||||||
// clean up Tee
|
|
||||||
stdout_log.close();
|
|
||||||
stderr_log.close();
|
|
||||||
|
|
||||||
|
char stdout_buf[1000] = {0};
|
||||||
char buffer[1000] = {0};
|
char stderr_buf[1000] = {0};
|
||||||
std::cout.flush();
|
std::cout.flush();
|
||||||
|
std::cerr.flush();
|
||||||
|
|
||||||
|
bool set_break = false;
|
||||||
|
|
||||||
// read from fd until child completes
|
// read from fd until child completes
|
||||||
while ( 1 ) {
|
while (! set_break ) {
|
||||||
ssize_t count = read(stdout_filedes[READ_FD], buffer, sizeof(buffer));
|
ssize_t stdout_count = read(child_stdout_pipe[READ_END], stdout_buf, sizeof(stdout_buf) - 1);
|
||||||
if (count == -1) {
|
|
||||||
|
// cycle through STDOUT
|
||||||
|
switch (stdout_count) {
|
||||||
|
case READ_PIPEOPEN_O_NONBLOCK:
|
||||||
if (errno == EINTR) {
|
if (errno == EINTR) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
perror("read");
|
perror("read");
|
||||||
|
slog.log(E_FATAL, "PIPE ISSUE with STDOUT");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if (count == 0) {
|
case READ_EOF:
|
||||||
|
set_break = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
default:
|
||||||
std::cout << buffer;
|
tee_out.write(stdout_buf, stdout_count);
|
||||||
std::cout.flush();
|
tee_out.flush();
|
||||||
memset(&buffer[0], 0, sizeof(buffer));
|
memset(&stdout_buf[0], 0, sizeof(stdout_buf));
|
||||||
// handle_child_process_output(buffer, count);
|
// END SWITCH
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_break = false;
|
||||||
|
while(! set_break ) {
|
||||||
|
ssize_t stderr_count = read(child_stderr_pipe[READ_END], stderr_buf, sizeof(stderr_buf) - 1 );
|
||||||
|
switch ( stderr_count )
|
||||||
|
{
|
||||||
|
case READ_PIPEOPEN_O_NONBLOCK:
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
perror("read");
|
||||||
|
slog.log( E_FATAL, "PIPE ISSUE with STDERR" );
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
case READ_EOF:
|
||||||
|
set_break = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
tee_err.write( stderr_buf, stderr_count );
|
||||||
|
tee_err.flush();
|
||||||
|
memset(&stderr_buf[0], 0, sizeof(stderr_buf));
|
||||||
|
// END SWITCH
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while ((pid = waitpid(pid, &exit_code_raw, 0)) == -1) {}
|
while ((pid = waitpid(pid, &exit_code_raw, 0)) == -1) {}
|
||||||
//waitpid( pid, &exit_code_raw, 0 );
|
//waitpid( pid, &exit_code_raw, 0 );
|
||||||
|
|
||||||
|
// clean up Tee
|
||||||
|
stdout_log.close();
|
||||||
|
stderr_log.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return WEXITSTATUS( exit_code_raw );
|
return WEXITSTATUS( exit_code_raw );
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
echo "independent test 2 output"
|
echo "independent test 2 output"
|
||||||
|
echo "independent test says TEST_VAR is ${TEST_VAR}"
|
||||||
exit $?
|
exit $?
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
{ "name": "independent test 1", "dependencies": [ null ] },
|
{ "name": "independent test 1", "dependencies": [ null ] },
|
||||||
{ "name": "independent test 2", "dependencies": [ null ] },
|
{ "name": "independent test 2", "dependencies": [ null ] },
|
||||||
{ "name": "dependent test", "dependencies": [ "independent test 1" ] },
|
{ "name": "dependent test", "dependencies": [ "independent test 1" ] },
|
||||||
{ "name": "curses dialog", "dependencies": [ null ] }
|
{ "name": "curses dialog", "dependencies": [ null ] },
|
||||||
|
{ "name": "fail", "dependencies": [ null ] }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,18 @@
|
||||||
"rectify": false,
|
"rectify": false,
|
||||||
"shell": "/usr/bin/env bash",
|
"shell": "/usr/bin/env bash",
|
||||||
"environment": "environments/examplar.variables"
|
"environment": "environments/examplar.variables"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fail",
|
||||||
|
"target": "components/fail.bash",
|
||||||
|
"rectifier": "",
|
||||||
|
"active": true,
|
||||||
|
"required": false,
|
||||||
|
"user": "bagira",
|
||||||
|
"group": "bagira",
|
||||||
|
"rectify": false,
|
||||||
|
"shell": "/usr/bin/env bash",
|
||||||
|
"environment": "environments/examplar.variables"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue