30 #include <sys/types.h> 
   52     void dupTo( 
int stdxxx ) ; 
 
   53     void write( 
const std::string & ) ;
 
   67         int stdxxx , 
bool clean , 
bool strict_path ,
 
   68         Identity run_as_id , 
bool strict_id ,
 
   69         int exec_error_exit , 
const std::string & exec_error_format ,
 
   70         std::string (*exec_error_format_fn)(std::string,
int) ) ;
 
   72     static std::pair<bool,pid_t> fork() ;
 
   76     static void printError( 
int , 
const std::string & s ) ;
 
   77     std::string execErrorFormat( 
const std::string & format , 
int errno_ ) ;
 
   92     int stdxxx , 
bool clean , 
bool strict_path ,
 
   93     Identity run_as_id , 
bool strict_id ,
 
   94     int exec_error_exit , 
const std::string & exec_error_format ,
 
   95     std::string (*exec_error_format_fn)(std::string,
int) ) :
 
   97             run_as_id,strict_id,exec_error_exit,exec_error_format,exec_error_format_fn) )
 
  108     return m_imp->wait() ;
 
  113     return NewProcessImp::fork() ;
 
  123 G::NewProcessImp::NewProcessImp( 
const Path & exe , 
const StringArray & args , 
 
  124     int stdxxx , 
bool clean , 
bool strict_path ,
 
  125     Identity run_as_id , 
bool strict_id ,
 
  126     int exec_error_exit , 
const std::string & exec_error_format ,
 
  127     std::string (*exec_error_format_fn)(std::string,
int) ) :
 
  132     G_ASSERT( stdxxx == -1 || stdxxx == 1 || stdxxx == 2 ) ;
 
  133     if( stdxxx == 1 ) stdxxx = STDOUT_FILENO ;
 
  134     else if( stdxxx == 2 ) stdxxx = STDERR_FILENO ;
 
  138         throw NewProcess::InvalidPath( exe.
str() ) ;
 
  141             throw NewProcess::Insecure() ;
 
  144     std::pair<bool,pid_t> f = 
fork() ;
 
  145     bool in_child = f.first ;
 
  146     m_child_pid = f.second ;
 
  154                 Process::beOrdinaryForExec( run_as_id ) ;
 
  158             Process::closeFilesExcept( m_pipe.fd() ) ;
 
  159             m_pipe.dupTo( stdxxx ) ;
 
  163             ::signal( SIGPIPE , SIG_DFL ) ;
 
  166             int e = run( exe , args , clean , strict_path ) ;
 
  169             if( exec_error_format_fn != 0 )
 
  170                 printError( stdxxx , (*exec_error_format_fn)(exec_error_format,e) ) ;
 
  171             else if( !exec_error_format.empty() )
 
  172                 printError( stdxxx , execErrorFormat(exec_error_format,e) ) ;
 
  177         ::_exit( exec_error_exit ) ;
 
  182         m_wait_future = NewProcessWaitFuture( m_child_pid , m_pipe.fd() ) ;
 
  186 std::pair<bool,pid_t> G::NewProcessImp::fork()
 
  188     std::cout << std::flush ;
 
  189     std::cerr << std::flush ;
 
  190     pid_t rc = ::fork() ;
 
  191     const bool ok = rc != -1 ;
 
  192     if( !ok ) 
throw NewProcess::CannotFork() ;
 
  193     bool in_child = rc == 0 ;
 
  194     pid_t child_pid = 
static_cast<pid_t
>(rc) ;
 
  195     return std::make_pair( in_child , child_pid ) ;
 
  198 void G::NewProcessImp::printError( 
int stdxxx , 
const std::string & s )
 
  201     G_IGNORE_RETURN( 
int , ::write( stdxxx , s.c_str() , s.length() ) ) ;
 
  204 int G::NewProcessImp::run( 
const G::Path & exe , 
const StringArray & args , 
bool clean , 
bool strict )
 
  207     std::string path( 
"PATH=/usr/bin:/bin" ) ; 
 
  208     std::string ifs( 
"IFS= \t\n" ) ;
 
  209     env[0U] = 
const_cast<char*
>( path.c_str() ) ;
 
  210     env[1U] = 
const_cast<char*
>( ifs.c_str() ) ;
 
  213     char ** argv = 
new char* [ args.size() + 2U ] ;
 
  214     std::string str_exe = exe.
str() ;
 
  215     argv[0U] = 
