예제 #1
0
파일: element.cpp 프로젝트: aopui/gnash
/// \brief Make this Element a Property with an Undefined data type.
///
/// @param name The name of the Property
///
/// @return A reference to this Element.
Element &
Element::makeUndefined(const std::string &name)
{
//    GNASH_REPORT_FUNCTION;
    if (name.size()) {
        setName(name);
    }
    return makeUndefined();
}
예제 #2
0
파일: bsonobj.cpp 프로젝트: kingfs/tokumxse
            if ( ordered && o.number() < 0 )
                x = -x;
        }
        if ( x != 0 )
            return x;
    }
    return -1;
}

BSONObj staticNull = fromjson( "{'':null}" );
BSONObj makeUndefined() {
    BSONObjBuilder b;
    b.appendUndefined( "" );
    return b.obj();
}
BSONObj staticUndefined = makeUndefined();

/* well ordered compare */
int BSONObj::woSortOrder(const BSONObj& other, const BSONObj& sortKey , bool useDotted ) const {
    if ( isEmpty() )
        return other.isEmpty() ? 0 : -1;
    if ( other.isEmpty() )
        return 1;

    uassert( 10060 ,  "woSortOrder needs a non-empty sortKey" , ! sortKey.isEmpty() );

    BSONObjIterator i(sortKey);
    while ( 1 ) {
        BSONElement f = i.next();
        if ( f.eoo() )
            return 0;
예제 #3
0
namespace shell_utils {

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 undefinedReturn = makeUndefined();

BSONElement singleArg(const BSONObj& args) {
    uassert(12597, "need to specify 1 argument", args.nFields() == 1);
    return args.firstElement();
}

const char* getUserDir() {
#ifdef _WIN32
    return getenv("USERPROFILE");
#else
    return getenv("HOME");
#endif
}

// real methods

BSONObj JSGetMemInfo(const BSONObj& args, void* data) {
    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();
}

#if !defined(_WIN32)
ThreadLocalValue<unsigned int> _randomSeed;
#endif

BSONObj JSSrand(const BSONObj& a, void* data) {
    unsigned int seed;
    // grab the least significant bits of either the supplied argument or
    // a random number from SecureRandom.
    if (a.nFields() == 1 && a.firstElement().isNumber())
        seed = static_cast<unsigned int>(a.firstElement().numberLong());
    else {
        std::unique_ptr<SecureRandom> rand(SecureRandom::create());
        seed = static_cast<unsigned int>(rand->nextInt64());
    }
#if !defined(_WIN32)
    _randomSeed.set(seed);
#else
    srand(seed);
#endif
    return BSON("" << static_cast<double>(seed));
}

BSONObj JSRand(const BSONObj& a, void* data) {
    uassert(12519, "rand accepts no arguments", a.nFields() == 0);
    unsigned r;
#if !defined(_WIN32)
    r = rand_r(&_randomSeed.getRef());
#else
    r = rand();
#endif
    return BSON("" << double(r) / (double(RAND_MAX) + 1));
}

BSONObj isWindows(const BSONObj& a, void* data) {
    uassert(13006, "isWindows accepts no arguments", a.nFields() == 0);
#ifdef _WIN32
    return BSON("" << true);
#else
    return BSON("" << false);
#endif
}

BSONObj getBuildInfo(const BSONObj& a, void* data) {
    uassert(16822, "getBuildInfo accepts no arguments", a.nFields() == 0);
    BSONObjBuilder b;
    VersionInfoInterface::instance().appendBuildInfo(&b);
    return BSON("" << b.done());
}

BSONObj isKeyTooLarge(const BSONObj& a, void* data) {
    uassert(17428, "keyTooLarge takes exactly 2 arguments", a.nFields() == 2);
    BSONObjIterator i(a);
    BSONObj index = i.next().Obj();
    BSONObj doc = i.next().Obj();

    return BSON("" << isAnyIndexKeyTooLarge(index, doc));
}

BSONObj validateIndexKey(const BSONObj& a, void* data) {
    BSONObj key = a[0].Obj();
    Status indexValid = validateKeyPattern(key);
    if (!indexValid.isOK()) {
        return BSON("" << BSON("ok" << false << "type" << indexValid.codeString() << "errmsg"
                                    << indexValid.reason()));
    }
    return BSON("" << BSON("ok" << true));
}

BSONObj replMonitorStats(const BSONObj& a, void* data) {
    uassert(17134,
            "replMonitorStats requires a single string argument (the ReplSet name)",
            a.nFields() == 1 && a.firstElement().type() == String);

    ReplicaSetMonitorPtr rsm = ReplicaSetMonitor::get(a.firstElement().valuestrsafe());
    if (!rsm) {
        return BSON(""
                    << "no ReplSetMonitor exists by that name");
    }

    BSONObjBuilder result;
    rsm->appendInfo(result);
    return result.obj();
}

BSONObj useWriteCommandsDefault(const BSONObj& a, void* data) {
    return BSON("" << shellGlobalParams.useWriteCommandsDefault);
}

BSONObj writeMode(const BSONObj&, void*) {
    return BSON("" << shellGlobalParams.writeMode);
}

BSONObj readMode(const BSONObj&, void*) {
    return BSON("" << shellGlobalParams.readMode);
}

BSONObj interpreterVersion(const BSONObj& a, void* data) {
    uassert(16453, "interpreterVersion accepts no arguments", a.nFields() == 0);
    return BSON("" << getGlobalScriptEngine()->getInterpreterVersionString());
}

BSONObj createCertificateRequest(const BSONObj& a, void* data) {
#ifndef MONGO_CONFIG_SSL
    return BSON(
        "" << BSON("ok" << false << "errmsg"
                        << "Cannot create a certificate signing request without SSL support"));
#else
    if (a.nFields() != 1 || a.firstElement().type() != Object) {
        return BSON(
            "" << BSON("ok" << false << "errmsg"
                            << "createCertificateRequest requires a single object argument"));
    }

    // args can optionally contain some to be determined fields...
    BSONObj args = a.firstElement().embeddedObject();
    if (!args.hasField("CN")) {
        return BSON(
            "" << BSON("ok" << false << "errmsg"
                            << "createCertificateRequest requires a Common Name (\"CN\") field"));
    }

    // Generate key pair and certificate signing request
    RSA* rsa;
    EVP_PKEY* pkey;
    X509_REQ* x509req;
    X509_NAME* name;
    BIO* out;
    char client_key[2048];
    char client_csr[2048];

    pkey = EVP_PKEY_new();
    if (!pkey) {
        return BSON("" << BSON("ok" << false));
        // fail("couldn't generate key");
    }

    rsa = RSA_generate_key(2048, RSA_F4, NULL, NULL);
    if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
        return BSON("" << BSON("ok" << false));
        // fail("couldn't assign the key");
    }

    x509req = X509_REQ_new();
    X509_REQ_set_pubkey(x509req, pkey);

    name = X509_NAME_new();
    X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (const unsigned char*)"IS", -1, -1, 0);
    X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (const unsigned char*)"MongoDB", -1, -1, 0);
    X509_NAME_add_entry_by_txt(
        name, "OU", MBSTRING_ASC, (const unsigned char*)"SkunkWorks client", -1, -1, 0);
    X509_NAME_add_entry_by_txt(
        name, "CN", MBSTRING_ASC, (const unsigned char*)args.getStringField("CN"), -1, -1, 0);

    X509_REQ_set_subject_name(x509req, name);
    X509_REQ_set_version(x509req, 2);

    if (!X509_REQ_sign(x509req, pkey, EVP_sha1())) {
        return BSON("" << BSON("ok" << false));
    }

    // out = BIO_new_file("client.key.pem", "wb");
    out = BIO_new(BIO_s_mem());
    if (!PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, NULL)) {
        return BSON("" << BSON("ok" << false));
        // fail("can't write private key");
    }
    int i = BIO_read(out, &client_key, sizeof client_key);
    client_key[i] = '\0';

    BIO_free_all(out);
    out = BIO_new(BIO_s_mem());
    if (!PEM_write_bio_X509_REQ_NEW(out, x509req)) {
        return BSON("" << BSON("ok" << false));
        // fail("coudln't write csr");
    }
    i = BIO_read(out, &client_csr, sizeof client_csr);
    client_csr[i] = '\0';
    BIO_free_all(out);

    EVP_PKEY_free(pkey);
    X509_REQ_free(x509req);


    return BSON("" << BSON("ok" << true << "certificateRequest" << client_csr << "privateKey"
                                << client_key));
