diff options
Diffstat (limited to 'shell/shell_utils.cpp')
-rw-r--r-- | shell/shell_utils.cpp | 383 |
1 files changed, 226 insertions, 157 deletions
diff --git a/shell/shell_utils.cpp b/shell/shell_utils.cpp index b6a67e2..7a62030 100644 --- a/shell/shell_utils.cpp +++ b/shell/shell_utils.cpp @@ -40,47 +40,53 @@ # include <sys/wait.h> #endif +#include "utils.h" #include "../client/dbclient.h" +#include "../util/md5.hpp" #include "../util/processinfo.h" -#include "utils.h" #include "../util/text.h" -#include "../util/md5.hpp" - -extern const char * jsconcatcode_server; +#include "../util/heapcheck.h" +#include "../util/time_support.h" +#include "../util/file.h" namespace mongo { + + DBClientWithCommands *latestConn = 0; + 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); } #endif + // these functions have not been audited for thread safety - currently they are called with an exclusive js mutex namespace shellUtils { Scope* theScope = 0; - + std::string _dbConnect; std::string _dbAuth; - + const char *argv0 = 0; void RecordMyLocation( const char *_argv0 ) { argv0 = _argv0; } - + // helpers - + BSONObj makeUndefined() { BSONObjBuilder b; b.appendUndefined( "" ); return b.obj(); } const BSONObj undefined_ = makeUndefined(); - + BSONObj encapsulate( const BSONObj &obj ) { return BSON( "" << obj ); } - + // real methods - mongo::BSONObj JSSleep(const mongo::BSONObj &args){ + mongo::BSONObj JSSleep(const mongo::BSONObj &args) { assert( args.nFields() == 1 ); assert( args.firstElement().isNumber() ); int ms = int( args.firstElement().number() ); @@ -101,52 +107,52 @@ namespace mongo { return undefined_; } - BSONObj JSGetMemInfo( const BSONObj& args ){ + BSONObj JSGetMemInfo( const BSONObj& args ) { ProcessInfo pi; uassert( 10258 , "processinfo not supported" , pi.supported() ); - + BSONObjBuilder e; e.append( "virtual" , pi.getVirtualMemorySize() ); e.append( "resident" , pi.getResidentSize() ); - + BSONObjBuilder b; b.append( "ret" , e.obj() ); - + return b.obj(); } #ifndef MONGO_SAFE_SHELL - BSONObj listFiles(const BSONObj& _args){ + BSONObj listFiles(const BSONObj& _args) { static BSONObj cd = BSON( "0" << "." ); BSONObj args = _args.isEmpty() ? cd : _args; uassert( 10257 , "need to specify 1 argument to listFiles" , args.nFields() == 1 ); - + BSONObjBuilder lst; - + string rootname = args.firstElement().valuestrsafe(); path root( rootname ); stringstream ss; ss << "listFiles: no such directory: " << rootname; string msg = ss.str(); uassert( 12581, msg.c_str(), boost::filesystem::exists( root ) ); - + directory_iterator end; directory_iterator i( root); - + int num =0; - while ( i != end ){ + while ( i != end ) { path p = *i; BSONObjBuilder b; b << "name" << p.string(); b.appendBool( "isDirectory", is_directory( p ) ); - if ( ! is_directory( p ) ){ - try { + if ( ! is_directory( p ) ) { + try { b.append( "size" , (double)file_size( p ) ); } - catch ( ... ){ + catch ( ... ) { i++; continue; } @@ -159,16 +165,16 @@ namespace mongo { num++; i++; } - + BSONObjBuilder ret; ret.appendArray( "", lst.done() ); return ret.obj(); } - BSONObj ls(const BSONObj& args) { + BSONObj ls(const BSONObj& args) { BSONObj o = listFiles(args); if( !o.isEmpty() ) { - for( BSONObj::iterator i = o.firstElement().Obj().begin(); i.more(); ) { + for( BSONObj::iterator i = o.firstElement().Obj().begin(); i.more(); ) { BSONObj f = i.next().Obj(); cout << f["name"].String(); if( f["isDirectory"].trueValue() ) cout << '/'; @@ -179,38 +185,38 @@ namespace mongo { return BSONObj(); } - BSONObj cd(const BSONObj& args) { + BSONObj cd(const BSONObj& args) { #if defined(_WIN32) std::wstring dir = toWideString( args.firstElement().String().c_str() ); if( SetCurrentDirectory(dir.c_str()) ) return BSONObj(); #else string dir = args.firstElement().String(); -/* if( chdir(dir.c_str) ) == 0 ) - return BSONObj(); - */ + /* if( chdir(dir.c_str) ) == 0 ) + return BSONObj(); + */ if( 1 ) return BSON(""<<"implementation not done for posix"); #endif return BSON( "" << "change directory failed" ); } - BSONObj pwd(const BSONObj&) { + BSONObj pwd(const BSONObj&) { boost::filesystem::path p = boost::filesystem::current_path(); return BSON( "" << p.string() ); } - BSONObj hostname(const BSONObj&) { + BSONObj hostname(const BSONObj&) { return BSON( "" << getHostName() ); } - static BSONElement oneArg(const BSONObj& args) { + static BSONElement oneArg(const BSONObj& args) { uassert( 12597 , "need to specify 1 argument" , args.nFields() == 1 ); return args.firstElement(); } const int CANT_OPEN_FILE = 13300; - BSONObj cat(const BSONObj& args){ + BSONObj cat(const BSONObj& args) { BSONElement e = oneArg(args); stringstream ss; ifstream f(e.valuestrsafe()); @@ -229,7 +235,7 @@ namespace mongo { return BSON( "" << ss.str() ); } - BSONObj md5sumFile(const BSONObj& args){ + BSONObj md5sumFile(const BSONObj& args) { BSONElement e = oneArg(args); stringstream ss; FILE* f = fopen(e.valuestrsafe(), "rb"); @@ -250,17 +256,17 @@ namespace mongo { return BSON( "" << digestToString( d ) ); } - BSONObj mkdir(const BSONObj& args){ + BSONObj mkdir(const BSONObj& args) { boost::filesystem::create_directories(args.firstElement().String()); return BSON( "" << true ); } - BSONObj removeFile(const BSONObj& args){ + BSONObj removeFile(const BSONObj& args) { BSONElement e = oneArg(args); bool found = false; - + path root( args.firstElement().valuestrsafe() ); - if ( boost::filesystem::exists( root ) ){ + if ( boost::filesystem::exists( root ) ) { found = true; boost::filesystem::remove_all( root ); } @@ -269,23 +275,43 @@ namespace mongo { b.appendBool( "removed" , found ); return b.obj(); } + + /** + * @param args - [ name, byte index ] + * In this initial implementation, all bits in the specified byte are flipped. + */ + BSONObj fuzzFile(const BSONObj& args) { + uassert( 13619, "fuzzFile takes 2 arguments", args.nFields() == 2 ); + shared_ptr< File > f( new File() ); + f->open( args.getStringField( "0" ) ); + uassert( 13620, "couldn't open file to fuzz", !f->bad() && f->is_open() ); + + char c; + f->read( args.getIntField( "1" ), &c, 1 ); + c = ~c; + f->write( args.getIntField( "1" ), &c, 1 ); + + return undefined_; + // f close is implicit + } + map< int, pair< pid_t, int > > dbs; map< pid_t, int > shells; #ifdef _WIN32 map< pid_t, HANDLE > handles; #endif - + mongo::mutex mongoProgramOutputMutex("mongoProgramOutputMutex"); stringstream mongoProgramOutput_; - void goingAwaySoon() { + void goingAwaySoon() { mongo::mutex::scoped_lock lk( mongoProgramOutputMutex ); - mongo::goingAway = true; + mongo::dbexitCalled = true; } void writeMongoProgramOutputLine( int port, int pid, const char *line ) { mongo::mutex::scoped_lock lk( mongoProgramOutputMutex ); - if( mongo::goingAway ) throw "program is terminating"; + if( mongo::dbexitCalled ) throw "program is terminating"; stringstream buf; if ( port > 0 ) buf << "m" << port << "| " << line; @@ -294,7 +320,7 @@ namespace mongo { cout << buf.str() << endl; mongoProgramOutput_ << buf.str() << endl; } - + // only returns last 100000 characters BSONObj RawMongoProgramOutput( const BSONObj &args ) { mongo::mutex::scoped_lock lk( mongoProgramOutputMutex ); @@ -310,7 +336,7 @@ namespace mongo { mongoProgramOutput_.str( "" ); return undefined_; } - + class ProgramRunner { vector<string> argv_; int port_; @@ -320,13 +346,13 @@ namespace mongo { pid_t pid() const { return pid_; } int port() const { return port_; } - boost::filesystem::path find(string prog) { + boost::filesystem::path find(string prog) { boost::filesystem::path p = prog; #ifdef _WIN32 p = change_extension(p, ".exe"); #endif - if( boost::filesystem::exists(p) ){ + if( boost::filesystem::exists(p) ) { #ifndef _WIN32 p = boost::filesystem::initial_path() / p; #endif @@ -345,23 +371,23 @@ namespace mongo { if( boost::filesystem::exists(t) ) return t; } } - } catch(...) { } + } + catch(...) { } { boost::filesystem::path t = boost::filesystem::initial_path() / p; if( boost::filesystem::exists(t) ) return t; } return p; // not found; might find via system path - } + } - ProgramRunner( const BSONObj &args , bool isMongoProgram=true) - { + ProgramRunner( const BSONObj &args , bool isMongoProgram=true) { assert( !args.isEmpty() ); string program( args.firstElement().valuestrsafe() ); assert( !program.empty() ); boost::filesystem::path programPath = find(program); - if (isMongoProgram){ + if (isMongoProgram) { #if 0 if (program == "mongos") { argv_.push_back("valgrind"); @@ -375,9 +401,9 @@ namespace mongo { } argv_.push_back( programPath.native_file_string() ); - + port_ = -1; - + BSONObjIterator j( args ); j.next(); // skip program name (handled above) while(j.more()) { @@ -387,7 +413,8 @@ namespace mongo { stringstream ss; ss << e.number(); str = ss.str(); - } else { + } + else { assert( e.type() == mongo::String ); str = e.valuestr(); } @@ -397,7 +424,7 @@ namespace mongo { port_ = strtol( str.c_str(), 0, 10 ); argv_.push_back(str); } - + if ( program != "mongod" && program != "mongos" && program != "mongobridge" ) port_ = 0; else { @@ -405,19 +432,19 @@ namespace mongo { cout << "error: a port number is expected when running mongod (etc.) from the shell" << endl; assert( port_ > 0 ); } - if ( port_ > 0 && dbs.count( port_ ) != 0 ){ + if ( port_ > 0 && dbs.count( port_ ) != 0 ) { cerr << "count for port: " << port_ << " is not 0 is: " << dbs.count( port_ ) << endl; - assert( dbs.count( port_ ) == 0 ); + assert( dbs.count( port_ ) == 0 ); } } - + void start() { int pipeEnds[ 2 ]; assert( pipe( pipeEnds ) != -1 ); - + fflush( 0 ); launch_process(pipeEnds[1]); //sets pid_ - + { stringstream ss; ss << "shell: started program"; @@ -433,52 +460,54 @@ namespace mongo { shells.insert( make_pair( pid_, pipeEnds[ 1 ] ) ); pipe_ = pipeEnds[ 0 ]; } - + // Continue reading output void operator()() { try { - // This assumes there aren't any 0's in the mongo program output. - // Hope that's ok. - const unsigned bufSize = 64000; - char buf[ bufSize ]; - char temp[ bufSize ]; - char *start = buf; - while( 1 ) { - int lenToRead = ( bufSize - 1 ) - ( start - buf ); - assert( lenToRead > 0 ); - int ret = read( pipe_, (void *)start, lenToRead ); - if( mongo::goingAway ) - break; - assert( ret != -1 ); - start[ ret ] = '\0'; - if ( strlen( start ) != unsigned( ret ) ) - writeMongoProgramOutputLine( 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'; - writeMongoProgramOutputLine( port_, pid_, last ); - } - if ( ret == 0 ) { - if ( *last ) + // This assumes there aren't any 0's in the mongo program output. + // Hope that's ok. + const unsigned bufSize = 64000; + char buf[ bufSize ]; + char temp[ bufSize ]; + char *start = buf; + while( 1 ) { + int lenToRead = ( bufSize - 1 ) - ( start - buf ); + assert( lenToRead > 0 ); + int ret = read( pipe_, (void *)start, lenToRead ); + if( mongo::dbexitCalled ) + break; + assert( ret != -1 ); + start[ ret ] = '\0'; + if ( strlen( start ) != unsigned( ret ) ) + writeMongoProgramOutputLine( 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'; writeMongoProgramOutputLine( port_, pid_, last ); - close( pipe_ ); - break; - } - if ( last != buf ) { - strcpy( temp, last ); - strcpy( buf, temp ); - } else { - assert( strlen( buf ) < bufSize ); + } + if ( ret == 0 ) { + if ( *last ) + writeMongoProgramOutputLine( port_, pid_, last ); + close( pipe_ ); + break; + } + if ( last != buf ) { + strcpy( temp, last ); + strcpy( buf, temp ); + } + else { + assert( strlen( buf ) < bufSize ); + } + start = buf + strlen( buf ); } - start = buf + strlen( buf ); - } - } catch(...) { + } + catch(...) { } } - void launch_process(int child_stdout){ + void launch_process(int child_stdout) { #ifdef _WIN32 stringstream ss; - for( unsigned i=0; i < argv_.size(); i++ ){ + for( unsigned i=0; i < argv_.size(); i++ ) { if (i) ss << ' '; if (argv_[i].find(' ') == string::npos) ss << argv_[i]; @@ -487,7 +516,7 @@ namespace mongo { } string args = ss.str(); - + boost::scoped_array<TCHAR> args_tchar (new TCHAR[args.size() + 1]); size_t i; for(i=0; i < args.size(); i++) @@ -519,28 +548,39 @@ namespace mongo { pid_ = pi.dwProcessId; handles.insert( make_pair( pid_, pi.hProcess ) ); - + #else pid_ = fork(); assert( pid_ != -1 ); - + if ( pid_ == 0 ) { // DON'T ASSERT IN THIS BLOCK - very bad things will happen const char** argv = new const char* [argv_.size()+1]; // don't need to free - in child - for (unsigned i=0; i < argv_.size(); i++){ + for (unsigned i=0; i < argv_.size(); i++) { argv[i] = argv_[i].c_str(); } argv[argv_.size()] = 0; - + if ( dup2( child_stdout, STDOUT_FILENO ) == -1 || - dup2( child_stdout, STDERR_FILENO ) == -1 ) - { + dup2( child_stdout, STDERR_FILENO ) == -1 ) { cout << "Unable to dup2 child output: " << errnoWithDescription() << endl; ::_Exit(-1); //do not pass go, do not call atexit handlers } + const char** env = new const char* [2]; // don't need to free - in child + env[0] = NULL; +#if defined(HEAP_CHECKING) + env[0] = "HEAPCHECK=normal"; + env[1] = NULL; + + // Heap-check for mongos only. 'argv[0]' must be in the path format. + if ( argv_[0].find("mongos") != string::npos) { + execvpe( argv[ 0 ], const_cast<char**>(argv) , const_cast<char**>(env) ); + } +#endif // HEAP_CHECKING + execvp( argv[ 0 ], const_cast<char**>(argv) ); cout << "Unable to start program " << argv[0] << ' ' << errnoWithDescription() << endl; @@ -550,9 +590,9 @@ namespace mongo { #endif } }; - + //returns true if process exited - bool wait_for_pid(pid_t pid, bool block=true, int* exit_code=NULL){ + bool wait_for_pid(pid_t pid, bool block=true, int* exit_code=NULL) { #ifdef _WIN32 assert(handles.count(pid)); HANDLE h = handles[pid]; @@ -561,13 +601,17 @@ namespace mongo { WaitForSingleObject(h, INFINITE); DWORD tmp; - if(GetExitCodeProcess(h, &tmp)){ + if(GetExitCodeProcess(h, &tmp)) { + if ( tmp == STILL_ACTIVE ) { + return false; + } CloseHandle(h); handles.erase(pid); if (exit_code) *exit_code = tmp; return true; - }else{ + } + else { return false; } #else @@ -576,17 +620,28 @@ namespace mongo { if (exit_code) *exit_code = WEXITSTATUS(tmp); return ret; - + #endif } - BSONObj WaitProgram( const BSONObj& a ){ - int pid = a.firstElement().numberInt(); + BSONObj WaitProgram( const BSONObj& a ) { + int pid = oneArg( a ).numberInt(); BSONObj x = BSON( "" << wait_for_pid( pid ) ); shells.erase( pid ); return x; } + BSONObj WaitMongoProgramOnPort( const BSONObj &a ) { + int port = oneArg( a ).numberInt(); + uassert( 13621, "no known mongo program on port", dbs.count( port ) != 0 ); + log() << "waiting port: " << port << ", pid: " << dbs[ port ].first << endl; + bool ret = wait_for_pid( dbs[ port ].first ); + if ( ret ) { + dbs.erase( port ); + } + return BSON( "" << ret ); + } + BSONObj StartMongoProgram( const BSONObj &a ) { _nokillop = true; ProgramRunner r( a ); @@ -603,7 +658,8 @@ namespace mongo { wait_for_pid( r.pid(), true, &exit_code ); if ( r.port() > 0 ) { dbs.erase( r.port() ); - } else { + } + else { shells.erase( r.pid() ); } return BSON( string( "" ) << exit_code ); @@ -625,10 +681,10 @@ namespace mongo { assert( !path.empty() ); if ( boost::filesystem::exists( path ) ) boost::filesystem::remove_all( path ); - boost::filesystem::create_directory( path ); + boost::filesystem::create_directory( path ); return undefined_; } - + void copyDir( const path &from, const path &to ) { directory_iterator end; directory_iterator i( from ); @@ -639,14 +695,15 @@ namespace mongo { path newDir = to / p.leaf(); boost::filesystem::create_directory( newDir ); copyDir( p, newDir ); - } else { + } + else { boost::filesystem::copy_file( p, to / p.leaf() ); } } ++i; - } + } } - + // NOTE target dbpath will be cleared first BSONObj CopyDbpath( const BSONObj &a ) { assert( a.nFields() == 2 ); @@ -662,24 +719,26 @@ namespace mongo { return undefined_; } - inline void kill_wrapper(pid_t pid, int sig, int port){ + inline void kill_wrapper(pid_t pid, int sig, int port) { #ifdef _WIN32 - if (sig == SIGKILL || port == 0){ + if (sig == SIGKILL || port == 0) { assert( handles.count(pid) ); TerminateProcess(handles[pid], 1); // returns failure for "zombie" processes. - }else{ + } + else { DBClientConnection conn; conn.connect("127.0.0.1:" + BSONObjBuilder::numStr(port)); try { conn.simpleCommand("admin", NULL, "shutdown"); - } catch (...) { + } + catch (...) { //Do nothing. This command never returns data to the client and the driver doesn't like that. } } #else int x = kill( pid, sig ); - if ( x ){ - if ( errno == ESRCH ){ + if ( x ) { + if ( errno == ESRCH ) { } else { cout << "killFailed: " << errnoWithDescription() << endl; @@ -688,8 +747,8 @@ namespace mongo { } #endif - } - + } + int killDb( int port, pid_t _pid, int signal ) { pid_t pid; int exitCode = 0; @@ -699,12 +758,13 @@ namespace mongo { return 0; } pid = dbs[ port ].first; - } else { + } + else { pid = _pid; } - + kill_wrapper( pid, signal, port ); - + int i = 0; for( ; i < 130; ++i ) { if ( i == 30 ) { @@ -713,12 +773,12 @@ namespace mongo { now[ 20 ] = 0; cout << now << " process on port " << port << ", with pid " << pid << " not terminated, sending sigkill" << endl; kill_wrapper( pid, SIGKILL, port ); - } + } if(wait_for_pid(pid, false, &exitCode)) break; sleepmillis( 1000 ); } - if ( i == 65 ) { + if ( i == 130 ) { char now[64]; time_t_to_String(time(0), now); now[ 20 ] = 0; @@ -729,14 +789,17 @@ namespace mongo { if ( port > 0 ) { close( dbs[ port ].second ); dbs.erase( port ); - } else { + } + else { close( shells[ pid ] ); shells.erase( 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; } @@ -751,7 +814,8 @@ namespace mongo { } return ret; } - + + /** stopMongoProgram(port[, signal]) */ BSONObj StopMongoProgram( const BSONObj &a ) { assert( a.nFields() == 1 || a.nFields() == 2 ); assert( a.firstElement().isNumber() ); @@ -759,23 +823,23 @@ namespace mongo { int code = killDb( port, 0, getSignal( a ) ); cout << "shell: stopped mongo program on port " << port << endl; return BSON( "" << code ); - } - + } + BSONObj StopMongoProgramByPid( const BSONObj &a ) { assert( a.nFields() == 1 || a.nFields() == 2 ); assert( a.firstElement().isNumber() ); - int pid = int( a.firstElement().number() ); + int pid = int( a.firstElement().number() ); int code = killDb( 0, pid, getSignal( a ) ); cout << "shell: stopped mongo program on pid " << pid << endl; return BSON( "" << code ); } - + void KillMongoProgramInstances() { vector< int > ports; for( map< int, pair< pid_t, int > >::iterator i = dbs.begin(); i != dbs.end(); ++i ) ports.push_back( i->first ); for( vector< int >::iterator i = ports.begin(); i != ports.end(); ++i ) - killDb( *i, 0, SIGTERM ); + killDb( *i, 0, SIGTERM ); vector< pid_t > pids; for( map< pid_t, int >::iterator i = shells.begin(); i != shells.end(); ++i ) pids.push_back( i->first ); @@ -785,7 +849,7 @@ namespace mongo { #else // ndef MONGO_SAFE_SHELL void KillMongoProgramInstances() {} #endif - + MongoProgramScope::~MongoProgramScope() { DESTRUCTOR_GUARD( KillMongoProgramInstances(); @@ -794,14 +858,14 @@ namespace mongo { } unsigned _randomSeed; - + BSONObj JSSrand( const BSONObj &a ) { uassert( 12518, "srand requires a single numeric argument", - a.nFields() == 1 && a.firstElement().isNumber() ); + a.nFields() == 1 && a.firstElement().isNumber() ); _randomSeed = (unsigned)a.firstElement().numberLong(); // grab least significant digits return undefined_; } - + BSONObj JSRand( const BSONObj &a ) { uassert( 12519, "rand accepts no arguments", a.nFields() == 0 ); unsigned r; @@ -813,7 +877,7 @@ namespace mongo { return BSON( "" << double( r ) / ( double( RAND_MAX ) + 1 ) ); } - BSONObj isWindows(const BSONObj& a){ + BSONObj isWindows(const BSONObj& a) { uassert( 13006, "isWindows accepts no arguments", a.nFields() == 0 ); #ifdef _WIN32 return BSON( "" << true ); @@ -822,7 +886,7 @@ namespace mongo { #endif } - BSONObj getHostName(const BSONObj& a){ + BSONObj getHostName(const BSONObj& a) { uassert( 13411, "getHostName accepts no arguments", a.nFields() == 0 ); char buf[260]; // HOST_NAME_MAX is usually 255 assert(gethostname(buf, 260) == 0); @@ -830,8 +894,8 @@ namespace mongo { return BSON("" << buf); } - - void installShellUtils( Scope& scope ){ + + void installShellUtils( Scope& scope ) { theScope = &scope; scope.injectNative( "sleep" , JSSleep ); scope.injectNative( "quit", Quit ); @@ -847,14 +911,16 @@ namespace mongo { scope.injectNative( "run", RunProgram ); scope.injectNative( "runMongoProgram", RunMongoProgram ); scope.injectNative( "stopMongod", StopMongoProgram ); - scope.injectNative( "stopMongoProgram", StopMongoProgram ); - scope.injectNative( "stopMongoProgramByPid", StopMongoProgramByPid ); + scope.injectNative( "stopMongoProgram", StopMongoProgram ); + scope.injectNative( "stopMongoProgramByPid", StopMongoProgramByPid ); scope.injectNative( "rawMongoProgramOutput", RawMongoProgramOutput ); scope.injectNative( "clearRawMongoProgramOutput", ClearRawMongoProgramOutput ); scope.injectNative( "waitProgram" , WaitProgram ); + scope.injectNative( "waitMongoProgramOnPort" , WaitMongoProgramOnPort ); scope.injectNative( "getHostName" , getHostName ); scope.injectNative( "removeFile" , removeFile ); + scope.injectNative( "fuzzFile" , fuzzFile ); scope.injectNative( "listFiles" , listFiles ); scope.injectNative( "ls" , ls ); scope.injectNative( "pwd", pwd ); @@ -871,8 +937,8 @@ namespace mongo { void initScope( Scope &scope ) { scope.externalSetup(); mongo::shellUtils::installShellUtils( scope ); - scope.execSetup( jsconcatcode_server , "setupServerCode" ); - + scope.execSetup(JSFiles::servers); + if ( !_dbConnect.empty() ) { uassert( 12513, "connect failed", scope.exec( _dbConnect , "(connect)" , false , true , false ) ); if ( !_dbAuth.empty() ) { @@ -881,18 +947,21 @@ namespace mongo { } } } - - map< const void*, string > _allMyUris; + + // connstr, myuris + map< string, set<string> > _allMyUris; + mongo::mutex _allMyUrisMutex("_allMyUrisMutex"); bool _nokillop = false; void onConnect( DBClientWithCommands &c ) { + latestConn = &c; if ( _nokillop ) { return; } BSONObj info; if ( c.runCommand( "admin", BSON( "whatsmyuri" << 1 ), info ) ) { - // There's no way to explicitly disconnect a DBClientConnection, but we might allocate - // a new uri on automatic reconnect. So just store one uri per connection. - _allMyUris[ &c ] = info[ "you" ].str(); + string connstr = dynamic_cast<DBClientBase&>(c).getServerAddress(); + mongo::mutex::scoped_lock lk( _allMyUrisMutex ); + _allMyUris[connstr].insert(info[ "you" ].str()); } } } |