summaryrefslogtreecommitdiff
path: root/src/mongo/util/ntservice.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/util/ntservice.cpp')
-rw-r--r--src/mongo/util/ntservice.cpp907
1 files changed, 445 insertions, 462 deletions
diff --git a/src/mongo/util/ntservice.cpp b/src/mongo/util/ntservice.cpp
index 41dde9d15c3..a92483be232 100644
--- a/src/mongo/util/ntservice.cpp
+++ b/src/mongo/util/ntservice.cpp
@@ -55,436 +55,423 @@ namespace mongo {
namespace ntservice {
namespace {
- bool _startService = false;
- SERVICE_STATUS_HANDLE _statusHandle = NULL;
- wstring _serviceName;
- ServiceCallback _serviceCallback = NULL;
+bool _startService = false;
+SERVICE_STATUS_HANDLE _statusHandle = NULL;
+wstring _serviceName;
+ServiceCallback _serviceCallback = NULL;
} // namespace
- static void installServiceOrDie(
- const wstring& serviceName,
- const wstring& displayName,
- const wstring& serviceDesc,
- const wstring& serviceUser,
- const wstring& servicePassword,
- const std::vector<std::string>& argv,
- const bool reinstall);
-
- static void removeServiceOrDie(const wstring& serviceName);
-
- bool shouldStartService() {
- return _startService;
- }
-
- static void WINAPI serviceCtrl(DWORD ctrlCode);
-
- void configureService(
- ServiceCallback serviceCallback,
- const moe::Environment& params,
- const NtServiceDefaultStrings& defaultStrings,
- const std::vector<std::string>& disallowedOptions,
- const std::vector<std::string>& argv
- ) {
- bool installService = false;
- bool removeService = false;
- bool reinstallService = false;
-
- _serviceCallback = serviceCallback;
-
- int badOption = -1;
- for (size_t i = 0; i < disallowedOptions.size(); ++i) {
- if (params.count(disallowedOptions[i])) {
- badOption = i;
- break;
- }
+static void installServiceOrDie(const wstring& serviceName,
+ const wstring& displayName,
+ const wstring& serviceDesc,
+ const wstring& serviceUser,
+ const wstring& servicePassword,
+ const std::vector<std::string>& argv,
+ const bool reinstall);
+
+static void removeServiceOrDie(const wstring& serviceName);
+
+bool shouldStartService() {
+ return _startService;
+}
+
+static void WINAPI serviceCtrl(DWORD ctrlCode);
+
+void configureService(ServiceCallback serviceCallback,
+ const moe::Environment& params,
+ const NtServiceDefaultStrings& defaultStrings,
+ const std::vector<std::string>& disallowedOptions,
+ const std::vector<std::string>& argv) {
+ bool installService = false;
+ bool removeService = false;
+ bool reinstallService = false;
+
+ _serviceCallback = serviceCallback;
+
+ int badOption = -1;
+ for (size_t i = 0; i < disallowedOptions.size(); ++i) {
+ if (params.count(disallowedOptions[i])) {
+ badOption = i;
+ break;
}
+ }
- _serviceName = defaultStrings.serviceName;
- wstring windowsServiceDisplayName( defaultStrings.displayName );
- wstring windowsServiceDescription( defaultStrings.serviceDescription );
- wstring windowsServiceUser;
- wstring windowsServicePassword;
+ _serviceName = defaultStrings.serviceName;
+ wstring windowsServiceDisplayName(defaultStrings.displayName);
+ wstring windowsServiceDescription(defaultStrings.serviceDescription);
+ wstring windowsServiceUser;
+ wstring windowsServicePassword;
- if (params.count("install")) {
- if ( badOption != -1 ) {
- log() << "--install cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- if ( !params.count("systemLog.destination") ||
- params["systemLog.destination"].as<std::string>() != "file" ) {
- log() << "--install has to be used with a log file for server output";
- quickExit( EXIT_BADOPTIONS );
- }
- installService = true;
+ if (params.count("install")) {
+ if (badOption != -1) {
+ log() << "--install cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
- if (params.count("reinstall")) {
- if ( badOption != -1 ) {
- log() << "--reinstall cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- if ( !params.count("systemLog.destination") ||
- params["systemLog.destination"].as<std::string>() != "file" ) {
- log() << "--reinstall has to be used with a log file for server output";
- quickExit( EXIT_BADOPTIONS );
- }
- reinstallService = true;
+ if (!params.count("systemLog.destination") ||
+ params["systemLog.destination"].as<std::string>() != "file") {
+ log() << "--install has to be used with a log file for server output";
+ quickExit(EXIT_BADOPTIONS);
}
- if (params.count("remove")) {
- if ( badOption != -1 ) {
- log() << "--remove cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- removeService = true;
+ installService = true;
+ }
+ if (params.count("reinstall")) {
+ if (badOption != -1) {
+ log() << "--reinstall cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
- if (params.count("service")) {
- if ( badOption != -1 ) {
- log() << "--service cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- _startService = true;
+ if (!params.count("systemLog.destination") ||
+ params["systemLog.destination"].as<std::string>() != "file") {
+ log() << "--reinstall has to be used with a log file for server output";
+ quickExit(EXIT_BADOPTIONS);
+ }
+ reinstallService = true;
+ }
+ if (params.count("remove")) {
+ if (badOption != -1) {
+ log() << "--remove cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
+ }
+ removeService = true;
+ }
+ if (params.count("service")) {
+ if (badOption != -1) {
+ log() << "--service cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
+ _startService = true;
+ }
- if (params.count("processManagement.windowsService.serviceName")) {
- if ( badOption != -1 ) {
- log() << "--serviceName cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- _serviceName = toWideString(
- params[ "processManagement.windowsService.serviceName" ].as<string>().c_str() );
+ if (params.count("processManagement.windowsService.serviceName")) {
+ if (badOption != -1) {
+ log() << "--serviceName cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
- if (params.count("processManagement.windowsService.displayName")) {
- if ( badOption != -1 ) {
- log() << "--serviceDisplayName cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- windowsServiceDisplayName = toWideString(
- params[ "processManagement.windowsService.displayName" ].as<string>().c_str() );
+ _serviceName = toWideString(
+ params["processManagement.windowsService.serviceName"].as<string>().c_str());
+ }
+ if (params.count("processManagement.windowsService.displayName")) {
+ if (badOption != -1) {
+ log() << "--serviceDisplayName cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
- if (params.count("processManagement.windowsService.description")) {
- if ( badOption != -1 ) {
- log() << "--serviceDescription cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- windowsServiceDescription = toWideString(
- params[ "processManagement.windowsService.description" ].as<string>().c_str() );
+ windowsServiceDisplayName = toWideString(
+ params["processManagement.windowsService.displayName"].as<string>().c_str());
+ }
+ if (params.count("processManagement.windowsService.description")) {
+ if (badOption != -1) {
+ log() << "--serviceDescription cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
- if (params.count("processManagement.windowsService.serviceUser")) {
- if ( badOption != -1 ) {
- log() << "--serviceUser cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- windowsServiceUser = toWideString(
- params[ "processManagement.windowsService.serviceUser" ].as<string>().c_str() );
+ windowsServiceDescription = toWideString(
+ params["processManagement.windowsService.description"].as<string>().c_str());
+ }
+ if (params.count("processManagement.windowsService.serviceUser")) {
+ if (badOption != -1) {
+ log() << "--serviceUser cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
- if (params.count("processManagement.windowsService.servicePassword")) {
- if ( badOption != -1 ) {
- log() << "--servicePassword cannot be used with --" << disallowedOptions[badOption];
- quickExit( EXIT_BADOPTIONS );
- }
- windowsServicePassword = toWideString(
- params[ "processManagement.windowsService.servicePassword"
- ].as<string>().c_str() );
+ windowsServiceUser = toWideString(
+ params["processManagement.windowsService.serviceUser"].as<string>().c_str());
+ }
+ if (params.count("processManagement.windowsService.servicePassword")) {
+ if (badOption != -1) {
+ log() << "--servicePassword cannot be used with --" << disallowedOptions[badOption];
+ quickExit(EXIT_BADOPTIONS);
}
+ windowsServicePassword = toWideString(
+ params["processManagement.windowsService.servicePassword"].as<string>().c_str());
+ }
- if ( installService || reinstallService ) {
- if ( reinstallService ) {
- removeServiceOrDie(_serviceName);
- }
-
- installServiceOrDie(
- _serviceName,
- windowsServiceDisplayName,
- windowsServiceDescription,
- windowsServiceUser,
- windowsServicePassword,
- argv,
- reinstallService);
- quickExit(EXIT_CLEAN);
- }
- else if ( removeService ) {
+ if (installService || reinstallService) {
+ if (reinstallService) {
removeServiceOrDie(_serviceName);
- quickExit( EXIT_CLEAN );
}
- }
- // This implementation assumes that inputArgv was a valid argv to mongod. That is, it assumes
- // that options that take arguments received them, and options that do not take arguments did
- // not.
- std::vector<std::string> constructServiceArgv(const std::vector<std::string>& inputArgv) {
-
- static const char*const optionsWithoutArgumentsToStrip[] = {
- "-install", "--install",
- "-reinstall", "--reinstall",
- "-service", "--service"
- };
-
- // Pointer to just past the end of optionsWithoutArgumentsToStrip, for use as an "end"
- // iterator.
- static const char*const *const optionsWithoutArgumentsToStripEnd =
- optionsWithoutArgumentsToStrip + boost::size(optionsWithoutArgumentsToStrip);
-
- static const char*const optionsWithArgumentsToStrip[] = {
- "-serviceName", "--serviceName",
- "-serviceUser", "--serviceUser",
- "-servicePassword", "--servicePassword",
- "-serviceDescription", "--serviceDescription",
- "-serviceDisplayName", "--serviceDisplayName"
- };
-
- // Pointer to just past the end of optionsWithArgumentsToStrip, for use as an "end"
- // iterator.
- static const char*const *const optionsWithArgumentsToStripEnd =
- optionsWithArgumentsToStrip + boost::size(optionsWithArgumentsToStrip);
-
- std::vector<std::string> result;
- for (std::vector<std::string>::const_iterator iter = inputArgv.begin(),
- end = inputArgv.end(); iter != end; ++iter) {
-
- if (optionsWithoutArgumentsToStripEnd != std::find(optionsWithoutArgumentsToStrip,
- optionsWithoutArgumentsToStripEnd,
- *iter)) {
- // The current element of inputArgv is an option that we wish to strip, that takes
- // no arguments. Skip adding it to "result".
- continue;
- }
+ installServiceOrDie(_serviceName,
+ windowsServiceDisplayName,
+ windowsServiceDescription,
+ windowsServiceUser,
+ windowsServicePassword,
+ argv,
+ reinstallService);
+ quickExit(EXIT_CLEAN);
+ } else if (removeService) {
+ removeServiceOrDie(_serviceName);
+ quickExit(EXIT_CLEAN);
+ }
+}
+
+// This implementation assumes that inputArgv was a valid argv to mongod. That is, it assumes
+// that options that take arguments received them, and options that do not take arguments did
+// not.
+std::vector<std::string> constructServiceArgv(const std::vector<std::string>& inputArgv) {
+ static const char* const optionsWithoutArgumentsToStrip[] = {
+ "-install", "--install", "-reinstall", "--reinstall", "-service", "--service"};
+
+ // Pointer to just past the end of optionsWithoutArgumentsToStrip, for use as an "end"
+ // iterator.
+ static const char* const* const optionsWithoutArgumentsToStripEnd =
+ optionsWithoutArgumentsToStrip + boost::size(optionsWithoutArgumentsToStrip);
+
+ static const char* const optionsWithArgumentsToStrip[] = {"-serviceName",
+ "--serviceName",
+ "-serviceUser",
+ "--serviceUser",
+ "-servicePassword",
+ "--servicePassword",
+ "-serviceDescription",
+ "--serviceDescription",
+ "-serviceDisplayName",
+ "--serviceDisplayName"};
+
+ // Pointer to just past the end of optionsWithArgumentsToStrip, for use as an "end"
+ // iterator.
+ static const char* const* const optionsWithArgumentsToStripEnd =
+ optionsWithArgumentsToStrip + boost::size(optionsWithArgumentsToStrip);
+
+ std::vector<std::string> result;
+ for (std::vector<std::string>::const_iterator iter = inputArgv.begin(), end = inputArgv.end();
+ iter != end;
+ ++iter) {
+ if (optionsWithoutArgumentsToStripEnd !=
+ std::find(optionsWithoutArgumentsToStrip, optionsWithoutArgumentsToStripEnd, *iter)) {
+ // The current element of inputArgv is an option that we wish to strip, that takes
+ // no arguments. Skip adding it to "result".
+ continue;
+ }
- std::string name;
- std::string value;
- bool foundEqualSign = mongoutils::str::splitOn(*iter, '=', name, value);
- if (!foundEqualSign)
- name = *iter;
- if (optionsWithArgumentsToStripEnd != std::find(optionsWithArgumentsToStrip,
- optionsWithArgumentsToStripEnd,
- name)) {
- // The current element, and maybe the next one, form an option and its argument.
- // Skip adding them to "result".
- if (!foundEqualSign) {
- // The next argv value must be the argument to the parameter, so strip it.
- ++iter;
- }
- continue;
+ std::string name;
+ std::string value;
+ bool foundEqualSign = mongoutils::str::splitOn(*iter, '=', name, value);
+ if (!foundEqualSign)
+ name = *iter;
+ if (optionsWithArgumentsToStripEnd !=
+ std::find(optionsWithArgumentsToStrip, optionsWithArgumentsToStripEnd, name)) {
+ // The current element, and maybe the next one, form an option and its argument.
+ // Skip adding them to "result".
+ if (!foundEqualSign) {
+ // The next argv value must be the argument to the parameter, so strip it.
+ ++iter;
}
-
- result.push_back(*iter);
+ continue;
}
- result.push_back("--service"); // Service command lines all contain "--service".
- return result;
+ result.push_back(*iter);
}
- void installServiceOrDie(
- const wstring& serviceName,
- const wstring& displayName,
- const wstring& serviceDesc,
- const wstring& serviceUser,
- const wstring& servicePassword,
- const std::vector<std::string>& argv,
- const bool reinstall
- ) {
- log() << "Trying to install Windows service '" << toUtf8String(serviceName) << "'";
-
- std::vector<std::string> serviceArgv = constructServiceArgv(argv);
-
- char exePath[1024];
- GetModuleFileNameA( NULL, exePath, sizeof exePath );
- serviceArgv.at(0) = exePath;
-
- std::string commandLine = constructUtf8WindowsCommandLine(serviceArgv);
-
- SC_HANDLE schSCManager = ::OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
- if ( schSCManager == NULL ) {
- DWORD err = ::GetLastError();
- log() << "Error connecting to the Service Control Manager: " << GetWinErrMsg(err);
- quickExit(EXIT_NTSERVICE_ERROR);
- }
+ result.push_back("--service"); // Service command lines all contain "--service".
+ return result;
+}
- SC_HANDLE schService = NULL;
- int retryCount = 10;
+void installServiceOrDie(const wstring& serviceName,
+ const wstring& displayName,
+ const wstring& serviceDesc,
+ const wstring& serviceUser,
+ const wstring& servicePassword,
+ const std::vector<std::string>& argv,
+ const bool reinstall) {
+ log() << "Trying to install Windows service '" << toUtf8String(serviceName) << "'";
- while (true) {
+ std::vector<std::string> serviceArgv = constructServiceArgv(argv);
- // Make sure service doesn't already exist.
- // TODO: Check to see if service is in "Deleting" status, suggest the user close down Services MMC snap-ins.
- schService = ::OpenService( schSCManager, serviceName.c_str(), SERVICE_ALL_ACCESS );
- if ( schService != NULL) {
- log() << "There is already a service named '" << toUtf8String(serviceName) <<
- (retryCount > 0 ? "', sleeping and retrying" : "', aborting");
- ::CloseServiceHandle( schService );
+ char exePath[1024];
+ GetModuleFileNameA(NULL, exePath, sizeof exePath);
+ serviceArgv.at(0) = exePath;
- // If we are reinstalling the service, but SCM thinks it is installed, then wait
- // and try again
- if(--retryCount > 0 && reinstall) {
- sleepmillis(500);
- continue;
- }
+ std::string commandLine = constructUtf8WindowsCommandLine(serviceArgv);
- ::CloseServiceHandle( schSCManager );
- quickExit(EXIT_NTSERVICE_ERROR);
- }
- else {
- break;
+ SC_HANDLE schSCManager = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ if (schSCManager == NULL) {
+ DWORD err = ::GetLastError();
+ log() << "Error connecting to the Service Control Manager: " << GetWinErrMsg(err);
+ quickExit(EXIT_NTSERVICE_ERROR);
+ }
+
+ SC_HANDLE schService = NULL;
+ int retryCount = 10;
+
+ while (true) {
+ // Make sure service doesn't already exist.
+ // TODO: Check to see if service is in "Deleting" status, suggest the user close down Services MMC snap-ins.
+ schService = ::OpenService(schSCManager, serviceName.c_str(), SERVICE_ALL_ACCESS);
+ if (schService != NULL) {
+ log() << "There is already a service named '" << toUtf8String(serviceName)
+ << (retryCount > 0 ? "', sleeping and retrying" : "', aborting");
+ ::CloseServiceHandle(schService);
+
+ // If we are reinstalling the service, but SCM thinks it is installed, then wait
+ // and try again
+ if (--retryCount > 0 && reinstall) {
+ sleepmillis(500);
+ continue;
}
- }
- std::wstring commandLineWide = toWideString(commandLine.c_str());
-
- // create new service
- schService = ::CreateServiceW(
- schSCManager, // Service Control Manager handle
- serviceName.c_str(), // service name
- displayName.c_str(), // service display name
- SERVICE_ALL_ACCESS, // desired access
- SERVICE_WIN32_OWN_PROCESS, // service type
- SERVICE_AUTO_START, // start type
- SERVICE_ERROR_NORMAL, // error control
- commandLineWide.c_str(), // command line
- NULL, // load order group
- NULL, // tag id
- L"\0\0", // dependencies
- NULL, // user account
- NULL ); // user account password
- if ( schService == NULL ) {
- DWORD err = ::GetLastError();
- log() << "Error creating service: " << GetWinErrMsg(err);
- ::CloseServiceHandle( schSCManager );
- quickExit( EXIT_NTSERVICE_ERROR );
+ ::CloseServiceHandle(schSCManager);
+ quickExit(EXIT_NTSERVICE_ERROR);
+ } else {
+ break;
}
+ }
- log() << "Service '" << toUtf8String(serviceName) << "' (" << toUtf8String(displayName) <<
- ") installed with command line '" << commandLine << "'";
- string typeableName( ( serviceName.find(L' ') != wstring::npos ) ?
- "\"" + toUtf8String(serviceName) + "\"" :
- toUtf8String(serviceName) );
- log() << "Service can be started from the command line with 'net start " << typeableName << "'";
-
- bool serviceInstalled;
+ std::wstring commandLineWide = toWideString(commandLine.c_str());
+
+ // create new service
+ schService = ::CreateServiceW(schSCManager, // Service Control Manager handle
+ serviceName.c_str(), // service name
+ displayName.c_str(), // service display name
+ SERVICE_ALL_ACCESS, // desired access
+ SERVICE_WIN32_OWN_PROCESS, // service type
+ SERVICE_AUTO_START, // start type
+ SERVICE_ERROR_NORMAL, // error control
+ commandLineWide.c_str(), // command line
+ NULL, // load order group
+ NULL, // tag id
+ L"\0\0", // dependencies
+ NULL, // user account
+ NULL); // user account password
+ if (schService == NULL) {
+ DWORD err = ::GetLastError();
+ log() << "Error creating service: " << GetWinErrMsg(err);
+ ::CloseServiceHandle(schSCManager);
+ quickExit(EXIT_NTSERVICE_ERROR);
+ }
- // TODO: If necessary grant user "Login as a Service" permission.
- if ( !serviceUser.empty() ) {
- wstring actualServiceUser;
- if ( serviceUser.find(L"\\") == string::npos ) {
- actualServiceUser = L".\\" + serviceUser;
- }
- else {
- actualServiceUser = serviceUser;
- }
+ log() << "Service '" << toUtf8String(serviceName) << "' (" << toUtf8String(displayName)
+ << ") installed with command line '" << commandLine << "'";
+ string typeableName((serviceName.find(L' ') != wstring::npos)
+ ? "\"" + toUtf8String(serviceName) + "\""
+ : toUtf8String(serviceName));
+ log() << "Service can be started from the command line with 'net start " << typeableName << "'";
+
+ bool serviceInstalled;
+
+ // TODO: If necessary grant user "Login as a Service" permission.
+ if (!serviceUser.empty()) {
+ wstring actualServiceUser;
+ if (serviceUser.find(L"\\") == string::npos) {
+ actualServiceUser = L".\\" + serviceUser;
+ } else {
+ actualServiceUser = serviceUser;
+ }
- log() << "Setting service login credentials for user: " << toUtf8String(actualServiceUser);
- serviceInstalled = ::ChangeServiceConfig(
- schService, // service handle
- SERVICE_NO_CHANGE, // service type
- SERVICE_NO_CHANGE, // start type
- SERVICE_NO_CHANGE, // error control
- NULL, // path
- NULL, // load order group
- NULL, // tag id
- NULL, // dependencies
- actualServiceUser.c_str(), // user account
- servicePassword.c_str(), // user account password
- NULL ); // service display name
- if ( !serviceInstalled ) {
- log() << "Setting service login failed, service has 'LocalService' permissions";
- }
+ log() << "Setting service login credentials for user: " << toUtf8String(actualServiceUser);
+ serviceInstalled = ::ChangeServiceConfig(schService, // service handle
+ SERVICE_NO_CHANGE, // service type
+ SERVICE_NO_CHANGE, // start type
+ SERVICE_NO_CHANGE, // error control
+ NULL, // path
+ NULL, // load order group
+ NULL, // tag id
+ NULL, // dependencies
+ actualServiceUser.c_str(), // user account
+ servicePassword.c_str(), // user account password
+ NULL); // service display name
+ if (!serviceInstalled) {
+ log() << "Setting service login failed, service has 'LocalService' permissions";
}
+ }
- // set the service description
- SERVICE_DESCRIPTION serviceDescription;
- serviceDescription.lpDescription = (LPTSTR)serviceDesc.c_str();
- serviceInstalled = ::ChangeServiceConfig2( schService, SERVICE_CONFIG_DESCRIPTION, &serviceDescription );
+ // set the service description
+ SERVICE_DESCRIPTION serviceDescription;
+ serviceDescription.lpDescription = (LPTSTR)serviceDesc.c_str();
+ serviceInstalled =
+ ::ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &serviceDescription);
#if 1
- if ( ! serviceInstalled ) {
+ 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 {
+ // 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
- log() << "Could not set service description. Check the Windows Event Log for more details.";
- }
+ log() << "Could not set service description. Check the Windows Event Log for more details.";
+ }
- ::CloseServiceHandle( schService );
- ::CloseServiceHandle( schSCManager );
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
- if (!serviceInstalled)
- quickExit( EXIT_NTSERVICE_ERROR );
- }
+ if (!serviceInstalled)
+ quickExit(EXIT_NTSERVICE_ERROR);
+}
- void removeServiceOrDie(const wstring& serviceName) {
- log() << "Trying to remove Windows service '" << toUtf8String(serviceName) << "'";
+void removeServiceOrDie(const wstring& serviceName) {
+ log() << "Trying to remove Windows service '" << toUtf8String(serviceName) << "'";
- SC_HANDLE schSCManager = ::OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
- if ( schSCManager == NULL ) {
- DWORD err = ::GetLastError();
- log() << "Error connecting to the Service Control Manager: " << GetWinErrMsg(err);
- quickExit(EXIT_NTSERVICE_ERROR);
- }
+ SC_HANDLE schSCManager = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ if (schSCManager == NULL) {
+ DWORD err = ::GetLastError();
+ log() << "Error connecting to the Service Control Manager: " << GetWinErrMsg(err);
+ quickExit(EXIT_NTSERVICE_ERROR);
+ }
- SC_HANDLE schService = ::OpenService( schSCManager, serviceName.c_str(), SERVICE_ALL_ACCESS );
- if ( schService == NULL ) {
- log() << "Could not find a service named '" << toUtf8String(serviceName) << "' to remove";
- ::CloseServiceHandle( schSCManager );
- quickExit(EXIT_NTSERVICE_ERROR);
- }
+ SC_HANDLE schService = ::OpenService(schSCManager, serviceName.c_str(), SERVICE_ALL_ACCESS);
+ if (schService == NULL) {
+ log() << "Could not find a service named '" << toUtf8String(serviceName) << "' to remove";
+ ::CloseServiceHandle(schSCManager);
+ quickExit(EXIT_NTSERVICE_ERROR);
+ }
- SERVICE_STATUS serviceStatus;
+ SERVICE_STATUS serviceStatus;
- // stop service if its running
- if ( ::ControlService( schService, SERVICE_CONTROL_STOP, &serviceStatus ) ) {
- log() << "Service " << toUtf8String(serviceName) << " is currently running, stopping service";
- while ( ::QueryServiceStatus( schService, &serviceStatus ) ) {
- if ( serviceStatus.dwCurrentState == SERVICE_STOP_PENDING ) {
- Sleep( 1000 );
- }
- else { break; }
+ // stop service if its running
+ if (::ControlService(schService, SERVICE_CONTROL_STOP, &serviceStatus)) {
+ log() << "Service " << toUtf8String(serviceName)
+ << " is currently running, stopping service";
+ while (::QueryServiceStatus(schService, &serviceStatus)) {
+ if (serviceStatus.dwCurrentState == SERVICE_STOP_PENDING) {
+ Sleep(1000);
+ } else {
+ break;
}
- log() << "Service '" << toUtf8String(serviceName) << "' stopped";
}
+ log() << "Service '" << toUtf8String(serviceName) << "' stopped";
+ }
- bool serviceRemoved = ::DeleteService( schService );
-
- ::CloseServiceHandle( schService );
- ::CloseServiceHandle( schSCManager );
+ bool serviceRemoved = ::DeleteService(schService);
- if (serviceRemoved) {
- log() << "Service '" << toUtf8String(serviceName) << "' removed";
- }
- else {
- log() << "Failed to remove service '" << toUtf8String(serviceName) << "'";
- }
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
- if (!serviceRemoved)
- quickExit(EXIT_NTSERVICE_ERROR);
+ if (serviceRemoved) {
+ log() << "Service '" << toUtf8String(serviceName) << "' removed";
+ } else {
+ log() << "Failed to remove service '" << toUtf8String(serviceName) << "'";
}
- bool reportStatus(DWORD reportState, DWORD waitHint, DWORD exitCode) {
- if ( _statusHandle == NULL )
- return false;
+ if (!serviceRemoved)
+ quickExit(EXIT_NTSERVICE_ERROR);
+}
+
+bool reportStatus(DWORD reportState, DWORD waitHint, DWORD exitCode) {
+ if (_statusHandle == NULL)
+ return false;
- static DWORD checkPoint = 1;
+ static DWORD checkPoint = 1;
- SERVICE_STATUS ssStatus;
+ SERVICE_STATUS ssStatus;
- DWORD dwControlsAccepted;
- switch ( reportState ) {
+ DWORD dwControlsAccepted;
+ switch (reportState) {
case SERVICE_START_PENDING:
case SERVICE_STOP_PENDING:
case SERVICE_STOPPED:
@@ -493,122 +480,118 @@ namespace {
default:
dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
break;
- }
-
- ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
- ssStatus.dwServiceSpecificExitCode = exitCode;
- ssStatus.dwControlsAccepted = dwControlsAccepted;
- ssStatus.dwCurrentState = reportState;
-
- // Only report ERROR_SERVICE_SPECIFIC_ERROR when the exit is not clean
- if (reportState == SERVICE_STOPPED && exitCode != EXIT_CLEAN)
- ssStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
- else
- ssStatus.dwWin32ExitCode = NO_ERROR;
-
- ssStatus.dwWaitHint = waitHint;
- ssStatus.dwCheckPoint =
- ( reportState == SERVICE_RUNNING || reportState == SERVICE_STOPPED ) ?
- 0 : checkPoint++;
-
- return SetServiceStatus( _statusHandle, &ssStatus );
}
- static void serviceStopWorker() {
- Client::initThread("serviceStopWorker");
-
- // Stop the process
- // TODO: SERVER-5703, separate the "cleanup for shutdown" functionality from
- // the "terminate process" functionality in exitCleanly.
- exitCleanly(EXIT_WINDOWS_SERVICE_STOP);
+ ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ ssStatus.dwServiceSpecificExitCode = exitCode;
+ ssStatus.dwControlsAccepted = dwControlsAccepted;
+ ssStatus.dwCurrentState = reportState;
+
+ // Only report ERROR_SERVICE_SPECIFIC_ERROR when the exit is not clean
+ if (reportState == SERVICE_STOPPED && exitCode != EXIT_CLEAN)
+ ssStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
+ else
+ ssStatus.dwWin32ExitCode = NO_ERROR;
+
+ ssStatus.dwWaitHint = waitHint;
+ ssStatus.dwCheckPoint =
+ (reportState == SERVICE_RUNNING || reportState == SERVICE_STOPPED) ? 0 : checkPoint++;
+
+ return SetServiceStatus(_statusHandle, &ssStatus);
+}
+
+static void serviceStopWorker() {
+ Client::initThread("serviceStopWorker");
+
+ // Stop the process
+ // TODO: SERVER-5703, separate the "cleanup for shutdown" functionality from
+ // the "terminate process" functionality in exitCleanly.
+ exitCleanly(EXIT_WINDOWS_SERVICE_STOP);
+}
+
+// Minimum of time we tell Windows to wait before we are guilty of a hung shutdown
+const int kStopWaitHintMillis = 30000;
+
+// Run exitCleanly on a separate thread so we can report progress to Windows
+// Note: Windows may still kill us for taking too long,
+// On client OSes, SERVICE_CONTROL_SHUTDOWN has a 5 second timeout configured in
+// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
+static void serviceStop() {
+ stdx::thread serviceWorkerThread(serviceStopWorker);
+
+ // We periodically check if we are done exiting by polling at half of each wait interval
+ //
+ while (
+ !serviceWorkerThread.try_join_for(boost::chrono::milliseconds(kStopWaitHintMillis / 2))) {
+ reportStatus(SERVICE_STOP_PENDING, kStopWaitHintMillis);
+ log() << "Service Stop is waiting for storage engine to finish shutdown";
}
+}
- // Minimum of time we tell Windows to wait before we are guilty of a hung shutdown
- const int kStopWaitHintMillis = 30000;
-
- // Run exitCleanly on a separate thread so we can report progress to Windows
- // Note: Windows may still kill us for taking too long,
- // On client OSes, SERVICE_CONTROL_SHUTDOWN has a 5 second timeout configured in
- // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
- static void serviceStop() {
- stdx::thread serviceWorkerThread(serviceStopWorker);
-
- // We periodically check if we are done exiting by polling at half of each wait interval
- //
- while (!serviceWorkerThread.try_join_for(
- boost::chrono::milliseconds(kStopWaitHintMillis / 2))) {
- reportStatus(SERVICE_STOP_PENDING, kStopWaitHintMillis);
- log() << "Service Stop is waiting for storage engine to finish shutdown";
- }
- }
+static void WINAPI initService(DWORD argc, LPTSTR* argv) {
+ _statusHandle = RegisterServiceCtrlHandler(_serviceName.c_str(), serviceCtrl);
+ if (!_statusHandle)
+ return;
- static void WINAPI initService( DWORD argc, LPTSTR *argv ) {
- _statusHandle = RegisterServiceCtrlHandler( _serviceName.c_str(), serviceCtrl );
- if ( !_statusHandle )
- return;
+ reportStatus(SERVICE_START_PENDING, 1000);
- reportStatus( SERVICE_START_PENDING, 1000 );
+ ExitCode exitCode = _serviceCallback();
- ExitCode exitCode = _serviceCallback();
+ // During clean shutdown, ie NT SCM signals us, _serviceCallback returns here
+ // as part of the listener loop terminating.
+ // exitCleanly is supposed to return. If it blocks, some other thread must be exiting.
+ //
+ serviceStop();
- // During clean shutdown, ie NT SCM signals us, _serviceCallback returns here
- // as part of the listener loop terminating.
- // exitCleanly is supposed to return. If it blocks, some other thread must be exiting.
- //
- serviceStop();
+ reportStatus(SERVICE_STOPPED, 0, exitCode);
+}
- reportStatus(SERVICE_STOPPED, 0, exitCode);
- }
+static void serviceShutdown(const char* controlCodeName) {
+ Client::initThread("serviceShutdown");
- static void serviceShutdown( const char* controlCodeName ) {
- Client::initThread( "serviceShutdown" );
+ log() << "got " << controlCodeName << " request from Windows Service Control Manager, "
+ << (inShutdown() ? "already in shutdown" : "will terminate after current cmd ends");
- log() << "got " << controlCodeName << " request from Windows Service Control Manager, " <<
- ( inShutdown() ? "already in shutdown" : "will terminate after current cmd ends" );
+ reportStatus(SERVICE_STOP_PENDING, kStopWaitHintMillis);
- reportStatus(SERVICE_STOP_PENDING, kStopWaitHintMillis);
+ // Note: This triggers _serviceCallback, ie ServiceMain,
+ // to stop by setting inShutdown() == true
+ signalShutdown();
- // Note: This triggers _serviceCallback, ie ServiceMain,
- // to stop by setting inShutdown() == true
- signalShutdown();
+ // Note: we will report exit status in initService
+}
- // Note: we will report exit status in initService
- }
-
- static void WINAPI serviceCtrl( DWORD ctrlCode ) {
- switch ( ctrlCode ) {
+static void WINAPI serviceCtrl(DWORD ctrlCode) {
+ switch (ctrlCode) {
case SERVICE_CONTROL_STOP:
- serviceShutdown( "SERVICE_CONTROL_STOP" );
+ serviceShutdown("SERVICE_CONTROL_STOP");
break;
case SERVICE_CONTROL_SHUTDOWN:
- serviceShutdown( "SERVICE_CONTROL_SHUTDOWN" );
+ serviceShutdown("SERVICE_CONTROL_SHUTDOWN");
break;
- }
}
+}
- void startService() {
-
- fassert(16454, _startService);
+void startService() {
+ fassert(16454, _startService);
- // Remove the Control-C handler so that we properly process SERVICE_CONTROL_SHUTDOWN
- // via the service handler instead of CTRL_SHUTDOWN_EVENT via the Control-C Handler
- removeControlCHandler();
+ // Remove the Control-C handler so that we properly process SERVICE_CONTROL_SHUTDOWN
+ // via the service handler instead of CTRL_SHUTDOWN_EVENT via the Control-C Handler
+ removeControlCHandler();
- SERVICE_TABLE_ENTRYW dispTable[] = {
- { const_cast<LPWSTR>(_serviceName.c_str()), (LPSERVICE_MAIN_FUNCTION)initService },
- { NULL, NULL }
- };
+ SERVICE_TABLE_ENTRYW dispTable[] = {
+ {const_cast<LPWSTR>(_serviceName.c_str()), (LPSERVICE_MAIN_FUNCTION)initService},
+ {NULL, NULL}};
- log() << "Trying to start Windows service '" << toUtf8String(_serviceName) << "'";
- if (StartServiceCtrlDispatcherW(dispTable)) {
- quickExit(EXIT_CLEAN);
- }
- else {
- ::exit(EXIT_NTSERVICE_ERROR);
- }
+ log() << "Trying to start Windows service '" << toUtf8String(_serviceName) << "'";
+ if (StartServiceCtrlDispatcherW(dispTable)) {
+ quickExit(EXIT_CLEAN);
+ } else {
+ ::exit(EXIT_NTSERVICE_ERROR);
}
+}
} // namspace ntservice
-} // namespace mongo
+} // namespace mongo
#endif