2022-05-14 02:36:12 +00:00
# include <pthread.h>
2022-03-14 23:09:25 +00:00
# include <libreborn/exec.h>
2022-07-20 06:58:14 +00:00
// Set Environmental Variable
static void setenv_safe ( const char * name , const char * value ) {
if ( value ! = NULL ) {
setenv ( name , value , 1 ) ;
} else {
unsetenv ( name ) ;
}
}
void set_and_print_env ( const char * name , const char * value ) {
// Print New Value
DEBUG ( " Set %s = %s " , name , value ! = NULL ? value : " (unset) " ) ;
// Set The Value
setenv_safe ( name , value ) ;
}
2022-03-14 23:09:25 +00:00
// Safe execvpe()
2022-07-20 06:58:14 +00:00
# define handle_environmental_variable(var) \
{ \
const char * full_var = is_arm_component ? " MCPI_ARM_ " var : " MCPI_NATIVE_ " var ; \
const char * var_value = getenv ( full_var ) ; \
set_and_print_env ( var , var_value ) ; \
}
void setup_exec_environment ( int is_arm_component ) {
for_each_special_environmental_variable ( handle_environmental_variable ) ;
}
2022-03-14 23:09:25 +00:00
__attribute__ ( ( noreturn ) ) void safe_execvpe ( const char * const argv [ ] , const char * const envp [ ] ) {
2022-07-02 22:14:23 +00:00
// Log
DEBUG ( " Running Command: " ) ;
for ( int i = 0 ; argv [ i ] ! = NULL ; i + + ) {
DEBUG ( " %s " , argv [ i ] ) ;
}
// Run
2022-03-14 23:09:25 +00:00
int ret = execvpe ( argv [ 0 ] , ( char * const * ) argv , ( char * const * ) envp ) ;
if ( ret = = - 1 ) {
2022-07-04 20:44:00 +00:00
if ( errno = = ENOENT & & strcmp ( argv [ 0 ] , " qemu-qrm " ) ) {
ERR ( " Unable to find QEMU! To install on Ubuntu/Debian, run \" sudo apt install qemu-user \" . To install on Arch Linux, run \" sudo pacman -Sy qemu-user \" . " ) ;
}
2022-03-14 23:09:25 +00:00
ERR ( " Unable To Execute Program: %s: %s " , argv [ 0 ] , strerror ( errno ) ) ;
} else {
IMPOSSIBLE ( ) ;
}
}
// Chop Off Last Component
void chop_last_component ( char * * str ) {
size_t length = strlen ( * str ) ;
for ( size_t i = 0 ; i < length ; i + + ) {
size_t j = length - i - 1 ;
if ( ( * str ) [ j ] = = ' / ' ) {
( * str ) [ j ] = ' \0 ' ;
break ;
}
}
}
// Get Binary Directory (Remember To Free)
char * get_binary_directory ( ) {
// Get Path To Current Executable
char * exe = realpath ( " /proc/self/exe " , NULL ) ;
ALLOC_CHECK ( exe ) ;
// Chop Off Last Component
chop_last_component ( & exe ) ;
// Return
return exe ;
}
// Run Command And Get Output
2022-05-15 17:51:28 +00:00
char * run_command ( const char * const command [ ] , int * exit_status ) {
2022-03-14 23:09:25 +00:00
// Store Output
int output_pipe [ 2 ] ;
safe_pipe2 ( output_pipe , 0 ) ;
// Run
pid_t ret = fork ( ) ;
if ( ret = = - 1 ) {
ERR ( " Unable To Run Command: %s " , strerror ( errno ) ) ;
} else if ( ret = = 0 ) {
// Child Process
// Pipe stdout
dup2 ( output_pipe [ 1 ] , STDOUT_FILENO ) ;
close ( output_pipe [ 0 ] ) ;
close ( output_pipe [ 1 ] ) ;
2022-07-20 06:58:14 +00:00
// Setup Environment
setup_exec_environment ( 0 ) ;
2022-03-14 23:09:25 +00:00
// Run
safe_execvpe ( command , ( const char * const * ) environ ) ;
} else {
// Parent Process
2022-05-14 02:36:12 +00:00
track_child ( ret ) ;
2022-03-14 23:09:25 +00:00
// Read stdout
close ( output_pipe [ 1 ] ) ;
char * output = NULL ;
2022-03-16 23:51:33 +00:00
# define BUFFER_SIZE 1024
char buf [ BUFFER_SIZE ] ;
2022-05-14 02:36:12 +00:00
ssize_t bytes_read = 0 ;
2022-03-16 23:51:33 +00:00
while ( ( bytes_read = read ( output_pipe [ 0 ] , ( void * ) buf , BUFFER_SIZE - 1 /* Account For NULL-Terminator */ ) ) > 0 ) {
buf [ bytes_read ] = ' \0 ' ;
2022-04-16 20:38:09 +00:00
string_append ( & output , " %s " , buf ) ;
2022-03-14 23:09:25 +00:00
}
close ( output_pipe [ 0 ] ) ;
// Get Return Code
int status ;
waitpid ( ret , & status , 0 ) ;
2022-05-14 02:36:12 +00:00
untrack_child ( ret ) ;
2022-05-15 17:51:28 +00:00
if ( exit_status ! = NULL ) {
* exit_status = status ;
2022-05-03 02:44:10 +00:00
}
2022-03-14 23:09:25 +00:00
// Return
return output ;
}
}
2022-05-14 02:36:12 +00:00
2022-05-15 17:51:28 +00:00
// Get Exit Status String
void get_exit_status_string ( int status , char * * out ) {
if ( out ! = NULL ) {
* out = NULL ;
if ( WIFEXITED ( status ) ) {
safe_asprintf ( out , " : Exit Code: %i " , WEXITSTATUS ( status ) ) ;
} else if ( WIFSIGNALED ( status ) ) {
safe_asprintf ( out , " : Signal: %i%s " , WTERMSIG ( status ) , WCOREDUMP ( status ) ? " (Core Dumped) " : " " ) ;
} else {
safe_asprintf ( out , " : Terminated " ) ;
}
}
}
2022-05-14 02:36:12 +00:00
// Track Children
# define MAX_CHILDREN 128
static pid_t children [ MAX_CHILDREN ] = { 0 } ;
static pthread_mutex_t children_lock = PTHREAD_MUTEX_INITIALIZER ;
void track_child ( pid_t pid ) {
pthread_mutex_lock ( & children_lock ) ;
for ( int i = 0 ; i < MAX_CHILDREN ; i + + ) {
if ( children [ i ] = = 0 ) {
children [ i ] = pid ;
break ;
}
}
pthread_mutex_unlock ( & children_lock ) ;
}
void untrack_child ( pid_t pid ) {
pthread_mutex_lock ( & children_lock ) ;
for ( int i = 0 ; i < MAX_CHILDREN ; i + + ) {
if ( children [ i ] = = pid ) {
children [ i ] = 0 ;
}
}
pthread_mutex_unlock ( & children_lock ) ;
}
void murder_children ( ) {
pthread_mutex_lock ( & children_lock ) ;
for ( int i = 0 ; i < MAX_CHILDREN ; i + + ) {
if ( children [ i ] ! = 0 ) {
kill ( children [ i ] , SIGTERM ) ;
}
}
pthread_mutex_unlock ( & children_lock ) ;
}