From 8294bd2d641b74778ac6293261fdff0dc062f77b Mon Sep 17 00:00:00 2001 From: Mathias Stearn Date: Fri, 12 Feb 2010 21:55:37 -0500 Subject: [PATCH] runProgram() shell function SERVER-605 --- jstests/run_program1.js | 19 +++++++++++++++++++ shell/utils.cpp | 39 ++++++++++++++++++++++++++++----------- 2 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 jstests/run_program1.js diff --git a/jstests/run_program1.js b/jstests/run_program1.js new file mode 100644 index 00000000000..267568b9b91 --- /dev/null +++ b/jstests/run_program1.js @@ -0,0 +1,19 @@ +if (runProgram('uname') == 0) { //test for a unixy environment (includes cygwin tools) + + // note that normal program exit returns 0 + assert.eq (0, runProgram('true')) + assert.neq(0, runProgram('false')) + assert.neq(0, runProgram('this_program_doesnt_exit')); + + //verify output visually + runProgram('echo', 'Hello', 'World.', 'How are you?'); + runProgram('bash', '-c', 'echo Hello World. "How are you?"'); // only one space is printed between Hello and World + + // numbers can be passed as numbers or strings + runProgram('sleep', 0.5); + runProgram('sleep', '0.5'); +} + +if (runProgram('ver') == 0) { //on windows + runProgram('echo', 'Hello', 'World.', 'How are you?'); +} diff --git a/shell/utils.cpp b/shell/utils.cpp index 9b3a31e5bc3..3c819ee37ce 100644 --- a/shell/utils.cpp +++ b/shell/utils.cpp @@ -217,14 +217,14 @@ namespace mongo { return BSON( "" << out ); } - class MongoProgramRunner { + class ProgramRunner { vector argv_; int port_; int pipe_; pid_t pid_; public: pid_t pid() const { return pid_; } - MongoProgramRunner( const BSONObj &args , bool isMongoProgram=true) + ProgramRunner( const BSONObj &args , bool isMongoProgram=true) { assert( !args.isEmpty() ); @@ -380,13 +380,13 @@ namespace mongo { if ( dup2( child_stdout, STDOUT_FILENO ) == -1 || dup2( child_stdout, STDERR_FILENO ) == -1 ) { - cout << "Unable to dup2 child output" << endl; + cout << "Unable to dup2 child output: " << OUTPUT_ERRNO << endl; ::_Exit(-1); //do not pass go, do not call atexit handlers } execvp( argv[ 0 ], const_cast(argv) ); - cout << "Unable to start program" << endl; + cout << "Unable to start program: " << OUTPUT_ERRNO << endl; ::_Exit(-1); } @@ -395,7 +395,7 @@ namespace mongo { }; //returns true if process exited - bool wait_for_pid(pid_t pid, bool block=true){ + bool wait_for_pid(pid_t pid, bool block=true, int* exit_code=NULL){ #ifdef _WIN32 assert(handles.count(pid)); HANDLE h = handles[pid]; @@ -403,28 +403,34 @@ namespace mongo { if (block) WaitForSingleObject(h, INFINITE); - DWORD ignore; - if(GetExitCodeProcess(h, &ignore)){ + DWORD tmp; + if(GetExitCodeProcess(h, &tmp)){ CloseHandle(h); handles.erase(pid); + if (exit_code) + *exit_code = tmp; return true; }else{ return false; } #else - int ignore; - return (pid == waitpid(pid, &ignore, (block ? 0 : WNOHANG))); + int tmp; + bool ret = (pid == waitpid(pid, &tmp, (block ? 0 : WNOHANG))); + if (exit_code) + *exit_code = WEXITSTATUS(tmp); + return ret; + #endif } BSONObj StartMongoProgram( const BSONObj &a ) { - MongoProgramRunner r( a ); + ProgramRunner r( a ); r.start(); boost::thread t( r ); return BSON( string( "" ) << int( r.pid() ) ); } BSONObj RunMongoProgram( const BSONObj &a ) { - MongoProgramRunner r( a ); + ProgramRunner r( a ); r.start(); boost::thread t( r ); wait_for_pid(r.pid()); @@ -432,6 +438,16 @@ namespace mongo { return BSON( string( "" ) << int( r.pid() ) ); } + BSONObj RunProgram(const BSONObj &a) { + ProgramRunner r( a, false ); + r.start(); + boost::thread t( r ); + int exit_code; + wait_for_pid(r.pid(), true, &exit_code); + shells.erase( r.pid() ); + return BSON( string( "" ) << exit_code ); + } + BSONObj ResetDbpath( const BSONObj &a ) { assert( a.nFields() == 1 ); string path = a.firstElement().valuestrsafe(); @@ -589,6 +605,7 @@ namespace mongo { scope.injectNative( "_srand" , JSSrand ); scope.injectNative( "_rand" , JSRand ); scope.injectNative( "_startMongoProgram", StartMongoProgram ); + scope.injectNative( "runProgram", RunProgram ); scope.injectNative( "runMongoProgram", RunMongoProgram ); scope.injectNative( "stopMongod", StopMongoProgram ); scope.injectNative( "stopMongoProgram", StopMongoProgram );