#endif
}

void installShellUtils(Scope& scope) {
    scope.injectNative("getMemInfo", JSGetMemInfo);
    scope.injectNative("_replMonitorStats", replMonitorStats);
    scope.injectNative("_srand", JSSrand);
    scope.injectNative("_rand", JSRand);
    scope.injectNative("_isWindows", isWindows);
    scope.injectNative("interpreterVersion", interpreterVersion);
    scope.injectNative("getBuildInfo", getBuildInfo);
    scope.injectNative("isKeyTooLarge", isKeyTooLarge);
    scope.injectNative("validateIndexKey", validateIndexKey);
    scope.injectNative("createCertificateRequest", createCertificateRequest);

#ifndef MONGO_SAFE_SHELL
    // can't launch programs
    installShellUtilsLauncher(scope);
    installShellUtilsExtended(scope);
#endif
}

void initScope(Scope& scope) {
    // Need to define this method before JSFiles::utils is executed.
    scope.injectNative("_useWriteCommandsDefault", useWriteCommandsDefault);
    scope.injectNative("_writeMode", writeMode);
    scope.injectNative("_readMode", readMode);
    scope.externalSetup();
    mongo::shell_utils::installShellUtils(scope);
    scope.execSetup(JSFiles::servers);
    scope.execSetup(JSFiles::shardingtest);
    scope.execSetup(JSFiles::servers_misc);
    scope.execSetup(JSFiles::replsettest);
    scope.execSetup(JSFiles::bridge);

    scope.injectNative("benchRun", BenchRunner::benchRunSync);
    scope.injectNative("benchRunSync", BenchRunner::benchRunSync);
    scope.injectNative("benchStart", BenchRunner::benchStart);
    scope.injectNative("benchFinish", BenchRunner::benchFinish);

    if (!_dbConnect.empty()) {
        uassert(12513, "connect failed", scope.exec(_dbConnect, "(connect)", false, true, false));
    }
    if (!_dbAuth.empty()) {
        uassert(12514, "login failed", scope.exec(_dbAuth, "(auth)", true, true, false));
    }
}

