Created
May 2, 2017 08:06
-
-
Save yohm/5c34fc10d8e7530b3d1d5d055bdcb0b4 to your computer and use it in GitHub Desktop.
invoking a subprocess using fork&exec in a temporal working directory with redirected stdout and stderr and timeout
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <cstdlib> | |
#include <ctime> | |
#include <unistd.h> | |
#include <sys/stat.h> | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
#include <fcntl.h> | |
#include <signal.h> | |
#include <vector> | |
#include <string> | |
int system_with_timeout(std::vector<std::string> args, int timeout, std::string dirname) { | |
pid_t pid; | |
if ((pid = fork()) == 0) { | |
char abspath[PATH_MAX]; | |
realpath( args[0].c_str(), abspath ); | |
char** arg = NULL; | |
arg = new char*[args.size() + 1 ]; | |
for( size_t i=0; i<args.size(); i++ ) { | |
if( i == 0 ) { | |
arg[i] = abspath; | |
} | |
else { | |
arg[i] = (char*) args[i].c_str(); | |
} | |
} | |
arg[ args.size() ] = NULL; | |
int ret = mkdir( dirname.c_str(), 0700 ); | |
if( ret != 0 ) { | |
std::cerr << "failed to create directory : " << dirname << std::endl; | |
exit(1); | |
} | |
ret = chdir( dirname.c_str() ); | |
if( ret != 0 ) { | |
std::cerr << "failed to change directory : " << dirname << std::endl; | |
exit(1); | |
} | |
int fd_out = open("_stdout", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); | |
int fd_err = open("_stderr", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); | |
// read only, create a file if not exist, read permission, write permission | |
dup2( fd_out, 1 ); | |
dup2( fd_err, 2 ); | |
close( fd_out ); | |
close( fd_err ); | |
int rc = execvp( arg[0], (char*const*) arg ); | |
std::cerr << "failed to execute the command. rc : " << rc << std::endl; | |
exit(1); | |
} | |
else if (pid > 0) { | |
int status = 0; | |
time_t begin = std::time(NULL); | |
while( true ) { | |
sleep(1); | |
int ret = waitpid(pid, &status, WNOHANG); | |
if( ret != 0 ) { | |
break; | |
} | |
double diff = std::difftime( std::time(NULL), begin ); | |
if( diff >= timeout ) { | |
std::cerr << " sending sigint" << std::endl; | |
kill( pid, 2 ); | |
} | |
} | |
if( WIFEXITED(status) ) { | |
return WEXITSTATUS(status); | |
} | |
else if( WIFSIGNALED(status) ) { | |
std::cerr << "signaled by signal" << WTERMSIG(status) << std::endl; | |
return -1; | |
} | |
else { | |
std::cerr << "other" << std::endl; | |
return -1; | |
} | |
} | |
std::cerr << "failed to fork" << std::endl; | |
return -1; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
std::vector<std::string> args; | |
args.push_back("/usr/bin/ruby"); | |
args.push_back("-e"); | |
args.push_back("puts 'hello'; $stderr.puts 'world'; sleep 3"); | |
int rc = system_with_timeout( args, 1 , "temp"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment