1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
|
#include <stdio.h> // popen()
#include <stdlib.h> // system()
#include <sys/types.h> // pid_t
#include <sys/wait.h> // pid_t
#include <unistd.h> // fork()
#include "EShellProcess.h"
#include "EStringList.h"
#include <signal.h> // signal(), sighandler_t
#include <setjmp.h> // longjmp()
using std::string;
using std::endl;
sigjmp_buf EShellProcess_ctrl_c_jmp_buffer;
void EShellProcess_SIGINT(int)
{
std::cout << "^C" << std::endl; // this really shouldn't be here, but i find it useful.
::siglongjmp( EShellProcess_ctrl_c_jmp_buffer, 1 );
}
int
EShellProcess::system( const std::string &cmdline, std::ostream & os )
{
return ::system( cmdline.c_str() ) / 256; // i don't like this /256. it's against the docs, but the return values aren't what the docs say :/
}
int
EShellProcess::fork( const std::string &cmdline, std::ostream & os )
{ // my very first fork()/exec()
pid_t pid;
EStringList tokens = EStringList::tokenize( cmdline );
pid = ::fork();
if( pid == -1 )
{
os << "EShellProcess::fork("<<cmdline<<"): error fork()ing." << endl;
return 1;
}
if( pid > 0 ) return 0; // parent, go away.
// child...
// i hate to do this array stuff, but i see no other
// way around it without finding a template class for
// dynamic arrays, and i'm not up for that right now...
static const int maxargs = 100;
char * args[maxargs];
int tcount = tokens.count();
int i = 0;
string tok;
string filearg;
for( ; i < tcount; i++ )
{
tok = tokens.shift();
if( i == 0 ) filearg = tok;
if( tok.empty() ) continue;
//os << "adding token ["<<tok<<"]"<<endl;
args[i] = const_cast<char *>( tok.c_str() );
// this ^^^^^^^^^^^ const_cast is theoretically okay
// because we're not gonna de-allocate the
// array and this process will never pass
// control back to anyone else, so tokens
// shouldn't be unduly molested behind our
// back. i won't swear that it's safe, though :/.
}
if( i == maxargs )
{
os << __FILE__<<":"<<__LINE__<<": EShellProcess::fork(): you've met or overstepped the\n"
<< "hard-coded limit of "<< maxargs<<" arguments.\n"
<<"Please contact the maintainer of this code with an example of how you're using it (stephan@wanderinghorse.net), "
<< "or fix this bug and send him your fix :)."
<< endl;
}
for( ; i < maxargs; i++ )
{
args[i] = NULL;
}
execvp( filearg.c_str(), args );
_exit(0);
return 0;
}
int
EShellProcess::pipe( const std::string &cmdline, std::ostream & os )
{
if( cmdline.empty() )
{
os << "EShellProcess::pipe(): cannot run an empty command :(";
return 1;
}
FILE *fp = 0;
fp = ::popen( cmdline.c_str(), "r" );
if( ! fp )
{
os << "EShellProcess::pipe(): popen("<<cmdline<<") failed :(" << std::endl;
return 1;
}
::fwrite( cmdline.c_str(), sizeof( char ), cmdline.size(), fp );
#define RESTORE_SIGNALS ::signal( SIGINT, old_sighandler )
typedef void (*signalfunc)(int);
signalfunc old_sighandler = ::signal( SIGINT, EShellProcess_SIGINT );
int getcchar;
if( 0 == ::sigsetjmp( EShellProcess_ctrl_c_jmp_buffer, 1 ) )
{
while( ! ::feof( fp ) )
{
getcchar = ::getc( fp );
if( getcchar == EOF ) break;
os <<(unsigned char) getcchar;
if( ! os && (os != std::cerr) )
{
RESTORE_SIGNALS;
std::cerr << "EShellProcess::pipe(): error in output stream!" << std::endl;
return 1;
}
}
}
RESTORE_SIGNALS;
int ret = ::pclose( fp );
return (ret == 0) ? 0 : (ret / 256);
}
|