summaryrefslogtreecommitdiff
path: root/src/mongo/shell/shell_utils_launcher.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/shell/shell_utils_launcher.cpp')
-rw-r--r--src/mongo/shell/shell_utils_launcher.cpp1345
1 files changed, 670 insertions, 675 deletions
diff --git a/src/mongo/shell/shell_utils_launcher.cpp b/src/mongo/shell/shell_utils_launcher.cpp
index 6d4991e999a..ddba7fc8e28 100644
--- a/src/mongo/shell/shell_utils_launcher.cpp
+++ b/src/mongo/shell/shell_utils_launcher.cpp
@@ -39,15 +39,15 @@
#include <vector>
#ifdef _WIN32
-# include <fcntl.h>
-# include <io.h>
-# define SIGKILL 9
+#include <fcntl.h>
+#include <io.h>
+#define SIGKILL 9
#else
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <signal.h>
-# include <sys/stat.h>
-# include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
#endif
#include "mongo/client/dbclientinterface.h"
@@ -61,160 +61,166 @@
namespace mongo {
- using std::unique_ptr;
- using std::cout;
- using std::endl;
- using std::make_pair;
- using std::map;
- using std::pair;
- using std::string;
- using std::stringstream;
- using std::vector;
+using std::unique_ptr;
+using std::cout;
+using std::endl;
+using std::make_pair;
+using std::map;
+using std::pair;
+using std::string;
+using std::stringstream;
+using std::vector;
- extern bool dbexitCalled;
+extern bool dbexitCalled;
#ifdef _WIN32
- inline int close(int fd) { return _close(fd); }
- inline int read(int fd, void* buf, size_t size) { return _read(fd, buf, size); }
- inline int pipe(int fds[2]) { return _pipe(fds, 4096, _O_TEXT | _O_NOINHERIT); }
+inline int close(int fd) {
+ return _close(fd);
+}
+inline int read(int fd, void* buf, size_t size) {
+ return _read(fd, buf, size);
+}
+inline int pipe(int fds[2]) {
+ return _pipe(fds, 4096, _O_TEXT | _O_NOINHERIT);
+}
#endif
- /**
- * These utilities are thread safe but do not provide mutually exclusive access to resources
- * identified by the caller. Resources identified by a pid or port should not be accessed
- * by different threads. Dependent filesystem paths should not be accessed by different
- * threads.
- */
- namespace shell_utils {
+/**
+ * These utilities are thread safe but do not provide mutually exclusive access to resources
+ * identified by the caller. Resources identified by a pid or port should not be accessed
+ * by different threads. Dependent filesystem paths should not be accessed by different
+ * threads.
+ */
+namespace shell_utils {
- ProgramOutputMultiplexer programOutputLogger;
+ProgramOutputMultiplexer programOutputLogger;
- bool ProgramRegistry::isPortRegistered( int port ) const {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- return _ports.count( port ) == 1;
- }
+bool ProgramRegistry::isPortRegistered(int port) const {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ return _ports.count(port) == 1;
+}
- ProcessId ProgramRegistry::pidForPort( int port ) const {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- verify( isPortRegistered( port ) );
- return _ports.find( port )->second.first;
- }
+ProcessId ProgramRegistry::pidForPort(int port) const {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ verify(isPortRegistered(port));
+ return _ports.find(port)->second.first;
+}
- int ProgramRegistry::portForPid(ProcessId pid) const {
- stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
- for (map<int, pair<ProcessId, int> >::const_iterator it = _ports.begin();
- it != _ports.end(); ++it)
- {
- if (it->second.first == pid) return it->first;
- }
+int ProgramRegistry::portForPid(ProcessId pid) const {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ for (map<int, pair<ProcessId, int>>::const_iterator it = _ports.begin(); it != _ports.end();
+ ++it) {
+ if (it->second.first == pid)
+ return it->first;
+ }
- return -1;
- }
+ return -1;
+}
- void ProgramRegistry::registerPort( int port, ProcessId pid, int output ) {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- verify( !isPortRegistered( port ) );
- _ports.insert( make_pair( port, make_pair( pid, output ) ) );
- }
+void ProgramRegistry::registerPort(int port, ProcessId pid, int output) {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ verify(!isPortRegistered(port));
+ _ports.insert(make_pair(port, make_pair(pid, output)));
+}
- void ProgramRegistry::deletePort( int port ) {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- if ( !isPortRegistered( port ) ) {
- return;
- }
- close( _ports.find( port )->second.second );
- _ports.erase( port );
- }
+void ProgramRegistry::deletePort(int port) {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ if (!isPortRegistered(port)) {
+ return;
+ }
+ close(_ports.find(port)->second.second);
+ _ports.erase(port);
+}
- void ProgramRegistry::getRegisteredPorts( vector<int> &ports ) {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- for( map<int,pair<ProcessId,int> >::const_iterator i = _ports.begin(); i != _ports.end();
- ++i ) {
- ports.push_back( i->first );
- }
- }
+void ProgramRegistry::getRegisteredPorts(vector<int>& ports) {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ for (map<int, pair<ProcessId, int>>::const_iterator i = _ports.begin(); i != _ports.end();
+ ++i) {
+ ports.push_back(i->first);
+ }
+}
- bool ProgramRegistry::isPidRegistered( ProcessId pid ) const {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- return _pids.count( pid ) == 1;
- }
+bool ProgramRegistry::isPidRegistered(ProcessId pid) const {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ return _pids.count(pid) == 1;
+}
- void ProgramRegistry::registerPid( ProcessId pid, int output ) {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- verify( !isPidRegistered( pid ) );
- _pids.insert( make_pair( pid, output ) );
- }
+void ProgramRegistry::registerPid(ProcessId pid, int output) {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ verify(!isPidRegistered(pid));
+ _pids.insert(make_pair(pid, output));
+}
- void ProgramRegistry::deletePid(ProcessId pid) {
- stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
- if (!isPidRegistered(pid)) {
- int port = portForPid(pid);
- if (port < 0) return;
- deletePort(port);
- return;
- }
- close(_pids.find(pid)->second);
- _pids.erase(pid);
- }
+void ProgramRegistry::deletePid(ProcessId pid) {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ if (!isPidRegistered(pid)) {
+ int port = portForPid(pid);
+ if (port < 0)
+ return;
+ deletePort(port);
+ return;
+ }
+ close(_pids.find(pid)->second);
+ _pids.erase(pid);
+}
- void ProgramRegistry::getRegisteredPids( vector<ProcessId> &pids ) {
- stdx::lock_guard<stdx::recursive_mutex> lk( _mutex );
- for( map<ProcessId,int>::const_iterator i = _pids.begin(); i != _pids.end(); ++i ) {
- pids.push_back( i->first );
- }
- }
+void ProgramRegistry::getRegisteredPids(vector<ProcessId>& pids) {
+ stdx::lock_guard<stdx::recursive_mutex> lk(_mutex);
+ for (map<ProcessId, int>::const_iterator i = _pids.begin(); i != _pids.end(); ++i) {
+ pids.push_back(i->first);
+ }
+}
- ProgramRegistry &registry = *( new ProgramRegistry() );
+ProgramRegistry& registry = *(new ProgramRegistry());
- void goingAwaySoon() {
- stdx::lock_guard<stdx::mutex> lk( mongoProgramOutputMutex );
- mongo::dbexitCalled = true;
- }
+void goingAwaySoon() {
+ stdx::lock_guard<stdx::mutex> lk(mongoProgramOutputMutex);
+ mongo::dbexitCalled = true;
+}
- void ProgramOutputMultiplexer::appendLine( int port, ProcessId pid, const char *line ) {
- stdx::lock_guard<stdx::mutex> lk( mongoProgramOutputMutex );
- if( mongo::dbexitCalled ) throw "program is terminating";
- stringstream buf;
- if ( port > 0 )
- buf << " m" << port << "| " << line;
- else
- buf << "sh" << pid << "| " << line;
- printf( "%s\n", buf.str().c_str() ); // cout << buf.str() << endl;
- fflush(stdout); // not implicit if stdout isn't directly outputting to a console.
- _buffer << buf.str() << endl;
- }
+void ProgramOutputMultiplexer::appendLine(int port, ProcessId pid, const char* line) {
+ stdx::lock_guard<stdx::mutex> lk(mongoProgramOutputMutex);
+ if (mongo::dbexitCalled)
+ throw "program is terminating";
+ stringstream buf;
+ if (port > 0)
+ buf << " m" << port << "| " << line;
+ else
+ buf << "sh" << pid << "| " << line;
+ printf("%s\n", buf.str().c_str()); // cout << buf.str() << endl;
+ fflush(stdout); // not implicit if stdout isn't directly outputting to a console.
+ _buffer << buf.str() << endl;
+}
- string ProgramOutputMultiplexer::str() const {
- stdx::lock_guard<stdx::mutex> lk( mongoProgramOutputMutex );
- string ret = _buffer.str();
- size_t len = ret.length();
- if ( len > 100000 ) {
- ret = ret.substr( len - 100000, 100000 );
- }
- return ret;
- }
-
- void ProgramOutputMultiplexer::clear() {
- stdx::lock_guard<stdx::mutex> lk( mongoProgramOutputMutex );
- _buffer.str( "" );
- }
-
- ProgramRunner::ProgramRunner( const BSONObj &args ) {
- verify( !args.isEmpty() );
+string ProgramOutputMultiplexer::str() const {
+ stdx::lock_guard<stdx::mutex> lk(mongoProgramOutputMutex);
+ string ret = _buffer.str();
+ size_t len = ret.length();
+ if (len > 100000) {
+ ret = ret.substr(len - 100000, 100000);
+ }
+ return ret;
+}
+
+void ProgramOutputMultiplexer::clear() {
+ stdx::lock_guard<stdx::mutex> lk(mongoProgramOutputMutex);
+ _buffer.str("");
+}
+
+ProgramRunner::ProgramRunner(const BSONObj& args) {
+ verify(!args.isEmpty());
- string program( args.firstElement().valuestrsafe() );
- verify( !program.empty() );
- boost::filesystem::path programPath = findProgram(program);
+ string program(args.firstElement().valuestrsafe());
+ verify(!program.empty());
+ boost::filesystem::path programPath = findProgram(program);
- string prefix( "mongod-" );
- bool isMongodProgram =
- string("mongod") == program ||
- program.compare( 0, prefix.size(), prefix ) == 0;
+ string prefix("mongod-");
+ bool isMongodProgram =
+ string("mongod") == program || program.compare(0, prefix.size(), prefix) == 0;
- prefix = "mongos-";
- bool isMongosProgram =
- string("mongos") == program ||
- program.compare( 0, prefix.size(), prefix ) == 0;
+ prefix = "mongos-";
+ bool isMongosProgram =
+ string("mongos") == program || program.compare(0, prefix.size(), prefix) == 0;
#if 0
if (isMongosProgram == "mongos") {
@@ -227,618 +233,607 @@ namespace mongo {
}
#endif
- _argv.push_back( programPath.string() );
+ _argv.push_back(programPath.string());
- _port = -1;
+ _port = -1;
- BSONObjIterator j( args );
- j.next(); // skip program name (handled above)
- while(j.more()) {
- BSONElement e = j.next();
- string str;
- if ( e.isNumber() ) {
- stringstream ss;
- ss << e.number();
- str = ss.str();
- }
- else {
- verify( e.type() == mongo::String );
- str = e.valuestr();
- }
- if ( str == "--port" )
- _port = -2;
- else if ( _port == -2 )
- _port = strtol( str.c_str(), 0, 10 );
- _argv.push_back(str);
- }
+ BSONObjIterator j(args);
+ j.next(); // skip program name (handled above)
+ while (j.more()) {
+ BSONElement e = j.next();
+ string str;
+ if (e.isNumber()) {
+ stringstream ss;
+ ss << e.number();
+ str = ss.str();
+ } else {
+ verify(e.type() == mongo::String);
+ str = e.valuestr();
+ }
+ if (str == "--port")
+ _port = -2;
+ else if (_port == -2)
+ _port = strtol(str.c_str(), 0, 10);
+ _argv.push_back(str);
+ }
- if ( ! isMongodProgram && ! isMongosProgram && program != "mongobridge" )
- _port = 0;
- else {
- if ( _port <= 0 )
- log() << "error: a port number is expected when running " << program << " from the shell" << endl;
- verify( _port > 0 );
- }
- if ( _port > 0 ) {
- bool haveDbForPort = registry.isPortRegistered( _port );
- if ( haveDbForPort ) {
- log() << "already have db for port: " << _port << endl;
- verify( !haveDbForPort );
- }
- }
+ if (!isMongodProgram && !isMongosProgram && program != "mongobridge")
+ _port = 0;
+ else {
+ if (_port <= 0)
+ log() << "error: a port number is expected when running " << program
+ << " from the shell" << endl;
+ verify(_port > 0);
+ }
+ if (_port > 0) {
+ bool haveDbForPort = registry.isPortRegistered(_port);
+ if (haveDbForPort) {
+ log() << "already have db for port: " << _port << endl;
+ verify(!haveDbForPort);
}
+ }
+}
- void ProgramRunner::start() {
- int pipeEnds[ 2 ];
- int status = pipe(pipeEnds);
- if (status != 0) {
- error() << "failed to create pipe: " << errnoWithDescription() << endl;
- fassertFailed(16701);
- }
-
- fflush( 0 );
- launchProcess(pipeEnds[1]); //sets _pid
+void ProgramRunner::start() {
+ int pipeEnds[2];
+ int status = pipe(pipeEnds);
+ if (status != 0) {
+ error() << "failed to create pipe: " << errnoWithDescription() << endl;
+ fassertFailed(16701);
+ }
- {
- stringstream ss;
- ss << "shell: started program (sh" << _pid << "): ";
- for (unsigned i = 0; i < _argv.size(); i++) {
- ss << " " << _argv[i];
- }
- log() << ss.str() << endl;
- }
+ fflush(0);
+ launchProcess(pipeEnds[1]); // sets _pid
- if ( _port > 0 )
- registry.registerPort( _port, _pid, pipeEnds[ 1 ] );
- else
- registry.registerPid( _pid, pipeEnds[ 1 ] );
- _pipe = pipeEnds[ 0 ];
+ {
+ stringstream ss;
+ ss << "shell: started program (sh" << _pid << "): ";
+ for (unsigned i = 0; i < _argv.size(); i++) {
+ ss << " " << _argv[i];
}
+ log() << ss.str() << endl;
+ }
- void ProgramRunner::operator()() {
- try {
- // This assumes there aren't any 0's in the mongo program output.
- // Hope that's ok.
- const unsigned bufSize = 128 * 1024;
- char buf[ bufSize ];
- char temp[ bufSize ];
- char *start = buf;
- while( 1 ) {
- int lenToRead = ( bufSize - 1 ) - ( start - buf );
- if ( lenToRead <= 0 ) {
- log() << "error: lenToRead: " << lenToRead << endl;
- log() << "first 300: " << string(buf,0,300) << endl;
- }
- verify( lenToRead > 0 );
- int ret = read( _pipe, (void *)start, lenToRead );
- if( mongo::dbexitCalled )
- break;
- verify( ret != -1 );
- start[ ret ] = '\0';
- if ( strlen( start ) != unsigned( ret ) )
- programOutputLogger.appendLine( _port, _pid, "WARNING: mongod wrote null bytes to output" );
- char *last = buf;
- for( char *i = strchr( buf, '\n' ); i; last = i + 1, i = strchr( last, '\n' ) ) {
- *i = '\0';
- programOutputLogger.appendLine( _port, _pid, last );
- }
- if ( ret == 0 ) {
- if ( *last )
- programOutputLogger.appendLine( _port, _pid, last );
- close( _pipe );
- break;
- }
- if ( last != buf ) {
- strncpy( temp, last, bufSize );
- temp[ bufSize-1 ] = '\0';
- strncpy( buf, temp, bufSize );
- buf[ bufSize-1 ] = '\0';
- }
- else {
- verify( strlen( buf ) < bufSize );
- }
- start = buf + strlen( buf );
- }
- }
- catch(...) {
- }
- }
-
- boost::filesystem::path ProgramRunner::findProgram( const string &prog ) {
- boost::filesystem::path p = prog;
+ if (_port > 0)
+ registry.registerPort(_port, _pid, pipeEnds[1]);
+ else
+ registry.registerPid(_pid, pipeEnds[1]);
+ _pipe = pipeEnds[0];
+}
+
+void ProgramRunner::operator()() {
+ try {
+ // This assumes there aren't any 0's in the mongo program output.
+ // Hope that's ok.
+ const unsigned bufSize = 128 * 1024;
+ char buf[bufSize];
+ char temp[bufSize];
+ char* start = buf;
+ while (1) {
+ int lenToRead = (bufSize - 1) - (start - buf);
+ if (lenToRead <= 0) {
+ log() << "error: lenToRead: " << lenToRead << endl;
+ log() << "first 300: " << string(buf, 0, 300) << endl;
+ }
+ verify(lenToRead > 0);
+ int ret = read(_pipe, (void*)start, lenToRead);
+ if (mongo::dbexitCalled)
+ break;
+ verify(ret != -1);
+ start[ret] = '\0';
+ if (strlen(start) != unsigned(ret))
+ programOutputLogger.appendLine(
+ _port, _pid, "WARNING: mongod wrote null bytes to output");
+ char* last = buf;
+ for (char* i = strchr(buf, '\n'); i; last = i + 1, i = strchr(last, '\n')) {
+ *i = '\0';
+ programOutputLogger.appendLine(_port, _pid, last);
+ }
+ if (ret == 0) {
+ if (*last)
+ programOutputLogger.appendLine(_port, _pid, last);
+ close(_pipe);
+ break;
+ }
+ if (last != buf) {
+ strncpy(temp, last, bufSize);
+ temp[bufSize - 1] = '\0';
+ strncpy(buf, temp, bufSize);
+ buf[bufSize - 1] = '\0';
+ } else {
+ verify(strlen(buf) < bufSize);
+ }
+ start = buf + strlen(buf);
+ }
+ } catch (...) {
+ }
+}
+
+boost::filesystem::path ProgramRunner::findProgram(const string& prog) {
+ boost::filesystem::path p = prog;
#ifdef _WIN32
- // The system programs either come versioned in the form of <utility>-<major.minor>
- // (e.g., mongorestore-2.4) or just <utility>. For windows, the appropriate extension
- // needs to be appended.
- //
- if (p.extension() != ".exe") {
- p = prog + ".exe";
- }
+ // The system programs either come versioned in the form of <utility>-<major.minor>
+ // (e.g., mongorestore-2.4) or just <utility>. For windows, the appropriate extension
+ // needs to be appended.
+ //
+ if (p.extension() != ".exe") {
+ p = prog + ".exe";
+ }
#endif
- if( boost::filesystem::exists(p) ) {
+ if (boost::filesystem::exists(p)) {
#ifndef _WIN32
- p = boost::filesystem::initial_path() / p;
+ p = boost::filesystem::initial_path() / p;
#endif
- return p;
- }
-
- {
- boost::filesystem::path t = boost::filesystem::current_path() / p;
- if( boost::filesystem::exists(t) ) return t;
- }
+ return p;
+ }
- {
- boost::filesystem::path t = boost::filesystem::initial_path() / p;
- if( boost::filesystem::exists(t) ) return t;
- }
+ {
+ boost::filesystem::path t = boost::filesystem::current_path() / p;
+ if (boost::filesystem::exists(t))
+ return t;
+ }
- return p; // not found; might find via system path
- }
+ {
+ boost::filesystem::path t = boost::filesystem::initial_path() / p;
+ if (boost::filesystem::exists(t))
+ return t;
+ }
- void ProgramRunner::launchProcess( int child_stdout ) {
+ return p; // not found; might find via system path
+}
+
+void ProgramRunner::launchProcess(int child_stdout) {
#ifdef _WIN32
- stringstream ss;
- for( unsigned i=0; i < _argv.size(); i++ ) {
- if (i) ss << ' ';
- if (_argv[i].find(' ') == string::npos)
- ss << _argv[i];
- else {
- ss << '"';
- // escape all embedded quotes
- for (size_t j=0; j<_argv[i].size(); ++j) {
- if (_argv[i][j]=='"') ss << '\\';
- ss << _argv[i][j];
- }
- ss << '"';
- }
- }
+ stringstream ss;
+ for (unsigned i = 0; i < _argv.size(); i++) {
+ if (i)
+ ss << ' ';
+ if (_argv[i].find(' ') == string::npos)
+ ss << _argv[i];
+ else {
+ ss << '"';
+ // escape all embedded quotes
+ for (size_t j = 0; j < _argv[i].size(); ++j) {
+ if (_argv[i][j] == '"')
+ ss << '\\';
+ ss << _argv[i][j];
+ }
+ ss << '"';
+ }
+ }
- string args = ss.str();
-
- std::unique_ptr<TCHAR[]> args_tchar (new TCHAR[args.size() + 1]);
- size_t i;
- for(i=0; i < args.size(); i++)
- args_tchar[i] = args[i];
- args_tchar[i] = 0;
-
- HANDLE h = (HANDLE)_get_osfhandle(child_stdout);
- verify(h != INVALID_HANDLE_VALUE);
- verify(SetHandleInformation(h, HANDLE_FLAG_INHERIT, 1));
-
- STARTUPINFO si;
- ZeroMemory(&si, sizeof(si));
- si.cb = sizeof(si);
- si.hStdError = h;
- si.hStdOutput = h;
- si.dwFlags |= STARTF_USESTDHANDLES;
-
- PROCESS_INFORMATION pi;
- ZeroMemory(&pi, sizeof(pi));
-
- bool success = CreateProcess( NULL, args_tchar.get(), NULL, NULL, true, 0, NULL, NULL, &si, &pi) != 0;
- if (!success) {
- LPSTR lpMsgBuf=0;
- DWORD dw = GetLastError();
- FormatMessageA(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- dw,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPSTR)&lpMsgBuf,
- 0, NULL );
- stringstream ss;
- ss << "couldn't start process " << _argv[0] << "; " << lpMsgBuf;
- uassert(14042, ss.str(), success);
- LocalFree(lpMsgBuf);
- }
+ string args = ss.str();
+
+ std::unique_ptr<TCHAR[]> args_tchar(new TCHAR[args.size() + 1]);
+ size_t i;
+ for (i = 0; i < args.size(); i++)
+ args_tchar[i] = args[i];
+ args_tchar[i] = 0;
+
+ HANDLE h = (HANDLE)_get_osfhandle(child_stdout);
+ verify(h != INVALID_HANDLE_VALUE);
+ verify(SetHandleInformation(h, HANDLE_FLAG_INHERIT, 1));
+
+ STARTUPINFO si;
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ si.hStdError = h;
+ si.hStdOutput = h;
+ si.dwFlags |= STARTF_USESTDHANDLES;
+
+ PROCESS_INFORMATION pi;
+ ZeroMemory(&pi, sizeof(pi));
+
+ bool success =
+ CreateProcess(NULL, args_tchar.get(), NULL, NULL, true, 0, NULL, NULL, &si, &pi) != 0;
+ if (!success) {
+ LPSTR lpMsgBuf = 0;
+ DWORD dw = GetLastError();
+ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ dw,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)&lpMsgBuf,
+ 0,
+ NULL);
+ stringstream ss;
+ ss << "couldn't start process " << _argv[0] << "; " << lpMsgBuf;
+ uassert(14042, ss.str(), success);
+ LocalFree(lpMsgBuf);
+ }
- CloseHandle(pi.hThread);
+ CloseHandle(pi.hThread);
- _pid = ProcessId::fromNative(pi.dwProcessId);
- registry._handles.insert( make_pair( _pid, pi.hProcess ) );
+ _pid = ProcessId::fromNative(pi.dwProcessId);
+ registry._handles.insert(make_pair(_pid, pi.hProcess));
#else
- unique_ptr<const char *[]> argvStorage( new const char* [_argv.size()+1] );
- const char** argv = argvStorage.get();
- for (unsigned i=0; i < _argv.size(); i++) {
- argv[i] = _argv[i].c_str();
- }
- argv[_argv.size()] = 0;
-
- unique_ptr<const char *[]> envStorage( new const char* [2] );
- const char** env = envStorage.get();
- env[0] = NULL;
- env[1] = NULL;
+ unique_ptr<const char* []> argvStorage(new const char* [_argv.size() + 1]);
+ const char** argv = argvStorage.get();
+ for (unsigned i = 0; i < _argv.size(); i++) {
+ argv[i] = _argv[i].c_str();
+ }
+ argv[_argv.size()] = 0;
- pid_t nativePid = fork();
- _pid = ProcessId::fromNative(nativePid);
- // Async signal unsafe functions should not be called in the child process.
+ unique_ptr<const char* []> envStorage(new const char* [2]);
+ const char** env = envStorage.get();
+ env[0] = NULL;
+ env[1] = NULL;
- verify( nativePid != -1 );
- if ( nativePid == 0 ) {
- // DON'T ASSERT IN THIS BLOCK - very bad things will happen
+ pid_t nativePid = fork();
+ _pid = ProcessId::fromNative(nativePid);
+ // Async signal unsafe functions should not be called in the child process.
- if ( dup2( child_stdout, STDOUT_FILENO ) == -1 ||
- dup2( child_stdout, STDERR_FILENO ) == -1 ) {
+ verify(nativePid != -1);
+ if (nativePid == 0) {
+ // DON'T ASSERT IN THIS BLOCK - very bad things will happen
- // Async signal unsafe code reporting a terminal error condition.
- cout << "Unable to dup2 child output: " << errnoWithDescription() << endl;
- quickExit(-1); //do not pass go, do not call atexit handlers
- }
+ if (dup2(child_stdout, STDOUT_FILENO) == -1 || dup2(child_stdout, STDERR_FILENO) == -1) {
+ // Async signal unsafe code reporting a terminal error condition.
+ cout << "Unable to dup2 child output: " << errnoWithDescription() << endl;
+ quickExit(-1); // do not pass go, do not call atexit handlers
+ }
- // NOTE execve is async signal safe, but it is not clear that execvp is async
- // signal safe.
- execvp( argv[ 0 ], const_cast<char**>(argv) );
+ // NOTE execve is async signal safe, but it is not clear that execvp is async
+ // signal safe.
+ execvp(argv[0], const_cast<char**>(argv));
- // Async signal unsafe code reporting a terminal error condition.
- cout << "Unable to start program " << argv[0] << ' ' << errnoWithDescription() << endl;
- quickExit(-1);
- }
+ // Async signal unsafe code reporting a terminal error condition.
+ cout << "Unable to start program " << argv[0] << ' ' << errnoWithDescription() << endl;
+ quickExit(-1);
+ }
#endif
- }
+}
- //returns true if process exited
- bool wait_for_pid(ProcessId pid, bool block=true, int* exit_code=NULL) {
+// returns true if process exited
+bool wait_for_pid(ProcessId pid, bool block = true, int* exit_code = NULL) {
#ifdef _WIN32
- verify(registry._handles.count(pid));
- HANDLE h = registry._handles[pid];
+ verify(registry._handles.count(pid));
+ HANDLE h = registry._handles[pid];
- if (block) {
- if (WaitForSingleObject(h, INFINITE)) {
- log() << "WaitForSingleObject failed: " << errnoWithDescription();
- }
- }
+ if (block) {
+ if (WaitForSingleObject(h, INFINITE)) {
+ log() << "WaitForSingleObject failed: " << errnoWithDescription();
+ }
+ }
- DWORD tmp;
- if(GetExitCodeProcess(h, &tmp)) {
- if ( tmp == STILL_ACTIVE ) {
- if (block)
- log() << "Process is STILL_ACTIVE even after blocking";
- return false;
- }
- CloseHandle(h);
- registry._handles.erase(pid);
- if (exit_code)
- *exit_code = tmp;
- return true;
- }
- else {
- log() << "GetExitCodeProcess failed: " << errnoWithDescription();
- return false;
- }
+ DWORD tmp;
+ if (GetExitCodeProcess(h, &tmp)) {
+ if (tmp == STILL_ACTIVE) {
+ if (block)
+ log() << "Process is STILL_ACTIVE even after blocking";
+ return false;
+ }
+ CloseHandle(h);
+ registry._handles.erase(pid);
+ if (exit_code)
+ *exit_code = tmp;
+ return true;
+ } else {
+ log() << "GetExitCodeProcess failed: " << errnoWithDescription();
+ return false;
+ }
#else
- int tmp;
- bool ret = (pid.toNative() == waitpid(pid.toNative(), &tmp, (block ? 0 : WNOHANG)));
- if (exit_code)
- *exit_code = WEXITSTATUS(tmp);
- return ret;
+ int tmp;
+ bool ret = (pid.toNative() == waitpid(pid.toNative(), &tmp, (block ? 0 : WNOHANG)));
+ if (exit_code)
+ *exit_code = WEXITSTATUS(tmp);
+ return ret;
#endif
- }
+}
- BSONObj RawMongoProgramOutput( const BSONObj &args, void* data ) {
- return BSON( "" << programOutputLogger.str() );
- }
-
- BSONObj ClearRawMongoProgramOutput( const BSONObj &args, void* data ) {
- programOutputLogger.clear();
- return undefinedReturn;
- }
+BSONObj RawMongoProgramOutput(const BSONObj& args, void* data) {
+ return BSON("" << programOutputLogger.str());
+}
- BSONObj CheckProgram(const BSONObj& args, void* data) {
- ProcessId pid = ProcessId::fromNative(singleArg(args).numberInt());
- bool isDead = wait_for_pid(pid, false);
- if (isDead) registry.deletePid(pid);
- return BSON( string( "" ) << (!isDead) );
- }
+BSONObj ClearRawMongoProgramOutput(const BSONObj& args, void* data) {
+ programOutputLogger.clear();
+ return undefinedReturn;
+}
- BSONObj WaitProgram( const BSONObj& a, void* data ) {
- ProcessId pid = ProcessId::fromNative(singleArg( a ).numberInt());
- int exit_code = -123456; // sentinel value
- wait_for_pid( pid, true, &exit_code );
- registry.deletePid( pid );
- return BSON( string("") << exit_code);
- }
+BSONObj CheckProgram(const BSONObj& args, void* data) {
+ ProcessId pid = ProcessId::fromNative(singleArg(args).numberInt());
+ bool isDead = wait_for_pid(pid, false);
+ if (isDead)
+ registry.deletePid(pid);
+ return BSON(string("") << (!isDead));
+}
- BSONObj StartMongoProgram( const BSONObj &a, void* data ) {
- _nokillop = true;
- ProgramRunner r( a );
- r.start();
- stdx::thread t( r );
- return BSON( string( "" ) << r.pid().asLongLong() );
- }
+BSONObj WaitProgram(const BSONObj& a, void* data) {
+ ProcessId pid = ProcessId::fromNative(singleArg(a).numberInt());
+ int exit_code = -123456; // sentinel value
+ wait_for_pid(pid, true, &exit_code);
+ registry.deletePid(pid);
+ return BSON(string("") << exit_code);
+}
- BSONObj RunMongoProgram( const BSONObj &a, void* data ) {
- ProgramRunner r( a );
- r.start();
- stdx::thread t( r );
- int exit_code = -123456; // sentinel value
- wait_for_pid( r.pid(), true, &exit_code );
- if ( r.port() > 0 ) {
- registry.deletePort( r.port() );
- }
- else {
- registry.deletePid( r.pid() );
- }
- return BSON( string( "" ) << exit_code );
- }
+BSONObj StartMongoProgram(const BSONObj& a, void* data) {
+ _nokillop = true;
+ ProgramRunner r(a);
+ r.start();
+ stdx::thread t(r);
+ return BSON(string("") << r.pid().asLongLong());
+}
- BSONObj RunProgram(const BSONObj &a, void* data) {
- ProgramRunner r( a );
- r.start();
- stdx::thread t( r );
- int exit_code = -123456; // sentinel value
- wait_for_pid(r.pid(), true, &exit_code);
- registry.deletePid( r.pid() );
- return BSON( string( "" ) << exit_code );
- }
+BSONObj RunMongoProgram(const BSONObj& a, void* data) {
+ ProgramRunner r(a);
+ r.start();
+ stdx::thread t(r);
+ int exit_code = -123456; // sentinel value
+ wait_for_pid(r.pid(), true, &exit_code);
+ if (r.port() > 0) {
+ registry.deletePort(r.port());
+ } else {
+ registry.deletePid(r.pid());
+ }
+ return BSON(string("") << exit_code);
+}
- BSONObj ResetDbpath( const BSONObj &a, void* data ) {
- verify( a.nFields() == 1 );
- string path = a.firstElement().valuestrsafe();
- verify( !path.empty() );
- if ( boost::filesystem::exists( path ) )
- boost::filesystem::remove_all( path );
- boost::filesystem::create_directory( path );
- return undefinedReturn;
- }
+BSONObj RunProgram(const BSONObj& a, void* data) {
+ ProgramRunner r(a);
+ r.start();
+ stdx::thread t(r);
+ int exit_code = -123456; // sentinel value
+ wait_for_pid(r.pid(), true, &exit_code);
+ registry.deletePid(r.pid());
+ return BSON(string("") << exit_code);
+}
- BSONObj PathExists( const BSONObj &a, void* data ) {
- verify( a.nFields() == 1 );
- string path = a.firstElement().valuestrsafe();
- verify( !path.empty() );
- bool exists = boost::filesystem::exists(path);
- return BSON( string( "" ) << exists );
- }
+BSONObj ResetDbpath(const BSONObj& a, void* data) {
+ verify(a.nFields() == 1);
+ string path = a.firstElement().valuestrsafe();
+ verify(!path.empty());
+ if (boost::filesystem::exists(path))
+ boost::filesystem::remove_all(path);
+ boost::filesystem::create_directory(path);
+ return undefinedReturn;
+}
- void copyDir( const boost::filesystem::path &from, const boost::filesystem::path &to ) {
- boost::filesystem::directory_iterator end;
- boost::filesystem::directory_iterator i( from );
- while( i != end ) {
- boost::filesystem::path p = *i;
- if ( p.leaf() != "mongod.lock" && p.leaf() != "WiredTiger.lock" ) {
- if ( boost::filesystem::is_directory( p ) ) {
- boost::filesystem::path newDir = to / p.leaf();
- boost::filesystem::create_directory( newDir );
- copyDir( p, newDir );
- }
- else {
- boost::filesystem::copy_file( p, to / p.leaf() );
- }
- }
- ++i;
- }
- }
+BSONObj PathExists(const BSONObj& a, void* data) {
+ verify(a.nFields() == 1);
+ string path = a.firstElement().valuestrsafe();
+ verify(!path.empty());
+ bool exists = boost::filesystem::exists(path);
+ return BSON(string("") << exists);
+}
- // NOTE target dbpath will be cleared first
- BSONObj CopyDbpath( const BSONObj &a, void* data ) {
- verify( a.nFields() == 2 );
- BSONObjIterator i( a );
- string from = i.next().str();
- string to = i.next().str();
- verify( !from.empty() );
- verify( !to.empty() );
- if ( boost::filesystem::exists( to ) )
- boost::filesystem::remove_all( to );
- boost::filesystem::create_directory( to );
- copyDir( from, to );
- return undefinedReturn;
- }
+void copyDir(const boost::filesystem::path& from, const boost::filesystem::path& to) {
+ boost::filesystem::directory_iterator end;
+ boost::filesystem::directory_iterator i(from);
+ while (i != end) {
+ boost::filesystem::path p = *i;
+ if (p.leaf() != "mongod.lock" && p.leaf() != "WiredTiger.lock") {
+ if (boost::filesystem::is_directory(p)) {
+ boost::filesystem::path newDir = to / p.leaf();
+ boost::filesystem::create_directory(newDir);
+ copyDir(p, newDir);
+ } else {
+ boost::filesystem::copy_file(p, to / p.leaf());
+ }
+ }
+ ++i;
+ }
+}
+
+// NOTE target dbpath will be cleared first
+BSONObj CopyDbpath(const BSONObj& a, void* data) {
+ verify(a.nFields() == 2);
+ BSONObjIterator i(a);
+ string from = i.next().str();
+ string to = i.next().str();
+ verify(!from.empty());
+ verify(!to.empty());
+ if (boost::filesystem::exists(to))
+ boost::filesystem::remove_all(to);
+ boost::filesystem::create_directory(to);
+ copyDir(from, to);
+ return undefinedReturn;
+}
- inline void kill_wrapper( ProcessId pid, int sig, int port, const BSONObj& opt ) {
+inline void kill_wrapper(ProcessId pid, int sig, int port, const BSONObj& opt) {
#ifdef _WIN32
- if (sig == SIGKILL || port == 0) {
- verify( registry._handles.count(pid) );
- TerminateProcess(registry._handles[pid], 1); // returns failure for "zombie" processes.
- return;
- }
+ if (sig == SIGKILL || port == 0) {
+ verify(registry._handles.count(pid));
+ TerminateProcess(registry._handles[pid], 1); // returns failure for "zombie" processes.
+ return;
+ }
- std::string eventName = getShutdownSignalName(pid.asUInt32());
+ std::string eventName = getShutdownSignalName(pid.asUInt32());
- HANDLE event = OpenEventA(EVENT_MODIFY_STATE, FALSE, eventName.c_str());
- if (event == NULL) {
- int gle = GetLastError();
- if (gle != ERROR_FILE_NOT_FOUND) {
- warning() << "kill_wrapper OpenEvent failed: " << errnoWithDescription();
- }
- else {
- log() << "kill_wrapper OpenEvent failed to open event to the process "
- << pid.asUInt32()
- << ". It has likely died already or server is running an older version."
- << " Attempting to shutdown through admin command.";
-
- // Back-off to the old way of shutting down the server on Windows, in case we
- // are managing a pre-2.6.0rc0 service, which did not have the event.
- //
- try {
- DBClientConnection conn;
- conn.connect("127.0.0.1:" + BSONObjBuilder::numStr(port));
-
- BSONElement authObj = opt["auth"];
-
- if (!authObj.eoo()){
- string errMsg;
- conn.auth("admin", authObj["user"].String(),
- authObj["pwd"].String(), errMsg);
-
- if (!errMsg.empty()) {
- cout << "Failed to authenticate before shutdown: "
- << errMsg << endl;
- }
- }
-
- BSONObj info;
- BSONObjBuilder b;
- b.append("shutdown", 1);
- b.append("force", 1);
- conn.runCommand("admin", b.done(), info);
- }
- catch (...) {
- // Do nothing. This command never returns data to the client and the driver
- // doesn't like that.
- //
+ HANDLE event = OpenEventA(EVENT_MODIFY_STATE, FALSE, eventName.c_str());
+ if (event == NULL) {
+ int gle = GetLastError();
+ if (gle != ERROR_FILE_NOT_FOUND) {
+ warning() << "kill_wrapper OpenEvent failed: " << errnoWithDescription();
+ } else {
+ log() << "kill_wrapper OpenEvent failed to open event to the process " << pid.asUInt32()
+ << ". It has likely died already or server is running an older version."
+ << " Attempting to shutdown through admin command.";
+
+ // Back-off to the old way of shutting down the server on Windows, in case we
+ // are managing a pre-2.6.0rc0 service, which did not have the event.
+ //
+ try {
+ DBClientConnection conn;
+ conn.connect("127.0.0.1:" + BSONObjBuilder::numStr(port));
+
+ BSONElement authObj = opt["auth"];
+
+ if (!authObj.eoo()) {
+ string errMsg;
+ conn.auth("admin", authObj["user"].String(), authObj["pwd"].String(), errMsg);
+
+ if (!errMsg.empty()) {
+ cout << "Failed to authenticate before shutdown: " << errMsg << endl;
}
}
- return;
+
+ BSONObj info;
+ BSONObjBuilder b;
+ b.append("shutdown", 1);
+ b.append("force", 1);
+ conn.runCommand("admin", b.done(), info);
+ } catch (...) {
+ // Do nothing. This command never returns data to the client and the driver
+ // doesn't like that.
+ //
}
+ }
+ return;
+ }
- ON_BLOCK_EXIT(CloseHandle, event);
+ ON_BLOCK_EXIT(CloseHandle, event);
- bool result = SetEvent(event);
- if (!result) {
- error() << "kill_wrapper SetEvent failed: " << errnoWithDescription();
- return;
- }
+ bool result = SetEvent(event);
+ if (!result) {
+ error() << "kill_wrapper SetEvent failed: " << errnoWithDescription();
+ return;
+ }
#else
- int x = kill( pid.toNative(), sig );
- if ( x ) {
- if ( errno == ESRCH ) {
- }
- else {
- log() << "killFailed: " << errnoWithDescription() << endl;
- verify( x == 0 );
- }
- }
+ int x = kill(pid.toNative(), sig);
+ if (x) {
+ if (errno == ESRCH) {
+ } else {
+ log() << "killFailed: " << errnoWithDescription() << endl;
+ verify(x == 0);
+ }
+ }
#endif
- }
+}
- int killDb( int port, ProcessId _pid, int signal, const BSONObj& opt ) {
- ProcessId pid;
- int exitCode = 0;
- if ( port > 0 ) {
- if( !registry.isPortRegistered( port ) ) {
- log() << "No db started on port: " << port << endl;
- return 0;
- }
- pid = registry.pidForPort( port );
- }
- else {
- pid = _pid;
- }
+int killDb(int port, ProcessId _pid, int signal, const BSONObj& opt) {
+ ProcessId pid;
+ int exitCode = 0;
+ if (port > 0) {
+ if (!registry.isPortRegistered(port)) {
+ log() << "No db started on port: " << port << endl;
+ return 0;
+ }
+ pid = registry.pidForPort(port);
+ } else {
+ pid = _pid;
+ }
- kill_wrapper( pid, signal, port, opt );
+ kill_wrapper(pid, signal, port, opt);
- int i = 0;
- for( ; i < 130; ++i ) {
- if ( i == 60 ) {
- log() << "process on port " << port << ", with pid " << pid << " not terminated, sending sigkill" << endl;
- kill_wrapper( pid, SIGKILL, port, opt );
- }
- if(wait_for_pid(pid, false, &exitCode))
- break;
- sleepmillis( 1000 );
- }
- if ( i == 130 ) {
- log() << "failed to terminate process on port " << port << ", with pid " << pid << endl;
- verify( "Failed to terminate process" == 0 );
- }
+ int i = 0;
+ for (; i < 130; ++i) {
+ if (i == 60) {
+ log() << "process on port " << port << ", with pid " << pid
+ << " not terminated, sending sigkill" << endl;
+ kill_wrapper(pid, SIGKILL, port, opt);
+ }
+ if (wait_for_pid(pid, false, &exitCode))
+ break;
+ sleepmillis(1000);
+ }
+ if (i == 130) {
+ log() << "failed to terminate process on port " << port << ", with pid " << pid << endl;
+ verify("Failed to terminate process" == 0);
+ }
- if ( port > 0 ) {
- registry.deletePort( port );
- }
- else {
- registry.deletePid( pid );
- }
- // FIXME I think the intention here is to do an extra sleep only when SIGKILL is sent to the child process.
- // We may want to change the 4 below to 29, since values of i greater than that indicate we sent a SIGKILL.
- if ( i > 4 || signal == SIGKILL ) {
- sleepmillis( 4000 ); // allow operating system to reclaim resources
- }
+ if (port > 0) {
+ registry.deletePort(port);
+ } else {
+ registry.deletePid(pid);
+ }
+ // FIXME I think the intention here is to do an extra sleep only when SIGKILL is sent to the child process.
+ // We may want to change the 4 below to 29, since values of i greater than that indicate we sent a SIGKILL.
+ if (i > 4 || signal == SIGKILL) {
+ sleepmillis(4000); // allow operating system to reclaim resources
+ }
- return exitCode;
- }
+ return exitCode;
+}
- int killDb( int port, ProcessId _pid, int signal ) {
- BSONObj dummyOpt;
- return killDb( port, _pid, signal, dummyOpt );
- }
-
- int getSignal( const BSONObj &a ) {
- int ret = SIGTERM;
- if ( a.nFields() >= 2 ) {
- BSONObjIterator i( a );
- i.next();
- BSONElement e = i.next();
- verify( e.isNumber() );
- ret = int( e.number() );
- }
- return ret;
- }
+int killDb(int port, ProcessId _pid, int signal) {
+ BSONObj dummyOpt;
+ return killDb(port, _pid, signal, dummyOpt);
+}
- BSONObj getStopMongodOpts( const BSONObj &a ) {
- if ( a.nFields() == 3 ) {
- BSONObjIterator i( a );
- i.next();
- i.next();
- BSONElement e = i.next();
+int getSignal(const BSONObj& a) {
+ int ret = SIGTERM;
+ if (a.nFields() >= 2) {
+ BSONObjIterator i(a);
+ i.next();
+ BSONElement e = i.next();
+ verify(e.isNumber());
+ ret = int(e.number());
+ }
+ return ret;
+}
- if ( e.isABSONObj() ){
- return e.embeddedObject();
- }
- }
+BSONObj getStopMongodOpts(const BSONObj& a) {
+ if (a.nFields() == 3) {
+ BSONObjIterator i(a);
+ i.next();
+ i.next();
+ BSONElement e = i.next();
- return BSONObj();
+ if (e.isABSONObj()) {
+ return e.embeddedObject();
}
+ }
- /** stopMongoProgram(port[, signal]) */
- BSONObj StopMongoProgram( const BSONObj &a, void* data ) {
- int nFields = a.nFields();
- verify( nFields >= 1 && nFields <= 3 );
- uassert( 15853 , "stopMongo needs a number" , a.firstElement().isNumber() );
- int port = int( a.firstElement().number() );
- int code = killDb( port, ProcessId::fromNative(0), getSignal( a ), getStopMongodOpts( a ));
- log() << "shell: stopped mongo program on port " << port << endl;
- return BSON( "" << (double)code );
- }
+ return BSONObj();
+}
- BSONObj StopMongoProgramByPid( const BSONObj &a, void* data ) {
- verify( a.nFields() == 1 || a.nFields() == 2 );
- uassert( 15852 , "stopMongoByPid needs a number" , a.firstElement().isNumber() );
- ProcessId pid = ProcessId::fromNative(int( a.firstElement().number() ));
- int code = killDb( 0, pid, getSignal( a ) );
- log() << "shell: stopped mongo program on pid " << pid << endl;
- return BSON( "" << (double)code );
- }
+/** stopMongoProgram(port[, signal]) */
+BSONObj StopMongoProgram(const BSONObj& a, void* data) {
+ int nFields = a.nFields();
+ verify(nFields >= 1 && nFields <= 3);
+ uassert(15853, "stopMongo needs a number", a.firstElement().isNumber());
+ int port = int(a.firstElement().number());
+ int code = killDb(port, ProcessId::fromNative(0), getSignal(a), getStopMongodOpts(a));
+ log() << "shell: stopped mongo program on port " << port << endl;
+ return BSON("" << (double)code);
+}
- void KillMongoProgramInstances() {
- vector< int > ports;
- registry.getRegisteredPorts( ports );
- for( vector< int >::iterator i = ports.begin(); i != ports.end(); ++i )
- killDb( *i, ProcessId::fromNative(0), SIGTERM );
- vector< ProcessId > pids;
- registry.getRegisteredPids( pids );
- for( vector< ProcessId >::iterator i = pids.begin(); i != pids.end(); ++i )
- killDb( 0, *i, SIGTERM );
- }
+BSONObj StopMongoProgramByPid(const BSONObj& a, void* data) {
+ verify(a.nFields() == 1 || a.nFields() == 2);
+ uassert(15852, "stopMongoByPid needs a number", a.firstElement().isNumber());
+ ProcessId pid = ProcessId::fromNative(int(a.firstElement().number()));
+ int code = killDb(0, pid, getSignal(a));
+ log() << "shell: stopped mongo program on pid " << pid << endl;
+ return BSON("" << (double)code);
+}
- MongoProgramScope::~MongoProgramScope() {
- DESTRUCTOR_GUARD(
- KillMongoProgramInstances();
- ClearRawMongoProgramOutput( BSONObj(), 0 );
- )
- }
+void KillMongoProgramInstances() {
+ vector<int> ports;
+ registry.getRegisteredPorts(ports);
+ for (vector<int>::iterator i = ports.begin(); i != ports.end(); ++i)
+ killDb(*i, ProcessId::fromNative(0), SIGTERM);
+ vector<ProcessId> pids;
+ registry.getRegisteredPids(pids);
+ for (vector<ProcessId>::iterator i = pids.begin(); i != pids.end(); ++i)
+ killDb(0, *i, SIGTERM);
+}
- void installShellUtilsLauncher( Scope& scope ) {
- scope.injectNative( "_startMongoProgram", StartMongoProgram );
- scope.injectNative( "runProgram", RunProgram );
- scope.injectNative( "run", RunProgram );
- scope.injectNative( "_runMongoProgram", RunMongoProgram );
- scope.injectNative( "_stopMongoProgram", StopMongoProgram );
- scope.injectNative( "stopMongoProgramByPid", StopMongoProgramByPid );
- scope.injectNative( "rawMongoProgramOutput", RawMongoProgramOutput );
- scope.injectNative( "clearRawMongoProgramOutput", ClearRawMongoProgramOutput );
- scope.injectNative( "waitProgram" , WaitProgram );
- scope.injectNative( "checkProgram" , CheckProgram );
- scope.injectNative( "resetDbpath", ResetDbpath );
- scope.injectNative( "pathExists", PathExists );
- scope.injectNative( "copyDbpath", CopyDbpath );
- }
- }
+MongoProgramScope::~MongoProgramScope() {
+ DESTRUCTOR_GUARD(KillMongoProgramInstances(); ClearRawMongoProgramOutput(BSONObj(), 0);)
+}
+
+void installShellUtilsLauncher(Scope& scope) {
+ scope.injectNative("_startMongoProgram", StartMongoProgram);
+ scope.injectNative("runProgram", RunProgram);
+ scope.injectNative("run", RunProgram);
+ scope.injectNative("_runMongoProgram", RunMongoProgram);
+ scope.injectNative("_stopMongoProgram", StopMongoProgram);
+ scope.injectNative("stopMongoProgramByPid", StopMongoProgramByPid);
+ scope.injectNative("rawMongoProgramOutput", RawMongoProgramOutput);
+ scope.injectNative("clearRawMongoProgramOutput", ClearRawMongoProgramOutput);
+ scope.injectNative("waitProgram", WaitProgram);
+ scope.injectNative("checkProgram", CheckProgram);
+ scope.injectNative("resetDbpath", ResetDbpath);
+ scope.injectNative("pathExists", PathExists);
+ scope.injectNative("copyDbpath", CopyDbpath);
+}
+}
}