Prompter::Prompter(const string& prompt) : _prompt(prompt), _confirmed() {}

bool Prompter::confirm() {
    if (_confirmed) {
        return true;
    }

    // The printf and scanf functions provide thread safe i/o.

    printf("\n%s (y/n): ", _prompt.c_str());

    char yn = '\0';
    int nScanMatches = scanf("%c", &yn);
    bool matchedY = (nScanMatches == 1 && (yn == 'y' || yn == 'Y'));

    return _confirmed = matchedY;
}

ConnectionRegistry::ConnectionRegistry() = default;

void ConnectionRegistry::registerConnection(DBClientWithCommands& client) {
    BSONObj info;
    if (client.runCommand("admin", BSON("whatsmyuri" << 1), info)) {
        string connstr = dynamic_cast<DBClientBase&>(client).getServerAddress();
        stdx::lock_guard<stdx::mutex> lk(_mutex);
        _connectionUris[connstr].insert(info["you"].str());
    }
}

void ConnectionRegistry::killOperationsOnAllConnections(bool withPrompt) const {
    Prompter prompter("do you want to kill the current op(s) on the server?");
    stdx::lock_guard<stdx::mutex> lk(_mutex);
    for (map<string, set<string>>::const_iterator i = _connectionUris.begin();
         i != _connectionUris.end();
         ++i) {
        auto status = ConnectionString::parse(i->first);
        if (!status.isOK()) {
            continue;
        }

        const ConnectionString cs(status.getValue());

        string errmsg;
        std::unique_ptr<DBClientWithCommands> conn(cs.connect("MongoDB Shell", errmsg));
        if (!conn) {
            continue;
        }

        const set<string>& uris = i->second;

        BSONObj currentOpRes;
        conn->runPseudoCommand("admin", "currentOp", "$cmd.sys.inprog", {}, currentOpRes);
        if (!currentOpRes["inprog"].isABSONObj()) {
            // We don't have permissions (or the call didn't succeed) - go to the next connection.
            continue;
        }
        auto inprog = currentOpRes["inprog"].embeddedObject();
        for (const auto op : inprog) {
            // For sharded clusters, `client_s` is used instead and `client` is not present.
            string client;
            if (auto elem = op["client"]) {
                // mongod currentOp client
                if (elem.type() != String) {
                    warning() << "Ignoring operation " << op["opid"].toString(false)
                              << "; expected 'client' field in currentOp response to have type "
                                 "string, but found "
                              << typeName(elem.type());
                    continue;
                }
                client = elem.str();
            } else if (auto elem = op["client_s"]) {
                // mongos currentOp client
                if (elem.type() != String) {
                    warning() << "Ignoring operation " << op["opid"].toString(false)
                              << "; expected 'client_s' field in currentOp response to have type "
                                 "string, but found "
                              << typeName(elem.type());
                    continue;
                }
                client = elem.str();
            } else {
                // Internal operation, like TTL index.
                continue;
            }
            if (uris.count(client)) {
                if (!withPrompt || prompter.confirm()) {
                    BSONObjBuilder cmdBob;
                    BSONObj info;
                    cmdBob.appendAs(op["opid"], "op");
                    auto cmdArgs = cmdBob.done();
                    conn->runPseudoCommand("admin", "killOp", "$cmd.sys.killop", cmdArgs, info);
                } else {
                    return;
                }
            }
        }
    }
}

