1
#include <stdio.h> // popen()
2
#include <stdlib.h> // system()
3
#include <sys/types.h> // pid_t
4
#include <sys/wait.h> // pid_t
5
#include <unistd.h> // fork()
7
#include "EShellProcess.h"
8
#include "EStringList.h"
9
#include <signal.h> // signal(), sighandler_t
10
#include <setjmp.h> // longjmp()
15
sigjmp_buf EShellProcess_ctrl_c_jmp_buffer;
17
void EShellProcess_SIGINT(int)
19
std::cout << "^C" << std::endl; // this really shouldn't be here, but i find it useful.
20
::siglongjmp( EShellProcess_ctrl_c_jmp_buffer, 1 );
24
EShellProcess::system( const std::string &cmdline, std::ostream & os )
26
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 :/
30
EShellProcess::fork( const std::string &cmdline, std::ostream & os )
31
{ // my very first fork()/exec()
33
EStringList tokens = EStringList::tokenize( cmdline );
38
os << "EShellProcess::fork("<<cmdline<<"): error fork()ing." << endl;
41
if( pid > 0 ) return 0; // parent, go away.
44
// i hate to do this array stuff, but i see no other
45
// way around it without finding a template class for
46
// dynamic arrays, and i'm not up for that right now...
47
static const int maxargs = 100;
49
int tcount = tokens.count();
53
for( ; i < tcount; i++ )
56
if( i == 0 ) filearg = tok;
57
if( tok.empty() ) continue;
58
//os << "adding token ["<<tok<<"]"<<endl;
59
args[i] = const_cast<char *>( tok.c_str() );
60
// this ^^^^^^^^^^^ const_cast is theoretically okay
61
// because we're not gonna de-allocate the
62
// array and this process will never pass
63
// control back to anyone else, so tokens
64
// shouldn't be unduly molested behind our
65
// back. i won't swear that it's safe, though :/.
69
os << __FILE__<<":"<<__LINE__<<": EShellProcess::fork(): you've met or overstepped the\n"
70
<< "hard-coded limit of "<< maxargs<<" arguments.\n"
71
<<"Please contact the maintainer of this code with an example of how you're using it (stephan@wanderinghorse.net), "
72
<< "or fix this bug and send him your fix :)."
75
for( ; i < maxargs; i++ )
79
execvp( filearg.c_str(), args );
85
EShellProcess::pipe( const std::string &cmdline, std::ostream & os )
89
os << "EShellProcess::pipe(): cannot run an empty command :(";
93
fp = ::popen( cmdline.c_str(), "r" );
96
os << "EShellProcess::pipe(): popen("<<cmdline<<") failed :(" << std::endl;
99
::fwrite( cmdline.c_str(), sizeof( char ), cmdline.size(), fp );
100
#define RESTORE_SIGNALS ::signal( SIGINT, old_sighandler )
101
typedef void (*signalfunc)(int);
102
signalfunc old_sighandler = ::signal( SIGINT, EShellProcess_SIGINT );
104
if( 0 == ::sigsetjmp( EShellProcess_ctrl_c_jmp_buffer, 1 ) )
106
while( ! ::feof( fp ) )
108
getcchar = ::getc( fp );
109
if( getcchar == EOF ) break;
110
os <<(unsigned char) getcchar;
111
if( ! os && (os != std::cerr) )
114
std::cerr << "EShellProcess::pipe(): error in output stream!" << std::endl;
120
int ret = ::pclose( fp );
121
return (ret == 0) ? 0 : (ret / 256);