30 #include <sys/types.h>
41 void noCloseOnExec(
int fd )
43 ::fcntl( fd , F_SETFD , 0 ) ;
58 explicit Pipe(
bool active ) ;
65 void write(
const std::string & ) ;
92 m_imp->m_ref_count = 1 ;
97 m_imp->m_ref_count-- ;
98 if( m_imp->m_ref_count == 0 )
102 G::NewProcess::ChildProcess::ChildProcess(
const ChildProcess & other ) :
111 std::swap( m_imp , temp.m_imp ) ;
116 return G::NewProcess::wait( m_imp->m_id , 127 ) ;
121 return m_imp->m_pipe.read() ;
142 std::cout << std::flush ;
143 std::cerr << std::flush ;
145 const bool ok = rc != -1 ;
149 child_pid.m_pid = rc ;
158 int G::NewProcess::wait(
const Process::Id & child_pid )
163 G_DEBUG(
"G::NewProcess::wait: waiting" ) ;
164 int rc = ::waitpid( child_pid.m_pid , &status , 0 ) ;
172 std::ostringstream ss ;
173 ss <<
"errno=" << error ;
174 throw WaitError( ss.str() ) ;
181 G_DEBUG(
"G::NewProcess::wait: done" ) ;
183 if( ! WIFEXITED(status) )
186 std::ostringstream ss ;
187 ss <<
"status=" << status ;
188 throw ChildError( ss.str() ) ;
191 const int exit_status = WEXITSTATUS(status) ;
195 int G::NewProcess::wait(
const Process::Id & child_pid ,
int error_return )
199 return wait( child_pid ) ;
204 return error_return ;
217 execCore( exe , args ) ;
233 std::string * pipe_result_p ,
int error_return , std::string (*fn)(
int) )
236 throw InvalidPath( exe.
str() ) ;
241 Pipe pipe( pipe_result_p != NULL ) ;
248 G_ASSERT( ::getuid() != 0U && ::geteuid() != 0U ) ;
252 int error = execCore( exe , args ) ;
255 std::string s = (*fn)(error) ;
256 ssize_t rc = ::write( STDOUT_FILENO , s.c_str() , s.length() ) ;
257 G_IGNORE_VARIABLE(rc) ;
263 ::_exit( error_return ) ;
264 return error_return ;
269 int exit_status = wait( child_pid , error_return ) ;
270 if( pipe_result_p != NULL ) *pipe_result_p = pipe.
read() ;
275 int G::NewProcess::execCore(
const G::Path & exe ,
const Strings & args )
278 std::string path(
"PATH=/usr/bin:/bin" ) ;
279 std::string ifs(
"IFS= \t\n" ) ;
280 env[0U] =
const_cast<char*
>( path.c_str() ) ;
281 env[1U] =
const_cast<char*
>( ifs.c_str() ) ;
284 char ** argv =
new char* [ args.size() + 2U ] ;
285 std::string str_exe = exe.
str() ;
286 argv[0U] =
const_cast<char*
>( str_exe.c_str() ) ;
287 unsigned int argc = 1U ;
288 for( Strings::const_iterator arg_p = args.begin() ; arg_p != args.end() ; ++arg_p , argc++ )
289 argv[argc] = const_cast<char*>(arg_p->c_str()) ;
292 ::execve( exe.
str().c_str() , argv , env ) ;
296 G_DEBUG(
"G::NewProcess::exec: execve() returned: errno=" << error <<
": " << exe ) ;
305 m_fds[0] = m_fds[1] = -1 ;
306 if( active && ::pipe( m_fds ) < 0 )
308 G_DEBUG(
"G::Pipe::ctor: " << m_fds[0] <<
" " << m_fds[1] ) ;
313 if( m_fds[0] >= 0 ) ::close( m_fds[0] ) ;
314 if( m_fds[1] >= 0 ) ::close( m_fds[1] ) ;
319 ::close( m_fds[0] ) ;
326 ::close( m_fds[1] ) ;
338 if( m_fd != -1 && m_fd != STDOUT_FILENO )
340 if( ::dup2(m_fd,STDOUT_FILENO) != STDOUT_FILENO )
345 noCloseOnExec( STDOUT_FILENO ) ;
352 ssize_t rc = m_fd == -1 ? 0 : ::read( m_fd , buffer ,
sizeof(buffer) ) ;
353 if( rc < 0 )
throw Error(
"read") ;
354 const size_t buffer_size =
static_cast<size_t>(rc) ;
355 return std::string(buffer,buffer_size) ;
static int spawn(Identity nobody, const Path &exe, const Strings &args, std::string *pipe_result_p=NULL, int error_return=127, std::string(*error_decode_fn)(int)=0)
Runs a command in an unprivileged child process.
std::string str() const
Returns the path string.
bool isRoot() const
Returns true if the userid is zero.
friend class ChildProcess
void operator=(const ChildProcess &)
void write(const std::string &)
std::list< std::string > Strings
A std::list of std::strings.
A very low-level interface to getpwnam() and the get/set/e/uid/gid functions.
static Identity effective()
Returns the current effective identity.
bool isRelative() const
Returns true if the path is a relative path.
static int errno_()
Returns the process's current 'errno' value.
unsigned long m_ref_count
Represents the state of a child process.
static Who fork()
Forks a child process.
A private implementation class used by G::NewProcess.
#define G_EXCEPTION(class_name, description)
define as a function rather than a type if optimising for size
static void closeFiles(bool keep_stderr=false)
Closes all open file descriptors.
static void beNobody(Identity)
If currently running with a real identity of root then the real identity is set to the nobody identit...
A Path object represents a file system path.
A private implementation class used by G::NewProcess.