From 469bbcf0701e1eb8a6670c23145b0da87357e178 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sun, 25 Mar 2012 20:00:08 +0000 Subject: Code is all reorganized. We're about ready to release. I should write up a little explenation of the arrangement. --- src/stable/process.cpp | 441 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 441 insertions(+) create mode 100644 src/stable/process.cpp (limited to 'src/stable/process.cpp') diff --git a/src/stable/process.cpp b/src/stable/process.cpp new file mode 100644 index 0000000..a98936e --- /dev/null +++ b/src/stable/process.cpp @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "bu/process.h" +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "bu/config.h" + +Bu::Process::Process( Flags eFlags, const char *sName, char *const argv[] ) : + iStdIn( -1 ), + iStdOut( -1 ), + iStdErr( -1 ), + iPid( 0 ), + iProcStatus( 0 ), + bBlocking( true ), + bStdOutEos( true ), + bStdErrEos( true ) +{ + gexec( eFlags, sName, argv ); +} + +Bu::Process::Process( Flags eFlags, const char *sName, const char *argv, ...) : + iStdIn( -1 ), + iStdOut( -1 ), + iStdErr( -1 ), + iPid( 0 ), + iProcStatus( 0 ), + bBlocking( true ), + bStdOutEos( true ), + bStdErrEos( true ) +{ + int iCnt = 0; + va_list ap; + va_start( ap, argv ); + for(; va_arg( ap, const char *); iCnt++ ) { } + va_end( ap ); + + char const **list = new char const *[iCnt+2]; + va_start( ap, argv ); + list[0] = argv; + for( int j = 1; j <= iCnt; j++ ) + { + list[j] = va_arg( ap, const char *); + } + list[iCnt+1] = NULL; + va_end( ap ); + + gexec( eFlags, sName, (char *const *)list ); + delete[] list; +} + +Bu::Process::Process( Flags eFlags, const Bu::Process::Options &opt, const char *sName, char *const argv[] ) : + iStdIn( -1 ), + iStdOut( -1 ), + iStdErr( -1 ), + iPid( 0 ), + iProcStatus( 0 ), + bBlocking( true ), + bStdOutEos( true ), + bStdErrEos( true ), + opt( opt ) +{ + gexec( eFlags, sName, argv ); +} + +Bu::Process::Process( Flags eFlags, const Bu::Process::Options &opt, const char *sName, const char *argv, ...) : + iStdIn( -1 ), + iStdOut( -1 ), + iStdErr( -1 ), + iPid( 0 ), + iProcStatus( 0 ), + bBlocking( true ), + bStdOutEos( true ), + bStdErrEos( true ), + opt( opt ) +{ + int iCnt = 0; + va_list ap; + va_start( ap, argv ); + for(; va_arg( ap, const char *); iCnt++ ) { } + va_end( ap ); + + char const **list = new char const *[iCnt+2]; + va_start( ap, argv ); + list[0] = argv; + for( int j = 1; j <= iCnt; j++ ) + { + list[j] = va_arg( ap, const char *); + } + list[iCnt+1] = NULL; + va_end( ap ); + + gexec( eFlags, sName, (char *const *)list ); + delete[] list; +} + +Bu::Process::~Process() +{ + close(); +} + +void Bu::Process::wait() +{ + close(); +} + +void Bu::Process::gexec( Flags eFlags, const char *sName, char *const argv[] ) +{ + int iaStdIn[2]; + int iaStdOut[2]; + int iaStdErr[2]; + pipe( iaStdIn ); + if( eFlags & StdOut ) + { + pipe( iaStdOut ); + iStdOut = iaStdOut[0]; + bStdOutEos = false; + } + if( eFlags & StdErr ) + { + pipe( iaStdErr ); + iStdErr = iaStdErr[0]; + bStdErrEos = false; + } + + iStdIn = iaStdIn[1]; + +// fcntl( iStdOut, F_SETFL, fcntl( iStdOut, F_GETFL, 0 )|O_NONBLOCK ); + + iPid = fork(); + if( iPid == 0 ) + { + ::close( iaStdIn[1] ); + dup2( iaStdIn[0], 0 ); + if( eFlags & StdOut ) + { + ::close( iaStdOut[0] ); + dup2( iaStdOut[1], 1 ); + } + if( eFlags & StdErr ) + { + ::close( iaStdErr[0] ); + dup2( iaStdErr[1], 2 ); + } + if( (opt.eFlags&Options::SetGid) ) + { + setgid( opt.iGid ); + } + if( (opt.eFlags&Options::SetUid) ) + { + setuid( opt.iUid ); + } + execvp( sName, argv ); + throw Bu::ExceptionBase("Hey, execvp failed!"); + } + ::close( iaStdIn[0] ); + if( eFlags & StdOut ) + ::close( iaStdOut[1] ); + if( eFlags & StdErr ) + ::close( iaStdErr[1] ); +} + +void Bu::Process::close() +{ + if( iPid ) + { + if( iStdIn > -1 ) + ::close( iStdIn ); + if( iStdOut > -1 ) + ::close( iStdOut ); + if( iStdErr > -1 ) + ::close( iStdErr ); + waitpid( iPid, &iProcStatus, 0 ); + iPid = 0; + } +} + +void Bu::Process::closeStdIn() +{ + ::close( iStdIn ); + iStdIn = -1; +} + +void Bu::Process::closeStdOut() +{ + ::close( iStdOut ); + iStdOut = -1; +} + +Bu::size Bu::Process::read( void *pBuf, Bu::size nBytes ) +{ + if( bStdOutEos ) + return 0; + fd_set rfds; + FD_ZERO( &rfds ); + FD_SET( iStdOut, &rfds ); + struct timeval tv = {0, 0}; + if( ::bu_select( iStdOut+1, &rfds, NULL, NULL, &tv ) < 0 ) + throw Bu::ExceptionBase( strerror( errno ) ); + if( FD_ISSET( iStdOut, &rfds ) || bBlocking ) + { + Bu::size nRead = TEMP_FAILURE_RETRY( ::read( iStdOut, pBuf, nBytes ) ); + if( nRead == 0 ) + { + bStdOutEos = true; + checkClose(); + return 0; + } + if( nRead < 0 ) + { + if( errno == EAGAIN ) + return 0; + throw Bu::ExceptionBase( strerror( errno ) ); + } + return nRead; + } + return 0; +} + +Bu::size Bu::Process::readErr( void *pBuf, Bu::size nBytes ) +{ + if( bStdErrEos ) + return 0; + fd_set rfds; + FD_ZERO( &rfds ); + FD_SET( iStdErr, &rfds ); + struct timeval tv = {0, 0}; + if( ::bu_select( iStdErr+1, &rfds, NULL, NULL, &tv ) < 0 ) + throw Bu::ExceptionBase( strerror( errno ) ); + if( FD_ISSET( iStdErr, &rfds ) || bBlocking ) + { + Bu::size nRead = TEMP_FAILURE_RETRY( ::read( iStdErr, pBuf, nBytes ) ); + if( nRead == 0 ) + { + bStdErrEos = true; + checkClose(); + return 0; + } + if( nRead < 0 ) + { + if( errno == EAGAIN ) + return 0; + throw Bu::ExceptionBase( strerror( errno ) ); + } + return nRead; + } + return 0; +} + +Bu::size Bu::Process::write( const void *pBuf, Bu::size nBytes ) +{ + return TEMP_FAILURE_RETRY( ::write( iStdIn, pBuf, nBytes ) ); +} + +Bu::size Bu::Process::tell() +{ + return 0; +} + +void Bu::Process::seek( Bu::size ) +{ +} + +void Bu::Process::setPos( Bu::size ) +{ +} + +void Bu::Process::setPosEnd( Bu::size ) +{ +} + +bool Bu::Process::isEos() +{ + return (iPid == 0); +} + +bool Bu::Process::isOpen() +{ + return (iPid != 0); +} + +void Bu::Process::flush() +{ +} + +bool Bu::Process::canRead() +{ + return true; +} + +bool Bu::Process::canWrite() +{ + return true; +} + +bool Bu::Process::isReadable() +{ + return true; +} + +bool Bu::Process::isWritable() +{ + return true; +} + +bool Bu::Process::isSeekable() +{ + return false; +} + +bool Bu::Process::isBlocking() +{ + return true; +} + +void Bu::Process::setBlocking( bool bBlocking ) +{ + if( bBlocking ) + { + if( !bStdOutEos ) + fcntl( iStdOut, F_SETFL, fcntl(iStdOut,F_GETFL,0 )&(~O_NONBLOCK) ); + if( !bStdErrEos ) + fcntl( iStdErr, F_SETFL, fcntl(iStdErr,F_GETFL,0 )&(~O_NONBLOCK) ); + } + else + { + if( !bStdOutEos ) + fcntl( iStdOut, F_SETFL, fcntl( iStdOut, F_GETFL, 0 )|O_NONBLOCK ); + if( !bStdErrEos ) + fcntl( iStdErr, F_SETFL, fcntl( iStdErr, F_GETFL, 0 )|O_NONBLOCK ); + } + this->bBlocking = bBlocking; +} + +void Bu::Process::setSize( Bu::size ) +{ +} + +Bu::size Bu::Process::getBlockSize() const +{ + return 0; +} + +Bu::size Bu::Process::getSize() const +{ + return 0; +} + +Bu::String Bu::Process::getLocation() const +{ + return ""; +} + +void Bu::Process::select( bool &bStdOut, bool &bStdErr ) +{ + fd_set rfds; + FD_ZERO( &rfds ); + if( !bStdOutEos ) + FD_SET( iStdOut, &rfds ); + if( !bStdErrEos ) + FD_SET( iStdErr, &rfds ); + if( ::bu_select( iStdErr+1, &rfds, NULL, NULL, NULL ) < 0 ) + throw Bu::ExceptionBase( strerror( errno ) ); + + if( FD_ISSET( iStdOut, &rfds ) ) + bStdOut = true; + else + bStdOut = false; + + if( FD_ISSET( iStdErr, &rfds ) ) + bStdErr = true; + else + bStdErr = false; +} + +bool Bu::Process::isRunning() +{ + if( waitpid( iPid, NULL, WNOHANG ) == iPid ) + checkClose(); + return iPid != 0; +} + +void Bu::Process::ignoreStdErr() +{ + if( iStdErr == -1 ) + return; + ::close( iStdErr ); + iStdErr = -1; + bStdErrEos = true; +} + +pid_t Bu::Process::getPid() +{ + return iPid; +} + +bool Bu::Process::childExited() +{ + return WIFEXITED( iProcStatus ); +} + +int Bu::Process::childExitStatus() +{ + return WEXITSTATUS( iProcStatus ); +} + +bool Bu::Process::childSignaled() +{ + return WIFSIGNALED( iProcStatus ); +} + +int Bu::Process::childSignal() +{ + return WTERMSIG( iProcStatus ); +} + +bool Bu::Process::childCoreDumped() +{ + return WCOREDUMP( iProcStatus ); +} + +void Bu::Process::checkClose() +{ + if( bStdOutEos && bStdErrEos ) + { + close(); + } +} + -- cgit v1.2.3