const_cast<char*
>( str_exe.c_str() ) ;
 
  216     unsigned int argc = 1U ;
 
  217     for( StringArray::const_iterator arg_p = args.begin() ; arg_p != args.end() ; ++arg_p , argc++ )
 
  218         argv[argc] = const_cast<char*>(arg_p->c_str()) ;
 
  219     argv[argc] = nullptr ;
 
  221     if( clean && strict )
 
  222         ::execve( exe.
str().c_str() , argv , env ) ;
 
  224         ::execvpe( exe.
str().c_str() , argv , env ) ;
 
  226         ::execv( exe.
str().c_str() , argv ) ;
 
  228         ::execvp( exe.
str().c_str() , argv ) ;
 
  229     int e = Process::errno_() ;
 
  232     G_DEBUG( 
"G::NewProcess::run: execve() returned: errno=" << e << 
": " << exe ) ;
 
  238     return m_wait_future ;
 
  241 void G::NewProcessImp::kill()
 
  243     if( m_child_pid != -1 )
 
  245         ::kill( m_child_pid , SIGTERM ) ;
 
  250 std::string G::NewProcessImp::execErrorFormat( 
const std::string & format , 
int errno_ )
 
  252     std::string result = format ;
 
  263     m_fds[0] = m_fds[1] = -1 ;
 
  264     if( ::socketpair( AF_UNIX , SOCK_STREAM , 0 , m_fds ) < 0 ) 
 
  265         throw NewProcess::PipeError() ; 
 
  266     G_DEBUG( 
"G::Pipe::ctor: " << m_fds[0] << 
" " << m_fds[1] ) ;
 
  271     if( m_fds[0] >= 0 ) ::close( m_fds[0] ) ;
 
  272     if( m_fds[1] >= 0 ) ::close( m_fds[1] ) ;
 
  275 void G::Pipe::inChild() 
 
  277     ::close( m_fds[0] ) ; 
 
  282 void G::Pipe::inParent() 
 
  284     ::close( m_fds[1] ) ; 
 
  289 int G::Pipe::fd()
 const 
  294 void G::Pipe::dupTo( 
int stdxxx )
 
  296     if( m_fd != -1 && stdxxx != -1 && m_fd != stdxxx )
 
  298         if( ::dup2(m_fd,stdxxx) != stdxxx )
 
  299             throw NewProcess::PipeError() ;
 
  304         int flags = ::fcntl( stdxxx , F_GETFD ) ;
 
  305         flags &= ~FD_CLOEXEC ;
 
  306         ::fcntl( stdxxx , F_SETFD , flags ) ; 
 
  340         char * p = &m_buffer[0] ;
 
  341         size_t space = m_buffer.size() ;
 
  345             ssize_t n = ::read( m_fd , p?p:more , p?space:
sizeof(more) ) ;
 
  346             m_read_error = errno ;
 
  347             if( n < 0 && m_error == EINTR )
 
  358                 m_buffer.resize( size ) ;
 
  375         m_rc = ::waitpid( m_pid , &m_status , 0 ) ;
 
  377         if( m_rc == -1 && m_error == EINTR )
 
  390         if( m_error || m_read_error )
 
  392             std::ostringstream ss ;
 
  393             ss << 
"errno=" << (m_read_error?m_read_error:m_error) ;
 
  394             throw NewProcess::WaitError( ss.str() ) ;
 
  396         if( ! WIFEXITED(m_status) )
 
  399             std::ostringstream ss ;
 
  400             ss << 
"status=" << m_status ;
 
  401             throw NewProcess::ChildError( ss.str() ) ;
 
  403         result = WEXITSTATUS(m_status) ;
 
  410     if( m_fd < 0 || m_read_error != 0 )
 
  411         return std::string() ;
 
  413         return std::string( &m_buffer[0] , m_buffer.size() ) ;
 
int get()
Returns the result of the run() as either the process exit code or as a thrown exception. 
 
void kill()
Tries to kill the spawned process. 
 
std::string str() const 
Returns the path string. 
 
bool isRoot() const 
Returns true if the userid is zero. 
 
static Identity invalid()
Returns an invalid identity. 
 
A class that holds the parameters and the results of a waitpid() system call. 
 
A combination of user-id and group-id, with a very low-level interface to the get/set/e/uid/gid funct...
 
std::vector< std::string > StringArray
A std::vector of std::strings. 
 
static Identity effective()
Returns the current effective identity. 
 
NewProcess(const Path &exe, const StringArray &args, int capture_stdxxx=1, bool clean=true, bool strict_path=true, Identity run_as_id=Identity::invalid(), bool strict_id=true, int exec_error_exit=127, const std::string &exec_error_format=std::string(), std::string(*exec_error_format_fn)(std::string, int)=0)
Constructor. 
 
static std::string fromInt(int i)
Converts int 'i' to a string. 
 
bool isRelative() const 
Returns true if the path is a relative path. 
 
static std::pair< bool, pid_t > fork()
A utility function that forks the calling process and returns twice; once in the parent and once in t...
 
std::string output()
Returns the first bit of child-process output. 
 
NewProcessWaitFuture & run()
Waits for the process identified by the constructor parameter to exit. 
 
static unsigned int replaceAll(std::string &s, const std::string &from, const std::string &to)
Does a global replace on string 's', replacing all occurances of sub-string 'from' with 'to'...
 
NewProcessWaitFuture & wait()
Returns a reference to the WaitFuture sub-object so that the caller can wait for the child process to...
 
NewProcessWaitFuture()
Default constructor for an object where run() does nothing and get() returns zero. 
 
A pimple-pattern implementation class used by G::NewProcess. 
 
A Path object represents a file system path. 
 
A private implementation class used by G::NewProcess that wraps a unix pipe.