WindowsCommandLine::WindowsCommandLine(int argc, wchar_t* argvW[], wchar_t* envpW[]) : _argv(NULL), _envp(NULL) { // Construct UTF-8 copy of arguments vector<string> utf8args; vector<size_t> utf8argLength; size_t blockSize = argc * sizeof(char*); size_t blockPtr = blockSize; for (int i = 0; i < argc; ++i) { utf8args.push_back( toUtf8String(argvW[i]) ); size_t argLength = utf8args[i].length() + 1; utf8argLength.push_back(argLength); blockSize += argLength; } _argv = static_cast<char**>(malloc(blockSize)); for (int i = 0; i < argc; ++i) { _argv[i] = reinterpret_cast<char*>(_argv) + blockPtr; strcpy_s(_argv[i], utf8argLength[i], utf8args[i].c_str()); blockPtr += utf8argLength[i]; } // Construct UTF-8 copy of environment strings size_t envCount = 0; wchar_t** envpWptr = &envpW[0]; while (*envpWptr++) { ++envCount; } vector<string> utf8envs; vector<size_t> utf8envLength; blockSize = (envCount + 1) * sizeof(char*); blockPtr = blockSize; for (size_t i = 0; i < envCount; ++i) { utf8envs.push_back( toUtf8String(envpW[i]) ); size_t envLength = utf8envs[i].length() + 1; utf8envLength.push_back(envLength); blockSize += envLength; } _envp = static_cast<char**>(malloc(blockSize)); size_t i; for (i = 0; i < envCount; ++i) { _envp[i] = reinterpret_cast<char*>(_envp) + blockPtr; strcpy_s(_envp[i], utf8envLength[i], utf8envs[i].c_str()); blockPtr += utf8envLength[i]; } _envp[i] = NULL; }
bool ServiceController::removeService( const std::wstring& serviceName ) { SC_HANDLE schSCManager = ::OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if ( schSCManager == NULL ) { DWORD err = ::GetLastError(); cerr << "Error connecting to the Service Control Manager: " << GetWinErrMsg(err) << endl; return false; } SC_HANDLE schService = ::OpenService( schSCManager, serviceName.c_str(), SERVICE_ALL_ACCESS ); if ( schService == NULL ) { cerr << "Could not find a service named " << toUtf8String(serviceName) << " to uninstall." << endl; ::CloseServiceHandle( schSCManager ); return false; } SERVICE_STATUS serviceStatus; // stop service if its running if ( ::ControlService( schService, SERVICE_CONTROL_STOP, &serviceStatus ) ) { cerr << "Service " << toUtf8String(serviceName) << " is currently running. Stopping service." << endl; while ( ::QueryServiceStatus( schService, &serviceStatus ) ) { if ( serviceStatus.dwCurrentState == SERVICE_STOP_PENDING ) { Sleep( 1000 ); } else { break; } } cerr << "Service stopped." << endl; } cerr << "Deleting service " << toUtf8String(serviceName) << "." << endl; bool serviceRemoved = ::DeleteService( schService ); ::CloseServiceHandle( schService ); ::CloseServiceHandle( schSCManager ); if (serviceRemoved) { cerr << "Service deleted successfully." << endl; } else { cerr << "Failed to delete service." << endl; } return serviceRemoved; }
std::string errnoWithDescription(int errNumber) { #if defined(_WIN32) if (errNumber == -1) errNumber = GetLastError(); #else if (errNumber < 0) errNumber = errno; #endif char buf[kBuflen]; char* msg{nullptr}; #if defined(__GNUC__) && defined(_GNU_SOURCE) && !(__ANDROID_API__ <= 22) && !defined(EMSCRIPTEN) msg = strerror_r(errNumber, buf, kBuflen); #elif defined(_WIN32) LPWSTR errorText = nullptr; FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, errNumber, 0, reinterpret_cast<LPWSTR>(&errorText), // output 0, // minimum size for output buffer nullptr); if (errorText) { ON_BLOCK_EXIT([&errorText] { LocalFree(errorText); }); std::string utf8ErrorText = toUtf8String(errorText); auto size = utf8ErrorText.find_first_of("\r\n"); if (size == std::string::npos) { // not found size = utf8ErrorText.length(); } if (size >= kBuflen) { size = kBuflen - 1; } memcpy(buf, utf8ErrorText.c_str(), size); buf[size] = '\0'; msg = buf; } else if (strerror_s(buf, kBuflen, errNumber) != 0) { msg = buf; } #else /* XSI strerror_r */ if (strerror_r(errNumber, buf, kBuflen) == 0) { msg = buf; } #endif if (!msg) { return str::stream() << kUnknownMsg << errNumber; } return {msg}; }
StatusWith<std::vector<PerfCounterCollector::CounterInfo>> PerfCounterCollector::addCounters( StringData path) { std::wstring pathWide = toNativeString(path.toString().c_str()); DWORD pathListLength = 0; PDH_STATUS status = PdhExpandCounterPathW(pathWide.c_str(), nullptr, &pathListLength); if (status != PDH_MORE_DATA) { return {ErrorCodes::WindowsPdhError, str::stream() << formatFunctionCallError("PdhExpandCounterPathW", status) << " for counter '" << path << "'"}; } auto buf = stdx::make_unique<wchar_t[]>(pathListLength); status = PdhExpandCounterPathW(pathWide.c_str(), buf.get(), &pathListLength); if (status != ERROR_SUCCESS) { return {ErrorCodes::WindowsPdhError, formatFunctionCallError("PdhExpandCounterPathW", status)}; } std::vector<CounterInfo> counters; // Windows' PdhExpandWildCardPathW returns a nullptr terminated array of nullptr separated // strings. std::vector<std::string> counterNames; const wchar_t* ptr = buf.get(); while (ptr && *ptr) { counterNames.emplace_back(toUtf8String(ptr)); ptr += wcslen(ptr) + 1; } // Sort to ensure we have a predictable ordering in the final BSON std::sort(counterNames.begin(), counterNames.end()); for (const auto& name : counterNames) { auto swCounterInfo = addCounter(name); if (!swCounterInfo.isOK()) { return swCounterInfo.getStatus(); } counters.emplace_back(std::move(swCounterInfo.getValue())); } return {std::move(counters)}; }
StatusWith<std::unique_ptr<SharedLibrary>> SharedLibrary::create( const boost::filesystem::path& full_path) { LOG(1) << "Loading library: " << toUtf8String(full_path.c_str()); HMODULE handle = LoadLibraryW(full_path.c_str()); if (handle == nullptr) { return StatusWith<std::unique_ptr<SharedLibrary>>( ErrorCodes::InternalError, str::stream() << "Load library failed: " << errnoWithDescription()); } return StatusWith<std::unique_ptr<SharedLibrary>>( std::unique_ptr<SharedLibrary>(new SharedLibrary(handle))); }
/* create a process dump. To use, load up windbg. Set your symbol and source path. Open the crash dump file. To see the crashing context, use .ecxr */ void doMinidump(struct _EXCEPTION_POINTERS* exceptionInfo) { LPCWSTR dumpFilename = L"mongo.dmp"; HANDLE hFile = CreateFileW(dumpFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if ( INVALID_HANDLE_VALUE == hFile ) { DWORD lasterr = GetLastError(); log() << "failed to open minidump file " << toUtf8String(dumpFilename) << " : " << errnoWithDescription( lasterr ) << std::endl; return; } MINIDUMP_EXCEPTION_INFORMATION aMiniDumpInfo; aMiniDumpInfo.ThreadId = GetCurrentThreadId(); aMiniDumpInfo.ExceptionPointers = exceptionInfo; aMiniDumpInfo.ClientPointers = TRUE; log() << "writing minidump diagnostic file " << toUtf8String(dumpFilename) << std::endl; BOOL bstatus = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &aMiniDumpInfo, NULL, NULL); if ( FALSE == bstatus ) { DWORD lasterr = GetLastError(); log() << "failed to create minidump : " << errnoWithDescription( lasterr ) << std::endl; } CloseHandle(hFile); }
string errnoWithDescription(int x) { #if defined(_WIN32) if( x < 0 ) x = GetLastError(); #else if( x < 0 ) x = errno; #endif stringstream s; s << "errno:" << x << ' '; #if defined(_WIN32) LPWSTR errorText = NULL; FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_IGNORE_INSERTS, NULL, x, 0, reinterpret_cast<LPWSTR>( &errorText ), // output 0, // minimum size for output buffer NULL); if( errorText ) { string x = toUtf8String(errorText); for( string::iterator i = x.begin(); i != x.end(); i++ ) { if( *i == '\n' || *i == '\r' ) break; s << *i; } LocalFree(errorText); } else s << strerror(x); /* DWORD n = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, x, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); */ #else s << strerror(x); #endif return s.str(); }
WindowsCommandLine::WindowsCommandLine( int argc, wchar_t* argvW[] ) { vector < string > utf8args; vector < size_t > utf8argLength; size_t blockSize = argc * sizeof( char * ); size_t blockPtr = blockSize; for ( int i = 0; i < argc; ++i ) { utf8args.push_back( toUtf8String( argvW[ i ] ) ); size_t argLength = utf8args[ i ].length() + 1; utf8argLength.push_back( argLength ); blockSize += argLength; } _argv = reinterpret_cast< char** >( malloc( blockSize ) ); for ( int i = 0; i < argc; ++i ) { _argv[ i ] = reinterpret_cast< char * >( _argv ) + blockPtr; strcpy_s( _argv[ i ], utf8argLength[ i ], utf8args[ i ].c_str() ); blockPtr += utf8argLength[ i ]; } }
int StringConverter::toUtf8(const UnicodeString& str, char* buffer, int bufferSize, bool nullTerminated) { std::string utf8Str = toUtf8String(str); // we want byte count, not real character count here, so length() is okay int ret = utf8Str.length(); if (ret < bufferSize) { memcpy(buffer, utf8Str.c_str(), ret); } else { return -1; } if (!nullTerminated) { return ret; } else { if (ret+1 < bufferSize) { buffer[ret++] = 0; return ret; } else { return -1; } } }
bool ServiceController::installService( const std::wstring& serviceName, const std::wstring& displayName, const std::wstring& serviceDesc, const std::wstring& serviceUser, const std::wstring& servicePassword, const std::string dbpath, int argc, char* argv[] ) { assert(argc >= 1); stringstream commandLine; if ( strchr(argv[0], ':') ) { // a crude test for fully qualified path commandLine << '"' << argv[0] << "\" "; } else { char buffer[256]; assert( _getcwd(buffer, 256) ); commandLine << '"' << buffer << '\\' << argv[0] << "\" "; } for ( int i = 1; i < argc; i++ ) { std::string arg( argv[ i ] ); // replace install command to indicate process is being started as a service if ( arg == "--install" || arg == "--reinstall" ) { arg = "--service"; } else if ( arg == "--dbpath" && i + 1 < argc ) { commandLine << arg << " \"" << dbpath << "\" "; i++; continue; } else if ( arg == "--logpath" && i + 1 < argc ) { commandLine << arg << " \"" << argv[i+1] << "\" "; i++; continue; } else if ( arg.length() > 9 && arg.substr(0, 9) == "--service" ) { // Strip off --service(Name|User|Password) arguments i++; continue; } commandLine << arg << " "; } SC_HANDLE schSCManager = ::OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if ( schSCManager == NULL ) { DWORD err = ::GetLastError(); cerr << "Error connecting to the Service Control Manager: " << GetWinErrMsg(err) << endl; return false; } // Make sure servise doesn't already exist. // TODO: Check to see if service is in "Deleting" status, suggest the user close down Services MMC snap-ins. SC_HANDLE schService = ::OpenService( schSCManager, serviceName.c_str(), SERVICE_ALL_ACCESS ); if ( schService != NULL ) { cerr << "There is already a service named " << toUtf8String(serviceName) << ". Aborting" << endl; ::CloseServiceHandle( schService ); ::CloseServiceHandle( schSCManager ); return false; } std::basic_ostringstream< TCHAR > commandLineWide; commandLineWide << commandLine.str().c_str(); cerr << "Creating service " << toUtf8String(serviceName) << "." << endl; // create new service schService = ::CreateService( schSCManager, serviceName.c_str(), displayName.c_str(), SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, commandLineWide.str().c_str(), NULL, NULL, L"\0\0", NULL, NULL ); if ( schService == NULL ) { DWORD err = ::GetLastError(); cerr << "Error creating service: " << GetWinErrMsg(err) << endl; ::CloseServiceHandle( schSCManager ); return false; } cerr << "Service creation successful." << endl; cerr << "Service can be started from the command line via 'net start \"" << toUtf8String(serviceName) << "\"'." << endl; bool serviceInstalled; // TODO: If neccessary grant user "Login as a Service" permission. if ( !serviceUser.empty() ) { std::wstring actualServiceUser; if ( serviceUser.find(L"\\") == string::npos ) { actualServiceUser = L".\\" + serviceUser; } else { actualServiceUser = serviceUser; } cerr << "Setting service login credentials. User: "******"Setting service login failed. Service has 'LocalService' permissions." << endl; } } // set the service description SERVICE_DESCRIPTION serviceDescription; serviceDescription.lpDescription = (LPTSTR)serviceDesc.c_str(); serviceInstalled = ::ChangeServiceConfig2( schService, SERVICE_CONFIG_DESCRIPTION, &serviceDescription ); if ( serviceInstalled ) { SC_ACTION aActions[ 3 ] = { { SC_ACTION_RESTART, 0 }, { SC_ACTION_RESTART, 0 }, { SC_ACTION_RESTART, 0 } }; SERVICE_FAILURE_ACTIONS serviceFailure; ZeroMemory( &serviceFailure, sizeof( SERVICE_FAILURE_ACTIONS ) ); serviceFailure.cActions = 3; serviceFailure.lpsaActions = aActions; // set service recovery options serviceInstalled = ::ChangeServiceConfig2( schService, SERVICE_CONFIG_FAILURE_ACTIONS, &serviceFailure ); } else { cerr << "Could not set service description. Check the event log for more details." << endl; } ::CloseServiceHandle( schService ); ::CloseServiceHandle( schSCManager ); return serviceInstalled; }
StatusWith<PerfCounterCollector::CounterInfo> PerfCounterCollector::addCounter(StringData path) { PDH_HCOUNTER counter{0}; PDH_STATUS status = PdhAddCounterW(_query, toNativeString(path.toString().c_str()).c_str(), NULL, &counter); if (status != ERROR_SUCCESS) { return {ErrorCodes::WindowsPdhError, formatFunctionCallError("PdhAddCounterW", status)}; } DWORD bufferSize = 0; status = PdhGetCounterInfoW(counter, false, &bufferSize, nullptr); if (status != PDH_MORE_DATA) { return {ErrorCodes::WindowsPdhError, formatFunctionCallError("PdhGetCounterInfoW", status)}; } auto buf = stdx::make_unique<char[]>(bufferSize); auto counterInfo = reinterpret_cast<PPDH_COUNTER_INFO>(buf.get()); status = PdhGetCounterInfoW(counter, false, &bufferSize, counterInfo); if (status != ERROR_SUCCESS) { return {ErrorCodes::WindowsPdhError, formatFunctionCallError("PdhGetCounterInfoW", status)}; } // A full qualified path is as such: // "\\MYMACHINE\\Processor(0)\\% Idle Time" // MachineName \\ Object Name (Instance Name) \\ CounterName // Ex: // MachineName: MYMACHINE // Object Name: Processor // InstanceName: 0 // CounterName: % Idle Time // We do not want to use Machine Name, but sometimes we want InstanceName // std::string firstName = str::stream() << '\\' << toUtf8String(counterInfo->szObjectName) << '\\' << toUtf8String(counterInfo->szCounterName); // Compute a second name std::string secondName(firstName); bool hasSecondValue = false; // Only include base for counters that need it if ((counterInfo->dwType & PERF_COUNTER_PRECISION) == PERF_COUNTER_PRECISION) { secondName += " Base"; hasSecondValue = true; } // InstanceName is null for counters without instance names return {CounterInfo{std::move(firstName), std::move(secondName), hasSecondValue, counterInfo->szInstanceName ? toUtf8String(counterInfo->szInstanceName) : std::string(), counterInfo->dwType, counter}}; }
ProgramRunner::ProgramRunner(const BSONObj& args, const BSONObj& env) { uassert(ErrorCodes::FailedToParse, "cannot pass an empty argument to ProgramRunner", !args.isEmpty()); string program(args.firstElement().valuestrsafe()); uassert(ErrorCodes::FailedToParse, "invalid program name passed to ProgramRunner", !program.empty()); boost::filesystem::path programPath = findProgram(program); boost::filesystem::path programName = programPath.stem(); string prefix("mongod-"); bool isMongodProgram = string("mongod") == programName || programName.string().compare(0, prefix.size(), prefix) == 0; prefix = "mongos-"; bool isMongosProgram = string("mongos") == programName || programName.string().compare(0, prefix.size(), prefix) == 0; if (isMongodProgram) { _name = "d"; } else if (isMongosProgram) { _name = "s"; } else if (programName == "mongobridge") { _name = "b"; } else { _name = "sh"; } _argv.push_back(programPath.string()); _port = -1; // Parse individual arguments into _argv 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); } else if (isMongodProgram && str == "--configsvr") { _name = "c"; } _argv.push_back(str); } // Load explicitly set environment key value pairs into _envp. for (const BSONElement& e : env) { // Environment variable values must be strings verify(e.type() == mongo::String); _envp.emplace(std::string(e.fieldName()), std::string(e.valuestr())); } // Import this process' environment into _envp, for all keys that have not already been set. // We need to do this so that the child process has all the PATH and locale variables, unless // we explicitly override them. #ifdef _WIN32 wchar_t* processEnv = GetEnvironmentStringsW(); ON_BLOCK_EXIT( [](wchar_t* toFree) { if (toFree) FreeEnvironmentStringsW(toFree); }, processEnv); // Windows' GetEnvironmentStringsW returns a NULL terminated array of NULL separated // <key>=<value> pairs. while (processEnv && *processEnv) { std::wstring envKeyValue(processEnv); size_t splitPoint = envKeyValue.find('='); invariant(splitPoint != std::wstring::npos); std::string envKey = toUtf8String(envKeyValue.substr(0, splitPoint)); std::string envValue = toUtf8String(envKeyValue.substr(splitPoint + 1)); _envp.emplace(std::move(envKey), std::move(envValue)); processEnv += envKeyValue.size() + 1; } #else // environ is a POSIX defined array of char*s. Each char* in the array is a <key>=<value>\0 // pair. char** environEntry = environ; while (*environEntry) { std::string envKeyValue(*environEntry); size_t splitPoint = envKeyValue.find('='); invariant(splitPoint != std::string::npos); std::string envKey = envKeyValue.substr(0, splitPoint); std::string envValue = envKeyValue.substr(splitPoint + 1); _envp.emplace(std::move(envKey), std::move(envValue)); ++environEntry; } #endif bool needsPort = isMongodProgram || isMongosProgram || (programName == "mongobridge"); if (!needsPort) { _port = -1; } uassert(ErrorCodes::FailedToParse, str::stream() << "a port number is expected when running " << program << " from the shell", !needsPort || _port >= 0); uassert(ErrorCodes::BadValue, str::stream() << "can't start " << program << ", port " << _port << " already in use", _port < 0 || !registry.isPortRegistered(_port)); }
bool ServiceController::installService( const std::wstring& serviceName, const std::wstring& displayName, const std::wstring& serviceDesc, const std::wstring& serviceUser, const std::wstring& servicePassword, const std::string dbpath, int argc, char* argv[] ) { assert(argc >= 1); stringstream commandLine; char exePath[1024]; GetModuleFileNameA( NULL, exePath, sizeof exePath ); commandLine << '"' << exePath << "\" "; for ( int i = 1; i < argc; i++ ) { std::string arg( argv[ i ] ); // replace install command to indicate process is being started as a service if ( arg == "--install" || arg == "--reinstall" ) { arg = "--service"; } else if ( arg == "--dbpath" && i + 1 < argc ) { commandLine << arg << " \"" << dbpath << "\" "; i++; continue; } else if ( arg == "--logpath" && i + 1 < argc ) { commandLine << arg << " \"" << argv[i+1] << "\" "; i++; continue; } else if ( arg == "-f" && i + 1 < argc ) { commandLine << arg << " \"" << argv[i+1] << "\" "; i++; continue; } else if ( arg == "--config" && i + 1 < argc ) { commandLine << arg << " \"" << argv[i+1] << "\" "; i++; continue; } else if ( arg == "--pidfilepath" && i + 1 < argc ) { commandLine << arg << " \"" << argv[i+1] << "\" "; i++; continue; } else if ( arg == "--repairpath" && i + 1 < argc ) { commandLine << arg << " \"" << argv[i+1] << "\" "; i++; continue; } else if ( arg == "--keyfile" && i + 1 < argc ) { commandLine << arg << " \"" << argv[i+1] << "\" "; i++; continue; } else if ( arg.length() > 9 && arg.substr(0, 9) == "--service" ) { // Strip off --service(Name|User|Password) arguments i++; continue; } commandLine << arg << " "; } SC_HANDLE schSCManager = ::OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if ( schSCManager == NULL ) { DWORD err = ::GetLastError(); cerr << "Error connecting to the Service Control Manager: " << GetWinErrMsg(err) << endl; return false; } // Make sure servise doesn't already exist. // TODO: Check to see if service is in "Deleting" status, suggest the user close down Services MMC snap-ins. SC_HANDLE schService = ::OpenService( schSCManager, serviceName.c_str(), SERVICE_ALL_ACCESS ); if ( schService != NULL ) { cerr << "There is already a service named " << toUtf8String(serviceName) << ". Aborting" << endl; ::CloseServiceHandle( schService ); ::CloseServiceHandle( schSCManager ); return false; } std::basic_ostringstream< TCHAR > commandLineWide; commandLineWide << commandLine.str().c_str(); cerr << "Creating service " << toUtf8String(serviceName) << "." << endl; // create new service schService = ::CreateService( schSCManager, serviceName.c_str(), displayName.c_str(), SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, commandLineWide.str().c_str(), NULL, NULL, L"\0\0", NULL, NULL ); if ( schService == NULL ) { DWORD err = ::GetLastError(); cerr << "Error creating service: " << GetWinErrMsg(err) << endl; ::CloseServiceHandle( schSCManager ); return false; } cerr << "Service creation successful." << endl; cerr << "Service can be started from the command line via 'net start \"" << toUtf8String(serviceName) << "\"'." << endl; bool serviceInstalled; // TODO: If neccessary grant user "Login as a Service" permission. if ( !serviceUser.empty() ) { std::wstring actualServiceUser; if ( serviceUser.find(L"\\") == string::npos ) { actualServiceUser = L".\\" + serviceUser; } else { actualServiceUser = serviceUser; } cerr << "Setting service login credentials. User: "******"Setting service login failed. Service has 'LocalService' permissions." << endl; } } // set the service description SERVICE_DESCRIPTION serviceDescription; serviceDescription.lpDescription = (LPTSTR)serviceDesc.c_str(); serviceInstalled = ::ChangeServiceConfig2( schService, SERVICE_CONFIG_DESCRIPTION, &serviceDescription ); #if 1 if ( ! serviceInstalled ) { #else // This code sets the mongod service to auto-restart, forever. // This might be a fine thing to do except that when mongod or Windows has a crash, the mongo.lock // file is still around, so any attempt at a restart will immediately fail. With auto-restart, we // go into a loop, crashing and restarting, crashing and restarting, until someone comes in and // disables the service or deletes the mongod.lock file. // // I'm leaving the old code here for now in case we solve this and are able to turn SC_ACTION_RESTART // back on. // if ( serviceInstalled ) { SC_ACTION aActions[ 3 ] = { { SC_ACTION_RESTART, 0 }, { SC_ACTION_RESTART, 0 }, { SC_ACTION_RESTART, 0 } }; SERVICE_FAILURE_ACTIONS serviceFailure; ZeroMemory( &serviceFailure, sizeof( SERVICE_FAILURE_ACTIONS ) ); serviceFailure.cActions = 3; serviceFailure.lpsaActions = aActions; // set service recovery options serviceInstalled = ::ChangeServiceConfig2( schService, SERVICE_CONFIG_FAILURE_ACTIONS, &serviceFailure ); } else { #endif cerr << "Could not set service description. Check the event log for more details." << endl; } ::CloseServiceHandle( schService ); ::CloseServiceHandle( schSCManager ); return serviceInstalled; } bool ServiceController::removeService( const std::wstring& serviceName ) { SC_HANDLE schSCManager = ::OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if ( schSCManager == NULL ) { DWORD err = ::GetLastError(); cerr << "Error connecting to the Service Control Manager: " << GetWinErrMsg(err) << endl; return false; } SC_HANDLE schService = ::OpenService( schSCManager, serviceName.c_str(), SERVICE_ALL_ACCESS ); if ( schService == NULL ) { cerr << "Could not find a service named " << toUtf8String(serviceName) << " to uninstall." << endl; ::CloseServiceHandle( schSCManager ); return false; } SERVICE_STATUS serviceStatus; // stop service if its running if ( ::ControlService( schService, SERVICE_CONTROL_STOP, &serviceStatus ) ) { cerr << "Service " << toUtf8String(serviceName) << " is currently running. Stopping service." << endl; while ( ::QueryServiceStatus( schService, &serviceStatus ) ) { if ( serviceStatus.dwCurrentState == SERVICE_STOP_PENDING ) { Sleep( 1000 ); } else { break; } } cerr << "Service stopped." << endl; } cerr << "Deleting service " << toUtf8String(serviceName) << "." << endl; bool serviceRemoved = ::DeleteService( schService ); ::CloseServiceHandle( schService ); ::CloseServiceHandle( schSCManager ); if (serviceRemoved) { cerr << "Service deleted successfully." << endl; } else { cerr << "Failed to delete service." << endl; } return serviceRemoved; }