Last active
January 9, 2018 17:11
-
-
Save Elizafox/95cd4f66764d53e6c6cb4bf483517728 to your computer and use it in GitHub Desktop.
C++ process stuff
This file contains 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
/* sunrise - a C++ installer for alpine | |
* Coypright (C) 2018 Interlinked Foundation | |
* All rights reserved | |
*/ | |
#include <string> // std::string | |
#include <vector> // std::vector | |
#include <algorithm> // std::transform | |
#include <iterator> // std::back_inserter | |
#include <exception> // std::generic_category | |
#include <system_error> // std::system_error | |
#include <cerrno> // errno | |
#include <csignal> // raise, SIGQUIT | |
#include <unistd.h> // STD*_FILENO, close, dup2, pipe, fork, exec, kill, | |
// pid_t | |
#include <sys/wait.h> // waitpid, WEXITED, WIFEXITED, WNOHANG | |
#include "process.hpp" // SubProcess, SubProcessStatus | |
namespace sunrise { namespace process { | |
SubProcess::SubProcess(std::vector<std::string> &args) | |
{ | |
if(SubProcess::fork()) | |
SubProcess::exec(args); | |
} | |
SubProcess::~SubProcess() | |
{ | |
SubProcessStatus sp_status = status(); | |
if(!sp_status.exited) | |
// End process | |
::kill(pid, SIGQUIT); | |
if(p_stdin >= 0) | |
::close(p_stdin); | |
if(p_stdout >= 0) | |
::close(p_stdout); | |
if(p_stderr >= 0) | |
::close(p_stderr); | |
} | |
bool SubProcess::fork() | |
{ | |
// Perform the fork before exec | |
// returns true if child, false if parent | |
int pipe_stdin[2], pipe_stdout[2], pipe_stderr[2]; | |
// Create our pipes | |
if(::pipe(pipe_stdin) < 0) | |
{ | |
throw std::system_error(errno, std::generic_category(), | |
"Could not create stdin pipe"); | |
} | |
if(::pipe(pipe_stdout) < 0) | |
{ | |
::close(pipe_stdin[0]); | |
::close(pipe_stdin[1]); | |
throw std::system_error(errno, std::generic_category(), | |
"Could not create stdout pipe"); | |
} | |
if(::pipe(pipe_stderr) < 0) | |
{ | |
::close(pipe_stdin[0]); | |
::close(pipe_stdin[1]); | |
::close(pipe_stdout[0]); | |
::close(pipe_stdout[1]); | |
throw std::system_error(errno, std::generic_category(), | |
"Could not create stderr pipe"); | |
} | |
switch((pid = ::fork())) | |
{ | |
case -1: | |
// Error | |
throw std::system_error(errno, std::generic_category(), | |
"Could not fork"); | |
case 0: | |
// Child | |
// Close original file descriptors | |
::close(STDIN_FILENO); | |
::close(STDOUT_FILENO); | |
::close(STDERR_FILENO); | |
// Close extra fd's | |
::close(pipe_stdin[PIPE_W]); | |
::close(pipe_stdout[PIPE_R]); | |
::close(pipe_stderr[PIPE_R]); | |
// Redirect file descriptors | |
::dup2(pipe_stdin[PIPE_R], STDIN_FILENO); | |
::dup2(pipe_stdout[PIPE_W], STDOUT_FILENO); | |
::dup2(pipe_stderr[PIPE_W], STDERR_FILENO); | |
return true; | |
default: | |
// Parent | |
// Close whatever we don't need | |
::close(pipe_stdin[PIPE_R]); | |
::close(pipe_stdout[PIPE_W]); | |
::close(pipe_stderr[PIPE_W]); | |
// Copy | |
p_stdin = pipe_stdin[PIPE_W]; | |
p_stdout = pipe_stdout[PIPE_R]; | |
p_stderr = pipe_stdout[PIPE_R]; | |
return false; | |
} | |
} | |
void SubProcess::exec(std::vector<std::string> &args) | |
{ | |
// Convert into char vector | |
std::vector<const char *> args_c; | |
args_c.reserve(args.size() + 1); | |
std::transform(args.begin(), args.end(), | |
std::back_inserter(args_c), | |
[](std::string const &a) { return a.c_str(); }); | |
args_c.push_back(""); // Null-terminated | |
// launch | |
::execv(args_c[0], const_cast<char * const *>(&(args_c[1]))); | |
// If we get here, execv failed | |
// Terminate ourselves with extreme prejudice | |
::raise(SIGQUIT); | |
} | |
SubProcessStatus SubProcess::wait() | |
{ | |
// Wait for child to terminate | |
int wstatus = 0; | |
::waitpid(pid, &wstatus, WEXITED); | |
return SubProcessStatus(true, WEXITSTATUS(wstatus)); | |
} | |
SubProcessStatus SubProcess::status() | |
{ | |
// Get status of child | |
int wstatus = 0; | |
::waitpid(pid, &wstatus, WNOHANG | WEXITED); | |
if(WIFEXITED(wstatus)) | |
{ | |
return SubProcessStatus(true, WEXITSTATUS(wstatus)); | |
} | |
else | |
{ | |
return SubProcessStatus(false); | |
} | |
} | |
} } // namespace |
This file contains 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
/* sunrise - a C++ installer for alpine | |
* Coypright (C) 2018 Interlinked Foundation | |
* All rights reserved | |
*/ | |
#pragma once | |
#include <string> // std::string | |
#include <vector> // std::vector | |
#include <unistd.h> // pid_t | |
namespace sunrise { namespace process { | |
class SubProcessStatus | |
{ | |
// Status of a subprocess | |
public: | |
bool exited = false; | |
int ret = 0; | |
SubProcessStatus(bool exited, int ret) : | |
exited(exited), | |
ret(ret) | |
{ | |
} | |
SubProcessStatus(bool exited) : | |
exited(exited) | |
{ | |
} | |
SubProcessStatus() | |
{ | |
} | |
}; | |
class SubProcess | |
{ | |
public: | |
int p_stdin = -1, p_stdout = -1, p_stderr = -1; | |
SubProcess(std::vector<std::string> &); | |
~SubProcess(); | |
SubProcessStatus wait(); | |
SubProcessStatus status(); | |
private: | |
virtual bool fork(); | |
virtual void exec(std::vector<std::string> &); | |
pid_t pid; | |
// for pipe() | |
static const int PIPE_R = 0; | |
static const int PIPE_W = 1; | |
}; | |
} } // namespace |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment