summaryrefslogtreecommitdiff
path: root/util/ntservice.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'util/ntservice.cpp')
-rw-r--r--util/ntservice.cpp371
1 files changed, 0 insertions, 371 deletions
diff --git a/util/ntservice.cpp b/util/ntservice.cpp
deleted file mode 100644
index c9723a10d4f..00000000000
--- a/util/ntservice.cpp
+++ /dev/null
@@ -1,371 +0,0 @@
-// ntservice.cpp
-
-/* Copyright 2009 10gen Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "pch.h"
-#include "ntservice.h"
-#include "../db/client.h"
-#include "winutil.h"
-#include "text.h"
-#include <direct.h>
-
-#if defined(_WIN32)
-
-namespace mongo {
-
- void shutdownServer();
-
- SERVICE_STATUS_HANDLE ServiceController::_statusHandle = NULL;
- std::wstring ServiceController::_serviceName;
- ServiceCallback ServiceController::_serviceCallback = NULL;
-
- ServiceController::ServiceController() {}
-
- bool initService();
-
- // returns true if the service is started.
- bool serviceParamsCheck( program_options::variables_map& params, const std::string dbpath, int argc, char* argv[] ) {
- bool installService = false;
- bool removeService = false;
- bool reinstallService = false;
- bool startService = false;
-
- std::wstring windowsServiceName = L"MongoDB";
- std::wstring windowsServiceDisplayName = L"Mongo DB";
- std::wstring windowsServiceDescription = L"Mongo DB Server";
- std::wstring windowsServiceUser = L"";
- std::wstring windowsServicePassword = L"";
-
- if (params.count("install")) {
- if ( ! params.count( "logpath" ) ) {
- cerr << "--install has to be used with --logpath" << endl;
- ::exit(-1);
- }
- installService = true;
- }
- if (params.count("reinstall")) {
- if ( ! params.count( "logpath" ) ) {
- cerr << "--reinstall has to be used with --logpath" << endl;
- ::exit(-1);
- }
- reinstallService = true;
- }
- if (params.count("remove")) {
- removeService = true;
- }
- if (params.count("service")) {
- startService = true;
- }
-
- if (params.count("serviceName")) {
- string x = params["serviceName"].as<string>();
- windowsServiceName = wstring(x.size(),L' ');
- for ( size_t i=0; i<x.size(); i++) {
- windowsServiceName[i] = x[i];
- }
- }
- if (params.count("serviceDisplayName")) {
- string x = params["serviceDisplayName"].as<string>();
- windowsServiceDisplayName = wstring(x.size(),L' ');
- for ( size_t i=0; i<x.size(); i++) {
- windowsServiceDisplayName[i] = x[i];
- }
- }
- if (params.count("serviceDescription")) {
- string x = params["serviceDescription"].as<string>();
- windowsServiceDescription = wstring(x.size(),L' ');
- for ( size_t i=0; i<x.size(); i++) {
- windowsServiceDescription[i] = x[i];
- }
- }
- if (params.count("serviceUser")) {
- string x = params["serviceUser"].as<string>();
- windowsServiceUser = wstring(x.size(),L' ');
- for ( size_t i=0; i<x.size(); i++) {
- windowsServiceUser[i] = x[i];
- }
- }
- if (params.count("servicePassword")) {
- string x = params["servicePassword"].as<string>();
- windowsServicePassword = wstring(x.size(),L' ');
- for ( size_t i=0; i<x.size(); i++) {
- windowsServicePassword[i] = x[i];
- }
- }
-
- if ( reinstallService ) {
- ServiceController::removeService( windowsServiceName );
- }
- if ( installService || reinstallService ) {
- if ( !ServiceController::installService( windowsServiceName , windowsServiceDisplayName, windowsServiceDescription, windowsServiceUser, windowsServicePassword, dbpath, argc, argv ) )
- dbexit( EXIT_NTSERVICE_ERROR );
- dbexit( EXIT_CLEAN );
- }
- else if ( removeService ) {
- if ( !ServiceController::removeService( windowsServiceName ) )
- dbexit( EXIT_NTSERVICE_ERROR );
- dbexit( EXIT_CLEAN );
- }
- else if ( startService ) {
- if ( !ServiceController::startService( windowsServiceName , mongo::initService ) )
- dbexit( EXIT_NTSERVICE_ERROR );
- return true;
- }
- return false;
- }
-
- 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.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: " << toUtf8String(actualServiceUser) << endl;
- serviceInstalled = ::ChangeServiceConfig( schService, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, actualServiceUser.c_str(), servicePassword.c_str(), NULL );
- if ( !serviceInstalled ) {
- cerr << "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;
- }
-
- 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;
- }
-
- bool ServiceController::startService( const std::wstring& serviceName, ServiceCallback startService ) {
- _serviceName = serviceName;
- _serviceCallback = startService;
-
- SERVICE_TABLE_ENTRY dispTable[] = {
- { (LPTSTR)serviceName.c_str(), (LPSERVICE_MAIN_FUNCTION)ServiceController::initService },
- { NULL, NULL }
- };
-
- return StartServiceCtrlDispatcher( dispTable );
- }
-
- bool ServiceController::reportStatus( DWORD reportState, DWORD waitHint ) {
- if ( _statusHandle == NULL )
- return false;
-
- static DWORD checkPoint = 1;
-
- SERVICE_STATUS ssStatus;
-
- DWORD dwControlsAccepted;
- switch ( reportState ) {
- case SERVICE_START_PENDING:
- case SERVICE_STOP_PENDING:
- case SERVICE_STOPPED:
- dwControlsAccepted = 0;
- break;
- default:
- dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
- break;
- }
-
- ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
- ssStatus.dwServiceSpecificExitCode = 0;
- ssStatus.dwControlsAccepted = dwControlsAccepted;
- ssStatus.dwCurrentState = reportState;
- ssStatus.dwWin32ExitCode = NO_ERROR;
- ssStatus.dwWaitHint = waitHint;
- ssStatus.dwCheckPoint = ( reportState == SERVICE_RUNNING || reportState == SERVICE_STOPPED ) ? 0 : checkPoint++;
-
- return SetServiceStatus( _statusHandle, &ssStatus );
- }
-
- void WINAPI ServiceController::initService( DWORD argc, LPTSTR *argv ) {
- _statusHandle = RegisterServiceCtrlHandler( _serviceName.c_str(), serviceCtrl );
- if ( !_statusHandle )
- return;
-
- reportStatus( SERVICE_START_PENDING, 1000 );
-
- _serviceCallback();
- dbexit( EXIT_CLEAN );
-
- reportStatus( SERVICE_STOPPED );
- }
-
- static void serviceShutdown( const char* controlCodeName ) {
- Client::initThread( "serviceShutdown" );
- log() << "got " << controlCodeName << " request from Windows Service Controller, " <<
- ( inShutdown() ? "already in shutdown" : "will terminate after current cmd ends" ) << endl;
- ServiceController::reportStatus( SERVICE_STOP_PENDING );
- if ( ! inShutdown() ) {
- exitCleanly( EXIT_WINDOWS_SERVICE_STOP );
- ServiceController::reportStatus( SERVICE_STOPPED );
- }
- }
-
- void WINAPI ServiceController::serviceCtrl( DWORD ctrlCode ) {
- switch ( ctrlCode ) {
- case SERVICE_CONTROL_STOP:
- serviceShutdown( "SERVICE_CONTROL_STOP" );
- break;
- case SERVICE_CONTROL_SHUTDOWN:
- serviceShutdown( "SERVICE_CONTROL_SHUTDOWN" );
- break;
- }
- }
-
-} // namespace mongo
-
-#endif