371 lines
20 KiB
Plaintext
371 lines
20 KiB
Plaintext
![]() |
[1mdiff --git a/src/lcpex/liblcpex.cpp b/src/lcpex/liblcpex.cpp[m
|
|||
|
[1mindex b0e033e..db79c19 100644[m
|
|||
|
[1m--- a/src/lcpex/liblcpex.cpp[m
|
|||
|
[1m+++ b/src/lcpex/liblcpex.cpp[m
|
|||
|
[36m@@ -1,5 +1,69 @@[m
|
|||
|
#include "liblcpex.h"[m
|
|||
|
[32m+[m[32m#include <cstring>[m
|
|||
|
[32m+[m[32m#include <stdexcept>[m
|
|||
|
[32m+[m[32m#include <signal.h>[m
|
|||
|
[32m+[m[32m#include <string>[m
|
|||
|
[32m+[m[32m#include "../logger/Logger.h"[m
|
|||
|
[32m+[m[32m#include "FileHandle.h"[m
|
|||
|
[32m+[m[32m#define BUFFER_SIZE 1024[m
|
|||
|
[32m+[m
|
|||
|
[32m+[m
|
|||
|
[32m+[m[32m// Initialize logger[m
|
|||
|
[32m+[m[32mstatic Logger logger(E_INFO, "lcpex");[m
|
|||
|
[32m+[m[32mstd::string user = logger.get_user_name();[m
|
|||
|
[32m+[m[32mstd::string group = logger.get_group_name();[m
|
|||
|
[32m+[m
|
|||
|
[32m+[m[32mvoid signal_handler(int sig) {[m
|
|||
|
[32m+[m[32m std::string command = "signal_handler"; // Command context[m
|
|||
|
[32m+[m
|
|||
|
[32m+[m[32m // Create an instance of Logger (you can change the log level and mask accordingly)[m
|
|||
|
[32m+[m[32m // Log the signal handling[m
|
|||
|
[32m+[m[32m if (sig == SIGCHLD) {[m
|
|||
|
[32m+[m[32m // Log that SIGCHLD was received, but leave the exit status to the parent[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_INFO", "SIGCHLD received. A child process ended.", user, group, command);[m
|
|||
|
[32m+[m[32m } else if (sig == SIGINT) {[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", "SIGINT received. Gracefully terminating...", user, group, command);[m
|
|||
|
[32m+[m[32m } else if (sig == SIGTERM) {[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", "SIGTERM received. Terminating...", user, group, command);[m
|
|||
|
[32m+[m[32m } else if (sig == SIGSEGV) {[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", "SIGSEGV received. Possible segmentation fault.", user, group, command);[m
|
|||
|
[32m+[m[32m } else {[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", "Unhandled signal received", user, group, command);[m
|
|||
|
[32m+[m[32m }[m
|
|||
|
[32m+[m[32m}[m
|
|||
|
[32m+[m
|
|||
|
[32m+[m[32m// Setup signal registrations[m
|
|||
|
[32m+[m[32mvoid setup_signal_handlers() {[m
|
|||
|
[32m+[m[32m struct sigaction sa;[m
|
|||
|
[32m+[m[32m sa.sa_handler = signal_handler; // <-- handler function[m
|
|||
|
[32m+[m[32m sigemptyset(&sa.sa_mask);[m
|
|||
|
[32m+[m[32m sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;[m
|
|||
|
[32m+[m[32m std::string command = "setup_signal_handlers"; // Command context[m
|
|||
|
[32m+[m
|
|||
|
[32m+[m[32m // SIGCHLD[m
|
|||
|
[32m+[m[32m if (sigaction(SIGCHLD, &sa, nullptr) == -1) {[m
|
|||
|
[32m+[m[32m std::string error_message = "Failed to set SIGCHLD handler: " + std::string(strerror(errno));[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", error_message, user, group, command); // Log to JSON file[m
|
|||
|
[32m+[m[32m }[m
|
|||
|
[32m+[m
|
|||
|
[32m+[m[32m // SIGINT[m
|
|||
|
[32m+[m[32m if (sigaction(SIGINT, &sa, nullptr) == -1) {[m
|
|||
|
[32m+[m[32m std::string error_message = "Failed to set SIGINT handler: " + std::string(strerror(errno));[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", error_message, user, group, command); // Log to JSON file[m
|
|||
|
[32m+[m[32m }[m
|
|||
|
[m
|
|||
|
[32m+[m[32m // SIGTERM[m
|
|||
|
[32m+[m[32m if (sigaction(SIGTERM, &sa, nullptr) == -1) {[m
|
|||
|
[32m+[m[32m std::string error_message = "Failed to set SIGTERM handler: " + std::string(strerror(errno));[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", error_message, user, group, command); // Log to JSON file[m
|
|||
|
[32m+[m[32m }[m
|
|||
|
[32m+[m
|
|||
|
[32m+[m[32m // SIGSEGV[m
|
|||
|
[32m+[m[32m if (sigaction(SIGSEGV, &sa, nullptr) == -1) {[m
|
|||
|
[32m+[m[32m std::string error_message = "Failed to set SIGSEGV handler: " + std::string(strerror(errno));[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", error_message, user, group, command); // Log to JSON file[m
|
|||
|
[32m+[m[32m }[m
|
|||
|
[32m+[m[32m}[m
|
|||
|
[m
|
|||
|
std::string prefix_generator([m
|
|||
|
std::string command,[m
|
|||
|
[36m@@ -37,8 +101,12 @@[m [mstd::string prefix_generator([m
|
|||
|
// it's not a shell command, so we can just execute it directly[m
|
|||
|
prefix = command;[m
|
|||
|
}[m
|
|||
|
[31m- std::cout << "LAUNCHER: " << prefix << std::endl;[m
|
|||
|
[32m+[m
|
|||
|
[32m+[m[32m // Log the message to JSON file[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_INFO", "LAUNCHER: " + prefix, user, group, command);[m
|
|||
|
[32m+[m[32m //logger.log(E_INFO, "LAUNCHER: " + prefix);[m
|
|||
|
return prefix;[m
|
|||
|
[32m+[m
|
|||
|
}[m
|
|||
|
[m
|
|||
|
[m
|
|||
|
[36m@@ -69,6 +137,7 @@[m [mint lcpex([m
|
|||
|
environment_file_path[m
|
|||
|
);[m
|
|||
|
command = prefix;[m
|
|||
|
[32m+[m[32m setup_signal_handlers();[m
|
|||
|
[m
|
|||
|
// if we are forcing a pty, then we will use the vpty library[m
|
|||
|
if( force_pty )[m
|
|||
|
[36m@@ -91,10 +160,14 @@[m [mint lcpex([m
|
|||
|
*/[m
|
|||
|
void set_cloexec_flag(int fd)[m
|
|||
|
{[m
|
|||
|
[32m+[m[32m std::string command = "set_cloexec_flag";[m
|
|||
|
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)[m
|
|||
|
{[m
|
|||
|
[31m- perror("fcntl");[m
|
|||
|
[31m- exit(1);[m
|
|||
|
[32m+[m[32m std::string error_message = "fcntl(F_SETFD) failed for fd " + std::to_string(fd);[m
|
|||
|
[32m+[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", error_message, user, group, command);[m
|
|||
|
[32m+[m
|
|||
|
[32m+[m[32m throw std::runtime_error("fcntl(F_SETFD) failed for fd " + std::to_string(fd));[m
|
|||
|
}[m
|
|||
|
}[m
|
|||
|
[m
|
|||
|
[36m@@ -125,6 +198,13 @@[m [mvoid set_cloexec_flag(int fd)[m
|
|||
|
void run_child_process(bool context_override, const char* context_user, const char* context_group, char* processed_command[], int fd_child_stdout_pipe[], int fd_child_stderr_pipe[]) {[m
|
|||
|
while ((dup2(fd_child_stdout_pipe[WRITE_END], STDOUT_FILENO) == -1) && (errno == EINTR)) {}[m
|
|||
|
while ((dup2(fd_child_stderr_pipe[WRITE_END], STDERR_FILENO) == -1) && (errno == EINTR)) {}[m
|
|||
|
[32m+[m[32m // Close unused pipe ends to avoid leaks[m
|
|||
|
[32m+[m
|
|||
|
[32m+[m[32m close(fd_child_stdout_pipe[READ_END]);[m
|
|||
|
[32m+[m[32m close(fd_child_stdout_pipe[WRITE_END]);[m
|
|||
|
[32m+[m[32m close(fd_child_stderr_pipe[READ_END]);[m
|
|||
|
[32m+[m[32m close(fd_child_stderr_pipe[WRITE_END]);[m
|
|||
|
[32m+[m[32m std::string command = "run_child_process"; // Command context[m
|
|||
|
[m
|
|||
|
if ( context_override ) {[m
|
|||
|
int context_result = set_identity_context(context_user, context_group);[m
|
|||
|
[36m@@ -132,34 +212,38 @@[m [mvoid run_child_process(bool context_override, const char* context_user, const ch[m
|
|||
|
case IDENTITY_CONTEXT_ERRORS::ERROR_NONE:[m
|
|||
|
break;[m
|
|||
|
case IDENTITY_CONTEXT_ERRORS::ERROR_NO_SUCH_USER:[m
|
|||
|
[31m- std::cerr << "REX: Aborting: context user not found: " << context_user << std::endl;[m
|
|||
|
[31m- exit(1);[m
|
|||
|
[32m+[m[32m logger.log(E_FATAL, "Aborting: context user not found: " + std::string(context_user));[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", "Aborting: context user not found: " + std::string(context_user), user, group, command);[m
|
|||
|
[32m+[m[32m _exit(1);[m
|
|||
|
break;[m
|
|||
|
case IDENTITY_CONTEXT_ERRORS::ERROR_NO_SUCH_GROUP:[m
|
|||
|
[31m- std::cerr << "REX: Aborting: context group not found: " << context_group << std::endl;[m
|
|||
|
[31m- exit(1);[m
|
|||
|
[32m+[m[32m logger.log(E_FATAL, "Aborting: context group not found: " + std::string(context_group));[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", "Aborting: context group not found: " + std::string(context_group), user, group, command);[m
|
|||
|
[32m+[m[32m _exit(1);[m
|
|||
|
break;[m
|
|||
|
case IDENTITY_CONTEXT_ERRORS::ERROR_SETGID_FAILED:[m
|
|||
|
[31m- std::cerr << "REX: Aborting: Setting GID failed: " << context_user << "/" << context_group << std::endl;[m
|
|||
|
[31m- exit(1);[m
|
|||
|
[32m+[m[32m logger.log(E_FATAL, "Aborting: Setting GID failed: " + std::string(context_user) + "/" + std::string(context_group));[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", "Aborting: Setting GID failed: " + std::string(context_user) + "/" + std::string(context_group), user, group, command);[m
|
|||
|
[32m+[m[32m _exit(1);[m
|
|||
|
break;[m
|
|||
|
case IDENTITY_CONTEXT_ERRORS::ERROR_SETUID_FAILED:[m
|
|||
|
[31m- std::cerr << "REX: Aborting: Setting UID failed: " << context_user << "/" << context_group << std::endl;[m
|
|||
|
[31m- exit(1);[m
|
|||
|
[32m+[m[32m logger.log(E_FATAL, "Aborting: Setting UID failed: " + std::string(context_user) + "/" + std::string(context_group));[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", "Aborting: Setting UID failed: " + std::string(context_user) + "/" + std::string(context_group), user, group, command);[m
|
|||
|
[32m+[m[32m _exit(1);[m
|
|||
|
break;[m
|
|||
|
default:[m
|
|||
|
[31m- std::cerr << "REX: Aborting: Unknown error while setting identity context." << std::endl;[m
|
|||
|
[31m- exit(1);[m
|
|||
|
[32m+[m[32m logger.log(E_FATAL, "Aborting: Unknown error while setting identity context.");[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", "Aborting: Unknown error while setting identity context.", user, group, command);[m
|
|||
|
[32m+[m[32m _exit(1);[m
|
|||
|
break;[m
|
|||
|
}[m
|
|||
|
}[m
|
|||
|
[31m-[m
|
|||
|
int exit_code = execvp(processed_command[0], processed_command);[m
|
|||
|
[31m- perror("failed on execvp in child");[m
|
|||
|
[31m- exit(exit_code);[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", "failed on execvp in child", user, group, command);[m
|
|||
|
[32m+[m[32m logger.log(E_FATAL, "failed on execvp in child");[m
|
|||
|
[32m+[m[32m _Exit(exit_code);[m
|
|||
|
}[m
|
|||
|
[m
|
|||
|
[31m-[m
|
|||
|
int execute([m
|
|||
|
std::string command,[m
|
|||
|
FILE * stdout_log_fh,[m
|
|||
|
[36m@@ -169,6 +253,8 @@[m [mint execute([m
|
|||
|
std::string context_group,[m
|
|||
|
bool environment_supplied[m
|
|||
|
){[m
|
|||
|
[32m+[m
|
|||
|
[32m+[m[32m try {[m
|
|||
|
// this does three things:[m
|
|||
|
// - execute a dang string as a subprocess command[m
|
|||
|
// - capture child stdout/stderr to respective log files[m
|
|||
|
[36m@@ -190,13 +276,13 @@[m [mint execute([m
|
|||
|
int fd_child_stderr_pipe[2];[m
|
|||
|
[m
|
|||
|
if ( pipe(fd_child_stdout_pipe ) == -1 ) {[m
|
|||
|
[31m- perror( "child stdout pipe" );[m
|
|||
|
[31m- exit( 1 );[m
|
|||
|
[32m+[m[32m throw std::runtime_error("Failed to create stdout pipe");[m
|
|||
|
}[m
|
|||
|
[m
|
|||
|
if ( pipe( fd_child_stderr_pipe ) == -1 ) {[m
|
|||
|
[31m- perror( "child stderr pipe" );[m
|
|||
|
[31m- exit( 1 );[m
|
|||
|
[32m+[m[32m close(fd_child_stdout_pipe[0]);[m
|
|||
|
[32m+[m[32m close(fd_child_stdout_pipe[1]);[m
|
|||
|
[32m+[m[32m throw std::runtime_error("Failed to create stderr pipe");[m
|
|||
|
}[m
|
|||
|
[m
|
|||
|
// using O_CLOEXEC to ensure that the child process closes the file descriptors[m
|
|||
|
[36m@@ -206,15 +292,20 @@[m [mint execute([m
|
|||
|
set_cloexec_flag( fd_child_stderr_pipe[WRITE_END] );[m
|
|||
|
[m
|
|||
|
// status result basket for the parent process to capture the child's exit status[m
|
|||
|
[31m- int status = 616;[m
|
|||
|
[32m+[m[32m int status;[m
|
|||
|
pid_t pid = fork();[m
|
|||
|
[m
|
|||
|
switch( pid ) {[m
|
|||
|
case -1:[m
|
|||
|
{[m
|
|||
|
// fork failed[m
|
|||
|
[31m- perror("fork failure");[m
|
|||
|
[31m- exit(1);[m
|
|||
|
[32m+[m[32m logger.log(E_FATAL, "fork failure: " + std::string(strerror(errno)));[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", "fork failure: " + std::string(strerror(errno)), user, group, command);[m
|
|||
|
[32m+[m[32m close(fd_child_stdout_pipe[0]); // Pipe Leaks on Error Paths[m
|
|||
|
[32m+[m[32m close(fd_child_stdout_pipe[1]); // Pipe Leaks on Error Paths[m
|
|||
|
[32m+[m[32m close(fd_child_stderr_pipe[0]); // Pipe Leaks on Error Paths[m
|
|||
|
[32m+[m[32m close(fd_child_stderr_pipe[1]); // Pipe Leaks on Error Paths[m
|
|||
|
[32m+[m[32m throw std::runtime_error("fork() failed: " + std::string(strerror(errno)));[m
|
|||
|
}[m
|
|||
|
[m
|
|||
|
case 0:[m
|
|||
|
[36m@@ -234,14 +325,23 @@[m [mint execute([m
|
|||
|
{[m
|
|||
|
// parent process[m
|
|||
|
[m
|
|||
|
[32m+[m[32m FdGuard stdout_read_guard(fd_child_stdout_pipe[READ_END]);[m
|
|||
|
[32m+[m[32m FdGuard stderr_read_guard(fd_child_stderr_pipe[READ_END]);[m
|
|||
|
[32m+[m[32m FdGuard stdout_write_guard(fd_child_stdout_pipe[WRITE_END]);[m
|
|||
|
[32m+[m[32m FdGuard stderr_write_guard(fd_child_stderr_pipe[WRITE_END]);[m
|
|||
|
[32m+[m
|
|||
|
[32m+[m[32m // We don't need WRITE_ENDs in parent, close them now[m
|
|||
|
[32m+[m[32m stdout_write_guard.reset(); // Closes and sets fd to -1[m
|
|||
|
[32m+[m[32m stderr_write_guard.reset();[m
|
|||
|
[32m+[m
|
|||
|
// The parent process has no need to access the entrance to the pipe, so fd_child_*_pipe[1|0] should be closed[m
|
|||
|
// within that process too:[m
|
|||
|
[31m- close(fd_child_stdout_pipe[WRITE_END]);[m
|
|||
|
[31m- close(fd_child_stderr_pipe[WRITE_END]);[m
|
|||
|
[m
|
|||
|
[31m- // attempt to write to stdout,stderr from child as well as to write each to file[m
|
|||
|
[31m- char buf[BUFFER_SIZE];[m
|
|||
|
[m
|
|||
|
[32m+[m[32m // attempt to write to stdout,stderr from child as well as to write each to file[m
|
|||
|
[32m+[m[32m char buf[BUFFER_SIZE] = {0};[m
|
|||
|
[32m+[m[32m std::strncpy(buf, command.c_str(), BUFFER_SIZE - 1);[m
|
|||
|
[32m+[m[32m buf[BUFFER_SIZE - 1] = '\0';[m
|
|||
|
// contains the byte count of the last read from the pipe[m
|
|||
|
ssize_t byte_count;[m
|
|||
|
[m
|
|||
|
[36m@@ -251,11 +351,11 @@[m [mint execute([m
|
|||
|
// populate the watched_fds array[m
|
|||
|
[m
|
|||
|
// child STDOUT to parent[m
|
|||
|
[31m- watched_fds[CHILD_PIPE_NAMES::STDOUT_READ].fd = fd_child_stdout_pipe[READ_END];[m
|
|||
|
[32m+[m[32m watched_fds[CHILD_PIPE_NAMES::STDOUT_READ].fd = stdout_read_guard.get();[m
|
|||
|
watched_fds[CHILD_PIPE_NAMES::STDOUT_READ].events = POLLIN;[m
|
|||
|
[m
|
|||
|
// child STDERR to parent[m
|
|||
|
[31m- watched_fds[CHILD_PIPE_NAMES::STDERR_READ].fd = fd_child_stderr_pipe[READ_END];[m
|
|||
|
[32m+[m[32m watched_fds[CHILD_PIPE_NAMES::STDERR_READ].fd = stderr_read_guard.get();[m
|
|||
|
watched_fds[CHILD_PIPE_NAMES::STDERR_READ].events = POLLIN;[m
|
|||
|
[m
|
|||
|
// number of files poll() reports as ready[m
|
|||
|
[36m@@ -275,8 +375,9 @@[m [mint execute([m
|
|||
|
[m
|
|||
|
if (num_files_readable == -1) {[m
|
|||
|
// error occurred in poll()[m
|
|||
|
[31m- perror("poll");[m
|
|||
|
[31m- exit(1);[m
|
|||
|
[32m+[m[32m logger.log(E_FATAL, "poll() failed: " + std::string(strerror(errno)));[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", "poll() failed", user, group, command);[m
|
|||
|
[32m+[m[32m throw std::runtime_error("poll() failed");[m
|
|||
|
}[m
|
|||
|
if (num_files_readable == 0) {[m
|
|||
|
// poll reports no files readable[m
|
|||
|
[36m@@ -291,7 +392,10 @@[m [mint execute([m
|
|||
|
if (byte_count == -1) {[m
|
|||
|
if (errno == EAGAIN) { continue; } else {[m
|
|||
|
// error reading from pipe[m
|
|||
|
[31m- perror("read");[m
|
|||
|
[32m+[m[32m logger.log(E_FATAL, "Error while reading: " + std::string(strerror(errno)));[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", "Error while reading from pipe", user, group, command);[m
|
|||
|
[32m+[m[32m stdout_read_guard.reset(-1);[m
|
|||
|
[32m+[m[32m stderr_read_guard.reset(-1);[m
|
|||
|
exit(EXIT_FAILURE);[m
|
|||
|
}[m
|
|||
|
[m
|
|||
|
[36m@@ -312,13 +416,17 @@[m [mint execute([m
|
|||
|
write_all(STDERR_FILENO, buf, byte_count);[m
|
|||
|
} else {[m
|
|||
|
// this should never happen[m
|
|||
|
[31m- perror("Logic error!");[m
|
|||
|
[32m+[m[32m logger.log(E_FATAL, "Logic error: unexpected pipe index.");[m
|
|||
|
exit(EXIT_FAILURE);[m
|
|||
|
}[m
|
|||
|
}[m
|
|||
|
}[m
|
|||
|
if (watched_fds[this_fd].revents & POLLERR) {[m
|
|||
|
[31m- close(watched_fds[this_fd].fd);[m
|
|||
|
[32m+[m[32m if (this_fd == CHILD_PIPE_NAMES::STDOUT_READ) {[m
|
|||
|
[32m+[m[32m stdout_read_guard.reset(-1);[m
|
|||
|
[32m+[m[32m } else if (this_fd == CHILD_PIPE_NAMES::STDERR_READ) {[m
|
|||
|
[32m+[m[32m stderr_read_guard.reset(-1);[m
|
|||
|
[32m+[m[32m }[m
|
|||
|
break_out = true;[m
|
|||
|
}[m
|
|||
|
if (watched_fds[this_fd].revents & POLLHUP) {[m
|
|||
|
[36m@@ -333,21 +441,46 @@[m [mint execute([m
|
|||
|
waitpid(pid, &status, 0);[m
|
|||
|
[m
|
|||
|
// Drain the pipes before exiting[m
|
|||
|
[31m- while ((byte_count = read(fd_child_stdout_pipe[READ_END], buf, BUFFER_SIZE)) > 0) {[m
|
|||
|
[32m+[m[32m while ((byte_count = read(stdout_read_guard.get(), buf, BUFFER_SIZE)) > 0) {[m
|
|||
|
write_all(stdout_log_fh->_fileno, buf, byte_count);[m
|
|||
|
write_all(STDOUT_FILENO, buf, byte_count);[m
|
|||
|
}[m
|
|||
|
[31m- while ((byte_count = read(fd_child_stderr_pipe[READ_END], buf, BUFFER_SIZE)) > 0) {[m
|
|||
|
[32m+[m[32m while ((byte_count = read(stderr_read_guard.get(), buf, BUFFER_SIZE)) > 0) {[m
|
|||
|
write_all(stderr_log_fh->_fileno, buf, byte_count);[m
|
|||
|
write_all(STDERR_FILENO, buf, byte_count);[m
|
|||
|
}[m
|
|||
|
[m
|
|||
|
[31m- if WIFEXITED(status) {[m
|
|||
|
[31m- return WEXITSTATUS(status);[m
|
|||
|
[31m- } else {[m
|
|||
|
[31m- return -617;[m
|
|||
|
[32m+[m[32m int status;[m
|
|||
|
[32m+[m[32m pid_t pid = waitpid(-1, &status, WNOHANG); // Non-blocking wait for child process[m
|
|||
|
[32m+[m[32m if (pid > 0) { // If a child process has terminated[m
|
|||
|
[32m+[m[32m // Check if the child process exited normally[m
|
|||
|
[32m+[m[32m if (WIFEXITED(status)) {[m
|
|||
|
[32m+[m[32m int exit_code = WEXITSTATUS(status);[m
|
|||
|
[32m+[m[32m logger.log(E_INFO, "Child exited with status " + std::to_string(exit_code));[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_INFO", "Child exited with status " + std::to_string(exit_code), user, group, command);[m
|
|||
|
[32m+[m[32m }[m
|
|||
|
[32m+[m[32m // Check if the child process was terminated by a signal[m
|
|||
|
[32m+[m[32m else if (WIFSIGNALED(status)) {[m
|
|||
|
[32m+[m[32m int signal_number = WTERMSIG(status);[m
|
|||
|
[32m+[m[32m logger.log(E_FATAL, "Process terminated by signal: " + std::to_string(signal_number));[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_FATAL", "Process terminated by signal: " + std::to_string(signal_number), user, group, command);[m
|
|||
|
[32m+[m[32m // Reset signal handler to default before exiting[m
|
|||
|
[32m+[m[32m signal(signal_number, SIG_DFL);[m
|
|||
|
[32m+[m[32m // Return 128 + signal number as the exit code for signal termination[m
|
|||
|
[32m+[m[32m return 128 + signal_number; // POSIX exit code format[m
|
|||
|
[32m+[m[32m }[m
|
|||
|
[32m+[m[32m // Handle unexpected exit conditions[m
|
|||
|
[32m+[m[32m else {[m
|
|||
|
[32m+[m[32m logger.log(E_WARN, "Unknown child exit condition.");[m
|
|||
|
[32m+[m[32m logger.log_to_json_file("E_WARN", "Unknown child exit condition", user, group, command);[m
|
|||
|
[32m+[m[32m }[m
|
|||
|
}[m
|
|||
|
}[m
|
|||
|
}[m
|
|||
|
[32m+[m[32m return 0;[m
|
|||
|
[32m+[m[32m } catch (const std::exception& ex) {[m
|
|||
|
[32m+[m[32m std::cerr << "[LCPEX ERROR] " << ex.what() << std::endl;[m
|
|||
|
[32m+[m[32m return -999;[m
|
|||
|
[32m+[m[32m}[m
|
|||
|
}[m
|
|||
|
[m
|