ConnectionRegistry connectionRegistry;

bool _nokillop = false;
void onConnect(DBClientWithCommands& c) {
    if (_nokillop) {
        return;
    }

    // Only override the default rpcProtocols if they were set on the command line.
    if (shellGlobalParams.rpcProtocols) {
        c.setClientRPCProtocols(*shellGlobalParams.rpcProtocols);
    }

    connectionRegistry.registerConnection(c);
}

bool fileExists(const std::string& file) {
    try {
#ifdef _WIN32
        boost::filesystem::path p(toWideString(file.c_str()));
#else
        boost::filesystem::path p(file);
#endif
        return boost::filesystem::exists(p);
    } catch (...) {
        return false;
    }
}


stdx::mutex& mongoProgramOutputMutex(*(new stdx::mutex()));
}
예제 #4
0
파일: utils.cpp 프로젝트: alanw/mongo
    namespace shellUtils {
        
        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 );
        }

        void sleepms( int ms ) {
            boost::xtime xt;
            boost::xtime_get(&xt, boost::TIME_UTC);
            xt.sec += ( ms / 1000 );
            xt.nsec += ( ms % 1000 ) * 1000000;
            if ( xt.nsec >= 1000000000 ) {
                xt.nsec -= 1000000000;
                xt.sec++;
            }
            boost::thread::sleep(xt);    
        }
        
        // real methods


        
        mongo::BSONObj JSSleep(const mongo::BSONObj &args){
            assert( args.nFields() == 1 );
            assert( args.firstElement().isNumber() );
            int ms = int( args.firstElement().number() );
            sleepms( ms );
            return undefined_;
        }

        BSONObj listFiles(const BSONObj& args){
            uassert( "need to specify 1 argument to listFiles" , args.nFields() == 1 );
            
            BSONObjBuilder lst;
            
            string rootname = args.firstElement().valuestrsafe();
            path root( rootname );
            
            directory_iterator end;
            directory_iterator i( root);
            
            int num =0;
            while ( i != end ){
                path p = *i;
                
                BSONObjBuilder b;
                b << "name" << p.string();
                b.appendBool( "isDirectory", is_directory( p ) );
                stringstream ss;
                ss << num;
                string name = ss.str();
                lst.append( name.c_str(), b.done() );
                
                num++;
                i++;
            }
            
            BSONObjBuilder ret;
            ret.appendArray( "", lst.done() );
            return ret.obj();
        }
        
        BSONObj Quit(const BSONObj& args) {
            // If not arguments are given first element will be EOO, which
            // converts to the integer value 0.
            int exit_code = int( args.firstElement().number() );
            ::exit(exit_code);
            return undefined_;
        }

        BSONObj JSGetMemInfo( const BSONObj& args ){
            ProcessInfo pi;
            uassert( "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();
        }

        BSONObj JSVersion( const BSONObj& args ){
            cout << "version: " << versionString << endl;
            if ( strstr( versionString , "+" ) )
                printGitVersion();
            return BSONObj();
        }
        
#ifndef _WIN32
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
        
        BSONObj AllocatePorts( const BSONObj &args ) {
            uassert( "allocatePorts takes exactly 1 argument", args.nFields() == 1 );
            uassert( "allocatePorts needs to be passed an integer", args.firstElement().isNumber() );
            
            int n = int( args.firstElement().number() );
            
            vector< int > ports;
            vector< int > sockets;
            for( int i = 0; i < n; ++i ) {
                int s = socket( AF_INET, SOCK_STREAM, 0 );
                assert( s );
                
                sockaddr_in address;
                memset(address.sin_zero, 0, sizeof(address.sin_zero));
                address.sin_family = AF_INET;
                address.sin_port = 0;
                address.sin_addr.s_addr = inet_addr( "127.0.0.1" );
                assert( 0 == ::bind( s, (sockaddr*)&address, sizeof( address ) ) );
                
                sockaddr_in newAddress;
                socklen_t len = sizeof( newAddress );
                assert( 0 == getsockname( s, (sockaddr*)&newAddress, &len ) );
                ports.push_back( ntohs( newAddress.sin_port ) );
                sockets.push_back( s );
            }
            for( vector< int >::const_iterator i = sockets.begin(); i != sockets.end(); ++i )
                assert( 0 == close( *i ) );
            
            sort( ports.begin(), ports.end() );
            for( unsigned i = 1; i < ports.size(); ++i )
                massert( "duplicate ports allocated", ports[ i - 1 ] != ports[ i ] );
            BSONObjBuilder b;
            b.append( "", ports );
            return b.obj();
        }

        map< int, pair< pid_t, int > > dbs;
        map< pid_t, int > shells;
        
        char *copyString( const char *original ) {
            char *ret = reinterpret_cast< char * >( malloc( strlen( original ) + 1 ) );
            strcpy( ret, original );
            return ret;
        }
        
        boost::mutex &mongoProgramOutputMutex( *( new boost::mutex ) );
        stringstream mongoProgramOutput_;
        
        void writeMongoProgramOutputLine( int port, int pid, const char *line ) {
            boost::mutex::scoped_lock lk( mongoProgramOutputMutex );
            stringstream buf;
            if ( port > 0 )
                buf << "m" << port << "| " << line;
            else
                buf << "sh" << pid << "| " << line;
            cout << buf.str() << endl;
            mongoProgramOutput_ << buf.str() << endl;
        }
        
        BSONObj RawMongoProgramOutput( const BSONObj &args ) {
            boost::mutex::scoped_lock lk( mongoProgramOutputMutex );
            return BSON( "" << mongoProgramOutput_.str() );
        }
                
        class MongoProgramRunner {
            char **argv_;
            int port_;
            int pipe_;
            pid_t pid_;
        public:
            pid_t pid() const { return pid_; }
            MongoProgramRunner( const BSONObj &args ) {
                assert( args.nFields() > 0 );
                string program( args.firstElement().valuestrsafe() );
                
                assert( !program.empty() );
                boost::filesystem::path programPath = ( boost::filesystem::path( argv0 ) ).branch_path() / program;
                massert( "couldn't find " + programPath.native_file_string(), boost::filesystem::exists( programPath ) );
                
                port_ = -1;
                argv_ = new char *[ args.nFields() + 1 ];
                {
                    string s = programPath.native_file_string();
                    if ( s == program )
                        s = "./" + s;
                    argv_[ 0 ] = copyString( s.c_str() );
                }
                
                BSONObjIterator j( args );
                j.next();
                for( int i = 1; i < args.nFields(); ++i ) {
                    BSONElement e = j.next();
                    string str;
                    if ( e.isNumber() ) {
                        stringstream ss;
                        ss << e.number();
                        str = ss.str();
                    } else {
                        assert( e.type() == mongo::String );
                        str = e.valuestr();
                    }
                    char *s = copyString( str.c_str() );
                    if ( string( "--port" ) == s )
                        port_ = -2;
                    else if ( port_ == -2 )
                        port_ = strtol( s, 0, 10 );
                    argv_[ i ] = s;
                }
                argv_[ args.nFields() ] = 0;
                
                if ( program != "mongod" && program != "mongos" && program != "mongobridge" )
                    port_ = 0;
                else
                    assert( 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 );        
                }
            }
            
            void start() {
                int pipeEnds[ 2 ];
                assert( pipe( pipeEnds ) != -1 );
                
                fflush( 0 );
                pid_ = fork();
                assert( pid_ != -1 );
                
                if ( pid_ == 0 ) {
                    assert( dup2( pipeEnds[ 1 ], STDOUT_FILENO ) != -1 );
                    assert( dup2( pipeEnds[ 1 ], STDERR_FILENO ) != -1 );
                    execvp( argv_[ 0 ], argv_ );
                    assert( "Unable to start program" == 0 );
                }
                
                cout << "shell: started mongo program";
                int i = 0;
                while( argv_[ i ] )
                    cout << " " << argv_[ i++ ];
                cout << endl;
                
                i = 0;
                while( argv_[ i ] )
                    free( argv_[ i++ ] );
                free( argv_ );

                if ( port_ > 0 )
                    dbs.insert( make_pair( port_, make_pair( pid_, pipeEnds[ 1 ] ) ) );
                else
                    shells.insert( make_pair( pid_, pipeEnds[ 1 ] ) );
                pipe_ = pipeEnds[ 0 ];
            }
            
            // Continue reading output
            void operator()() {
                // This assumes there aren't any 0's in the mongo program output.
                // Hope that's ok.
                char buf[ 1024 ];
                char temp[ 1024 ];
                char *start = buf;
                while( 1 ) {
                    int lenToRead = 1023 - ( start - buf );
                    int ret = read( pipe_, (void *)start, lenToRead );
                    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 )
                            writeMongoProgramOutputLine( port_, pid_, last );
                        close( pipe_ );
                        break;
                    }
                    if ( last != buf ) {
                        strcpy( temp, last );
                        strcpy( buf, temp );
                    } else {
                        assert( strlen( buf ) < 1023 );
                    }
                    start = buf + strlen( buf );
                }        
            }
        };
        
        BSONObj StartMongoProgram( const BSONObj &a ) {
            MongoProgramRunner r( a );
            r.start();
            boost::thread t( r );
            return BSON( string( "" ) << int( r.pid() ) );
        }

        BSONObj ResetDbpath( const BSONObj &a ) {
            assert( a.nFields() == 1 );
            string path = a.firstElement().valuestrsafe();
            assert( !path.empty() );
            if ( boost::filesystem::exists( path ) )
                boost::filesystem::remove_all( path );
            boost::filesystem::create_directory( path );    
            return undefined_;
        }
        
        void killDb( int port, pid_t _pid, int signal ) {
            pid_t pid;
            if ( port > 0 ) {
                if( dbs.count( port ) != 1 ) {
                    cout << "No db started on port: " << port << endl;
                    return;
                }
                pid = dbs[ port ].first;
            } else {
                pid = _pid;
            }
            
            assert( 0 == kill( pid, signal ) );
            
            int i = 0;
            for( ; i < 65; ++i ) {
                if ( i == 5 ) {
                    char now[64];
                    time_t_to_String(time(0), now);
                    now[ 20 ] = 0;
                    cout << now << " process on port " << port << ", with pid " << pid << " not terminated, sending sigkill" << endl;
                    assert( 0 == kill( pid, SIGKILL ) );
                }        
                int temp;
                int ret = waitpid( pid, &temp, WNOHANG );
                if ( ret == pid )
                    break;
                sleepms( 1000 );
            }
            if ( i == 65 ) {
                char now[64];
                time_t_to_String(time(0), now);
                now[ 20 ] = 0;
                cout << now << " failed to terminate process on port " << port << ", with pid " << pid << endl;
                assert( "Failed to terminate process" == 0 );
            }
            
            if ( port > 0 ) {
                close( dbs[ port ].second );
                dbs.erase( port );
            } else {
                close( shells[ pid ] );
                shells.erase( pid );
            }
            if ( i > 4 || signal == SIGKILL ) {
                sleepms( 4000 ); // allow operating system to reclaim resources
            }
        }

        int getSignal( const BSONObj &a ) {
            int ret = SIGTERM;
            if ( a.nFields() == 2 ) {
                BSONObjIterator i( a );
                i.next();
                BSONElement e = i.next();
                assert( e.isNumber() );
                ret = int( e.number() );
            }
            return ret;
        }
        
        BSONObj StopMongoProgram( const BSONObj &a ) {
            assert( a.nFields() == 1 || a.nFields() == 2 );
            assert( a.firstElement().isNumber() );
            int port = int( a.firstElement().number() );
            killDb( port, 0, getSignal( a ) );
            cout << "shell: stopped mongo program on port " << port << endl;
            return undefined_;
        }        
        
        BSONObj StopMongoProgramByPid( const BSONObj &a ) {
            assert( a.nFields() == 1 || a.nFields() == 2 );
            assert( a.firstElement().isNumber() );
            int pid = int( a.firstElement().number() );            
            killDb( 0, pid, getSignal( a ) );
            cout << "shell: stopped mongo program on pid " << pid << endl;
            return undefined_;            
        }
                                                
        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 );            
            vector< pid_t > pids;
            for( map< pid_t, int >::iterator i = shells.begin(); i != shells.end(); ++i )
                pids.push_back( i->first );
            for( vector< pid_t >::iterator i = pids.begin(); i != pids.end(); ++i )
                killDb( 0, *i, SIGTERM );
        }
        
        MongoProgramScope::~MongoProgramScope() {
            try {
                KillMongoProgramInstances();
            } catch ( ... ) {
                assert( false );
            }
        }

#else
        MongoProgramScope::~MongoProgramScope() {}
        void KillMongoProgramInstances() {}        
#endif
        
        void installShellUtils( Scope& scope ){
            scope.injectNative( "listFiles" , listFiles );
            scope.injectNative( "sleep" , JSSleep );
            scope.injectNative( "quit", Quit );
            scope.injectNative( "getMemInfo" , JSGetMemInfo );
            scope.injectNative( "version" , JSVersion );
#if !defined(_WIN32)
            scope.injectNative( "allocatePorts", AllocatePorts );
            scope.injectNative( "_startMongoProgram", StartMongoProgram );
            scope.injectNative( "stopMongod", StopMongoProgram );
            scope.injectNative( "stopMongoProgram", StopMongoProgram );        
            scope.injectNative( "stopMongoProgramByPid", StopMongoProgramByPid );        
            scope.injectNative( "resetDbpath", ResetDbpath );
            scope.injectNative( "rawMongoProgramOutput", RawMongoProgramOutput );
#endif
        }
        
    }