service.c revision 5385
961N/A/*
961N/A* CDDL HEADER START
961N/A*
961N/A* The contents of this file are subject to the terms of the
961N/A* Common Development and Distribution License, Version 1.0 only
961N/A* (the "License"). You may not use this file except in compliance
961N/A* with the License.
961N/A*
961N/A* You can obtain a copy of the license at
961N/A* trunk/opends/resource/legal-notices/OpenDS.LICENSE
961N/A* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
961N/A* See the License for the specific language governing permissions
961N/A* and limitations under the License.
961N/A*
961N/A* When distributing Covered Code, include this CDDL HEADER in each
5025N/A* file and include the License file \
961N/A* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
961N/A* add the following below this CDDL HEADER, with the fields enclosed
961N/A* by brackets "[]" replaced with your own identifying * information:
961N/A* Portions Copyright [yyyy] [name of copyright owner]
961N/A*
961N/A* CDDL HEADER END
961N/A*
961N/A*
5025N/A* Copyright 2008-2010 Sun Microsystems, Inc.
5385N/A* Portions Copyright 2011 ForgeRock AS
961N/A*/
961N/A
961N/A#include "service.h"
961N/A
961N/Aint _serviceCurStatus;
961N/ASERVICE_STATUS_HANDLE *_serviceStatusHandle;
961N/AHANDLE _terminationEvent = NULL;
961N/Achar *_instanceDir = NULL;
961N/AHANDLE _eventLog = NULL;
1295N/Achar * _logFile = NULL;
961N/A
961N/A// ----------------------------------------------------
961N/A// Register a service handler to the service control dispatcher.
961N/A// A service handler will manage the control function such as:
961N/A// stop, pause, continue, shutdown, interrogate. The control functions
961N/A// are sent by the service control dispatcher upon user request
961N/A// (ie. NET STOP)
961N/A//
961N/A// serviceName the internal name of the service (unique in the system)
961N/A// serviceHandler the handler of the service
961N/A// serviceStatusHandle the service status handle returned by the SCM
961N/A// The functions returns SERVICE_RETURN_OK if we could start the service
961N/A// and SERVICE_RETURN_ERROR otherwise.
961N/A// ----------------------------------------------------
961N/A
961N/AServiceReturnCode registerServiceHandler (
961N/Achar* serviceName,
961N/ALPHANDLER_FUNCTION serviceHandler,
961N/ASERVICE_STATUS_HANDLE* serviceStatusHandle
961N/A)
961N/A{
961N/A ServiceReturnCode returnValue;
961N/A
1298N/A debug("Registering the service handler for '%s'", serviceName);
1298N/A
961N/A // register the service to the service control dispatcher (SCM)
961N/A *serviceStatusHandle = RegisterServiceCtrlHandler (
961N/A serviceName, (LPHANDLER_FUNCTION) serviceHandler
961N/A );
961N/A if (serviceStatusHandle == NULL)
961N/A {
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A }
961N/A else
961N/A {
961N/A returnValue = SERVICE_RETURN_OK;
961N/A }
1298N/A
1298N/A debug("registerServiceHandler returning '%d'", returnValue);
1878N/A
961N/A return returnValue;
961N/A} // registerServiceHandler
961N/A
961N/A
961N/A
961N/A// ---------------------------------------------------
961N/A// Reports a log event of a given type, id and arguments
961N/A// serviceBinPath the binary associated with the service.
961N/A// The function returns TRUE if the event could be logged and FALSE otherwise.
961N/A// ---------------------------------------------------
961N/ABOOL reportLogEvent(WORD eventType, DWORD eventId, WORD argCount,
961N/Aconst char** args)
961N/A{
961N/A BOOL reportOk;
961N/A
961N/A if (argCount > 0)
961N/A {
961N/A // report the event
961N/A reportOk = ReportEvent(
961N/A _eventLog, // event log handle
961N/A eventType, // info, warning, error
5385N/A WIN_FACILITY_NAME_OPENDJ, // unique category for OPENDJ
961N/A eventId,
961N/A NULL, // no user security identifier
961N/A argCount, // number of args
961N/A 0, // raw data size
961N/A args, // args
961N/A NULL // no raw data
961N/A );
961N/A }
961N/A else
961N/A {
961N/A // report the event
961N/A reportOk = ReportEvent(
961N/A _eventLog, // event log handle
961N/A eventType, // info, warning, error
5385N/A WIN_FACILITY_NAME_OPENDJ, // unique category for OPENDJ
961N/A eventId,
961N/A NULL, // no user security identifier
961N/A argCount, // number of args
961N/A 0, // raw data size
961N/A NULL, // args
961N/A NULL // no raw data
961N/A );
961N/A }
961N/A
961N/A
961N/A return reportOk;
961N/A}
961N/A
961N/A// ---------------------------------------------------------------
961N/A// Get a handle to the Service Control Manager (SCM).
961N/A// accessRights the desired access rights; generic access are:
961N/A// - GENERIC_READ use to get the list of services
961N/A// - GENERIC_WRITE use to create & remove a service
961N/A// - GENERIC_EXECUTE
961N/A// - GENERIC_ALL
961N/A// scm the handler to the SCM
961N/A// The function returns SERVICE_RETURN_OK if we could get the SCM
961N/A// and SERVICE_RETURN_ERROR otherwise.
961N/A// ---------------------------------------------------------------
961N/A
961N/AServiceReturnCode openScm(DWORD accessRights, SC_HANDLE *scm)
961N/A{
961N/A ServiceReturnCode returnValue;
961N/A
961N/A // open Service Control Manager
961N/A *scm = (SC_HANDLE)OpenSCManager (
961N/A NULL, // local machine
961N/A NULL, // ServicesActive database
961N/A accessRights // desired rights
961N/A );
961N/A if (scm == NULL)
961N/A {
1878N/A debugError("Failed to open the Service Control Manager. Last error = %d",
1878N/A GetLastError());
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A }
961N/A else
961N/A {
1298N/A debug("Successfully opened the Service Control Manager.");
961N/A returnValue = SERVICE_RETURN_OK;
961N/A }
961N/A return returnValue;
961N/A} // openScm
961N/A
961N/A// ---------------------------------------------------
961N/A// Creates the registry key to send events based on the name of the service.
961N/A// serviceName the serviceName.
961N/A// serviceBinPath the binary associated with the service.
961N/A// The function returns TRUE if the key could be registered (or was already
961N/A// registered) and FALSE otherwise.
961N/A// ---------------------------------------------------
961N/ABOOLEAN createRegistryKey(char* serviceName)
961N/A{
961N/A // true if the server is already registered
961N/A BOOL alreadyRegistered = FALSE;
961N/A
961N/A // false as soon as an error occurs
961N/A BOOL success = TRUE;
961N/A
961N/A // handle to the created/opened key
961N/A HKEY hkey = NULL;
961N/A
961N/A // Create the event source subkey (or open it if it already exists)
961N/A char subkey [MAX_REGISTRY_KEY];
961N/A
961N/A long result;
961N/A
961N/A DWORD nbCategories = 1;
961N/A
961N/A // get the full path to the current executable file: is safe to do it
961N/A // here because we already required it to figure out to get the service
961N/A // name based on the command to run associated with it.
961N/A char execName [MAX_PATH];
1298N/A
1298N/A debug("Creating registry key for service '%s'.", serviceName);
1298N/A
961N/A GetModuleFileName (
961N/A NULL,
961N/A execName,
961N/A MAX_PATH
961N/A );
961N/A
961N/A // Check whether the Registry Key is already created,
961N/A // If so don't create a new one.
961N/A sprintf (subkey, EVENT_LOG_KEY, serviceName);
961N/A result = RegOpenKeyEx(
961N/A HKEY_LOCAL_MACHINE,
961N/A subkey,
961N/A 0,
961N/A KEY_QUERY_VALUE, // to query the values of a registry key.
961N/A &hkey // OUT
961N/A );
961N/A if (result == ERROR_SUCCESS)
961N/A {
1298N/A debug("The registry key for service '%s' already exists.", serviceName);
961N/A alreadyRegistered = TRUE;
961N/A success = FALSE;
961N/A }
961N/A
961N/A if (success)
961N/A {
961N/A DWORD disposition;
961N/A result = RegCreateKeyEx(
961N/A HKEY_LOCAL_MACHINE, //
961N/A subkey, //
961N/A 0, // reserved
961N/A NULL, // key object class
961N/A REG_OPTION_NON_VOLATILE, // option
961N/A KEY_WRITE, // desired access
961N/A NULL, // hkey cannot be inherited
961N/A &hkey, // OUT
961N/A &disposition // OUT new key / existing key
961N/A );
961N/A if (result != ERROR_SUCCESS)
961N/A {
1298N/A debugError("RegCreateKeyEx failed, result=%d.", result);
961N/A success = FALSE;
961N/A }
961N/A }
961N/A
961N/A if (success)
961N/A {
961N/A result = RegSetValueEx(
961N/A hkey, // subkey handle
961N/A "EventMessageFile", // value name
961N/A 0, // must be zero
961N/A REG_EXPAND_SZ, // value type
961N/A (LPBYTE)execName, // pointer to value data
961N/A (DWORD) (lstrlen(execName) + 1)
961N/A * sizeof(TCHAR) // length of value data
961N/A );
961N/A if (result != ERROR_SUCCESS)
961N/A {
1878N/A debugError("RegSetValueEx('EventMessageFile') failed, result=%d.",
1878N/A result);
961N/A success = FALSE;
961N/A }
961N/A }
961N/A
961N/A // Set the supported event types
961N/A if (success)
961N/A {
961N/A DWORD supportedTypes =
961N/A EVENTLOG_SUCCESS
961N/A | EVENTLOG_ERROR_TYPE
961N/A | EVENTLOG_WARNING_TYPE
961N/A | EVENTLOG_INFORMATION_TYPE;
961N/A
961N/A result = RegSetValueEx(
961N/A hkey, // subkey handle
961N/A "TypesSupported", // value name
961N/A 0, // must be zero
961N/A REG_DWORD, // value type
961N/A (LPBYTE) &supportedTypes, // pointer to value data
961N/A sizeof(DWORD) // length of value data
961N/A );
961N/A if (result != ERROR_SUCCESS)
961N/A {
1298N/A debugError("RegSetValueEx('TypesSupported') failed, result=%d.", result);
961N/A success = FALSE;
961N/A }
961N/A }
961N/A
961N/A // Set the category message file
961N/A if (success)
961N/A {
961N/A result = RegSetValueEx(
961N/A hkey, // subkey handle
961N/A "CategoryMessageFile", // value name
961N/A 0, // must be zero
961N/A REG_EXPAND_SZ, // value type
961N/A (LPBYTE)execName, // pointer to value data
961N/A (DWORD) (lstrlen(execName) + 1)
961N/A *sizeof(TCHAR) // length of value data
961N/A );
961N/A if (result != ERROR_SUCCESS)
961N/A {
1878N/A debugError("RegSetValueEx('CategoryMessageFile') failed, result=%d.",
1878N/A result);
961N/A success = FALSE;
961N/A }
961N/A }
961N/A
5385N/A // Set the number of categories: 1 (OPENDJ)
961N/A if (success)
961N/A {
961N/A long result = RegSetValueEx(
961N/A hkey, // subkey handle
961N/A "CategoryCount", // value name
961N/A 0, // must be zero
961N/A REG_DWORD, // value type
961N/A (LPBYTE) &nbCategories, // pointer to value data
961N/A sizeof(DWORD) // length of value data
961N/A );
961N/A if (result != ERROR_SUCCESS)
961N/A {
1298N/A debugError("RegSetValueEx('CategoryCount') failed, result=%d.", result);
961N/A success = FALSE;
961N/A }
961N/A }
961N/A
961N/A // close the key before leaving
961N/A if (hkey != NULL)
961N/A {
961N/A RegCloseKey (hkey);
961N/A }
961N/A
961N/A if (alreadyRegistered || success)
961N/A {
961N/A return TRUE;
961N/A }
961N/A else
961N/A {
1298N/A debugError("Could not create a registry key.");
961N/A return FALSE;
961N/A }
961N/A} // createRegistryKey
961N/A
961N/A
961N/A// ---------------------------------------------------
961N/A// Removes the registry key to send events based on the name of the service.
961N/A// serviceName the serviceName.
961N/A// The function returns TRUE if the key could be unregistered (or it was not
961N/A// registered) and FALSE otherwise.
961N/A// ---------------------------------------------------
961N/ABOOLEAN removeRegistryKey(char* serviceName)
961N/A{
1298N/A BOOL returnValue = FALSE;
961N/A
961N/A // Create the event source subkey (or open it if it already exists)
961N/A char subkey [MAX_REGISTRY_KEY];
961N/A
961N/A long result;
961N/A
961N/A HKEY hkey = NULL;
961N/A
1298N/A debug("Removing registry key for service '%s'.", serviceName);
1298N/A
961N/A // Check whether the Registry Key is already created,
961N/A // If so don't create a new one.
961N/A sprintf (subkey, EVENT_LOG_KEY, serviceName);
961N/A result = RegOpenKeyEx(
961N/A HKEY_LOCAL_MACHINE,
961N/A subkey,
961N/A 0,
961N/A KEY_QUERY_VALUE, // to query the values of a registry key.
961N/A &hkey // OUT
961N/A );
961N/A if (result != ERROR_SUCCESS)
961N/A {
1878N/A debug("The registry key for service '%s' does not exist, so we do not need to remove it.",
1878N/A serviceName);
961N/A // Assume that the registry key does not exist.
961N/A returnValue = TRUE;
961N/A }
961N/A else
961N/A {
961N/A result = RegDeleteKey (HKEY_LOCAL_MACHINE, subkey);
961N/A if (result == ERROR_SUCCESS)
961N/A {
961N/A returnValue = TRUE;
961N/A }
1298N/A else
1298N/A {
1298N/A debugError("RegDeleteKey('%s') failed, result=%d.", subkey, result);
1298N/A }
961N/A }
961N/A
961N/A return returnValue;
961N/A} // removeRegistryKey
961N/A
961N/A// ---------------------------------------------------
961N/A// Register the source of event and returns the handle
961N/A// for the event log.
961N/A// serviceName the serviceName.
961N/A// ---------------------------------------------------
961N/AHANDLE registerEventLog(char *serviceName)
961N/A{
961N/A HANDLE eventLog = NULL;
961N/A
961N/A // subkey under Eventlog registry key
961N/A char subkey [MAX_SERVICE_NAME];
1298N/A debug("Registering the Event Log for service '%s'.", serviceName);
1298N/A
961N/A sprintf (subkey, serviceName);
961N/A
961N/A eventLog = RegisterEventSource(
961N/A NULL, // local host
961N/A subkey // subkey under Eventlog registry key
961N/A );
961N/A
961N/A return eventLog;
961N/A
961N/A} // registerEventLog
961N/A
961N/A// ---------------------------------------------------
961N/A// Deregister the source of event.
961N/A// ---------------------------------------------------
961N/Avoid deregisterEventLog()
961N/A{
961N/A if (_eventLog != NULL)
961N/A {
1298N/A debug("Deregistering the Event Log.");
961N/A DeregisterEventSource(_eventLog);
961N/A }
961N/A}
961N/A
961N/A// ----------------------------------------------------
961N/A// Check if the server is running or not.
961N/A// The functions returns SERVICE_RETURN_OK if we could determine if
961N/A// the server is running or not and false otherwise.
961N/A// ----------------------------------------------------
5025N/AServiceReturnCode isServerRunning(BOOL *running, BOOL mustDebug)
961N/A{
961N/A ServiceReturnCode returnValue;
961N/A char* relativePath = "\\locks\\server.lock";
961N/A char lockFile[MAX_PATH];
5025N/A if (mustDebug)
5025N/A {
5025N/A debug("Determining if the server is running.");
5025N/A }
961N/A if (strlen(relativePath)+strlen(_instanceDir)+1 < MAX_PATH)
961N/A {
961N/A int fd;
961N/A
961N/A sprintf(lockFile, "%s%s", _instanceDir, relativePath);
5025N/A if (mustDebug)
5025N/A {
5025N/A debug(
5025N/A "When determining whether the server is running, the lock file name is '%s'.",
1878N/A lockFile);
5025N/A }
961N/A fd = _open(lockFile, _O_RDWR);
961N/A
961N/A if (fd != -1)
961N/A {
5025N/A if (mustDebug)
5025N/A {
5025N/A debug("Able to open the lock file '%s'.", lockFile);
5025N/A }
961N/A returnValue = SERVICE_RETURN_OK;
961N/A // Test if there is a lock
961N/A /* Lock some bytes and read them. Then unlock. */
961N/A if(_locking(fd, LK_NBLCK, 1) != -1)
961N/A {
5025N/A if (mustDebug)
5025N/A {
5025N/A debug("Able to lock '%s', so the server is not running.", lockFile);
5025N/A }
961N/A *running = FALSE;
1295N/A _locking(fd, LK_UNLCK, 1);
961N/A }
961N/A else
961N/A {
961N/A if (errno == EACCES)
961N/A {
5025N/A if (mustDebug)
5025N/A {
5025N/A debug("Unable to lock '%s', so the server is running.", lockFile);
5025N/A }
961N/A *running = TRUE;
961N/A }
961N/A else
961N/A {
961N/A *running = FALSE;
961N/A returnValue = SERVICE_RETURN_ERROR;
1298N/A debugError("Unexpected error locking: %d", errno);
961N/A }
961N/A }
961N/A _close(fd);
961N/A }
961N/A else
961N/A {
5025N/A if (mustDebug)
5025N/A {
5025N/A debug("Could not open lock file '%s', which means the server is not running.",
5025N/A lockFile);
5025N/A }
961N/A *running = FALSE;
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A }
961N/A }
961N/A else
961N/A {
5025N/A debugError("Lock file path is too long.");
961N/A *running = FALSE;
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A }
1298N/A
961N/A return returnValue;
961N/A} // isServerRunning
961N/A
961N/A// ----------------------------------------------------
961N/A// Start the application using start-ds.bat
961N/A// The functions returns SERVICE_RETURN_OK if we could start the server
961N/A// and SERVICE_RETURN_ERROR otherwise.
961N/A// ----------------------------------------------------
961N/AServiceReturnCode doStartApplication()
961N/A{
961N/A ServiceReturnCode returnValue;
961N/A // init out params
1196N/A char* relativePath = "\\bat\\start-ds.bat";
961N/A char command[COMMAND_SIZE];
5072N/A PROCESS_INFORMATION procInfo; // info on the new process
5072N/A BOOL createOk;
5072N/A BOOL waitOk;
1298N/A
5385N/A debug("doStartApplication");
1878N/A
961N/A if (strlen(relativePath)+strlen(_instanceDir)+1 < COMMAND_SIZE)
961N/A {
5072N/A sprintf(command, "\"%s%s\" --windowsNetStart", _instanceDir, relativePath);
5072N/A debug("doStartApplication: Launching batch file: %s", command);
5072N/A createOk = createBatchFileChildProcess(command, FALSE, &procInfo);
961N/A
5072N/A if (createOk)
5072N/A {
5072N/A // At this point start-ds.bat has been launched. Try to wait till it
5072N/A // returns. At the end of start-ds.bat we can be sure that the server (at
5072N/A // least) tried to start: the script checks that the file created during
5072N/A // startup is deleted (file logs\server.starting).
5072N/A const DWORD STARTDS_WAIT_DEFAULT_VALUE = 300000;
5072N/A DWORD wait = STARTDS_WAIT_DEFAULT_VALUE;
5385N/A char * nWaitForStartDS = getenv("OPENDJ_WINDOWS_SERVICE_STARTDS_WAIT");
5072N/A DWORD startDSExit;
5072N/A if (nWaitForStartDS != NULL)
5072N/A {
5385N/A debug("doStartApplication: OPENDJ_WINDOWS_SERVICE_STARTDS_WAIT env var set to %s",
5072N/A nWaitForStartDS);
5072N/A wait = (int)strtol(nWaitForStartDS, (char **)NULL, 10);
5072N/A if (wait <= 0)
5072N/A {
5072N/A wait = STARTDS_WAIT_DEFAULT_VALUE;
5072N/A }
5072N/A }
5072N/A else
5072N/A {
5385N/A debug("doStartApplication: OPENDJ_WINDOWS_SERVICE_STARTDS_WAIT is not set. Using default %d milliseconds.",
5072N/A STARTDS_WAIT_DEFAULT_VALUE);
5072N/A }
5072N/A waitOk = waitForProcess(&procInfo, wait, &startDSExit);
5072N/A if (waitOk)
5072N/A {
5072N/A debug("doStartApplication: waited properly for process end.");
5072N/A debug("doStartApplication: exit code of script: %d", startDSExit);
5072N/A if (startDSExit != 0)
5072N/A {
5072N/A createOk = FALSE;
5072N/A }
5072N/A }
5072N/A }
5072N/A else
5072N/A {
5072N/A debug("The batch file process could not be created property");
5072N/A }
5072N/A
5072N/A if (createOk && waitOk)
5072N/A {
5072N/A BOOL running;
5072N/A // Just check once if the server is running or not: since the wait
5072N/A // wait was successful, if the server is getting the lock, it already
5072N/A // got it.
5072N/A isServerRunning(&running, TRUE);
5072N/A if (running)
5072N/A {
5072N/A returnValue = SERVICE_RETURN_OK;
5072N/A debug("doStartApplication: server running.");
5072N/A }
5072N/A else
5072N/A {
5072N/A returnValue = SERVICE_RETURN_ERROR;
5072N/A debug("doStartApplication: server not running.");
5072N/A }
5072N/A }
5072N/A else if (createOk)
961N/A {
961N/A // Try to see if server is really running
5072N/A const DWORD DEFAULT_TRIES = 100;
5072N/A int nTries = DEFAULT_TRIES;
5385N/A char * nTriesEnv = getenv("OPENDJ_WINDOWS_SERVICE_START_NTRIES");
961N/A BOOL running = FALSE;
3899N/A if (nTriesEnv != NULL)
3899N/A {
5385N/A debug("OPENDJ_WINDOWS_SERVICE_START_NTRIES env var set to %s", nTriesEnv);
5025N/A nTries = (int)strtol(nTriesEnv, (char **)NULL, 10);
5025N/A if (nTries <= 0)
5025N/A {
5072N/A nTries = DEFAULT_TRIES;
5025N/A }
3899N/A }
3899N/A else
3899N/A {
5385N/A debug("OPENDJ_WINDOWS_SERVICE_START_NTRIES is not set. Using default %d tries.", nTries);
3899N/A }
1878N/A
1878N/A debug(
5072N/A "doStartApplication: the spawn of the batch command worked. Command: '%s'",
1878N/A command);
5072N/A
961N/A while ((nTries > 0) && !running)
961N/A {
1298N/A nTries--;
5025N/A if (isServerRunning(&running, TRUE) != SERVICE_RETURN_OK)
961N/A {
961N/A break;
961N/A }
961N/A if (!running)
961N/A {
3899N/A debug("Sleeping for 5 seconds to allow the process to get the lock. %d tries remaining.",
1878N/A nTries);
3899N/A Sleep(5000);
961N/A }
961N/A }
961N/A if (running)
961N/A {
961N/A returnValue = SERVICE_RETURN_OK;
1295N/A debug("doStartApplication: server running.");
961N/A }
961N/A else
961N/A {
961N/A returnValue = SERVICE_RETURN_ERROR;
1295N/A debug("doStartApplication: server not running.");
961N/A }
961N/A }
961N/A else
961N/A {
1878N/A
961N/A returnValue = SERVICE_RETURN_ERROR;
5072N/A debug("doStartApplication: batch command spawn failed. Sent command: '%s'", command);
961N/A }
961N/A }
961N/A else
961N/A {
961N/A returnValue = SERVICE_RETURN_ERROR;
1295N/A debug("doStartApplication: the command path name is too long.");
961N/A }
961N/A return returnValue;
961N/A} // doStartApplication
961N/A
5072N/A
5072N/A
961N/A// ----------------------------------------------------
961N/A// Start the application using stop-ds.bat
961N/A// The functions returns SERVICE_RETURN_OK if we could stop the server
961N/A// and SERVICE_RETURN_ERROR otherwise.
961N/A// ----------------------------------------------------
961N/AServiceReturnCode doStopApplication()
961N/A{
961N/A ServiceReturnCode returnValue;
961N/A // init out params
1196N/A char* relativePath = "\\bat\\stop-ds.bat";
961N/A char command[COMMAND_SIZE];
5385N/A
5385N/A debug("doStopApplication");
961N/A if (strlen(relativePath)+strlen(_instanceDir)+1 < COMMAND_SIZE)
961N/A {
961N/A sprintf(command, "\"%s%s\" --windowsNetStop", _instanceDir, relativePath);
961N/A
961N/A // launch the command
1295N/A if (spawn(command, FALSE) != -1)
961N/A {
961N/A // Try to see if server is really stopped
961N/A int nTries = 10;
961N/A BOOL running = TRUE;
1878N/A
1295N/A debug("doStopApplication: the spawn of the process worked.");
1878N/A
961N/A // Wait to be able to launch the java process in order it to free the lock
961N/A // on the file.
961N/A Sleep(3000);
961N/A while ((nTries > 0) && running)
961N/A {
5025N/A if (isServerRunning(&running, TRUE) != SERVICE_RETURN_OK)
961N/A {
961N/A break;
961N/A }
961N/A if (running)
961N/A {
961N/A Sleep(2000);
961N/A }
961N/A }
961N/A if (!running)
961N/A {
961N/A returnValue = SERVICE_RETURN_OK;
1295N/A debug("doStopApplication: server stopped.");
961N/A }
961N/A else
961N/A {
961N/A returnValue = SERVICE_RETURN_ERROR;
1295N/A debug("doStopApplication: server NOT stopped.");
961N/A }
961N/A }
961N/A else
961N/A {
961N/A returnValue = SERVICE_RETURN_ERROR;
1300N/A debug("doStopApplication: spawn failed. Sent command: %s", command);
961N/A }
961N/A }
961N/A else
961N/A {
961N/A returnValue = SERVICE_RETURN_ERROR;
1295N/A debug("doStopApplication: the command path name is too long.");
961N/A }
961N/A return returnValue;
961N/A} // doStopApplication
961N/A
961N/A// ---------------------------------------------------------------
961N/A// Build the path to the binary that contains serviceMain.
961N/A// Actually, the binary is the current executable file...
961N/A// serviceBinPath the path to the service binary.
961N/A// instanceDir the instanceDirectory.
961N/A// The string stored in serviceBinPath looks like
5385N/A// <SERVER_ROOT>/lib/opendj_service.exe start <_instanceDir>
961N/A// It is up to the caller of the function to allocate
1295N/A// at least COMMAND_SIZE bytes in serviceBinPath.
961N/A// The function returns SERVICE_RETURN_OK if we could create the binary
961N/A// path name and SERVICE_RETURN_ERROR otherwise.
961N/A// ---------------------------------------------------------------
961N/A
961N/AServiceReturnCode createServiceBinPath(char* serviceBinPath)
961N/A{
961N/A ServiceReturnCode returnValue = SERVICE_RETURN_OK;
961N/A
961N/A // get the full path to the current executable file
961N/A char fileName [MAX_PATH];
961N/A DWORD result = GetModuleFileName (
961N/A NULL, // get the path to the current executable file
961N/A fileName,
961N/A MAX_PATH
961N/A );
961N/A
961N/A if (result == 0)
961N/A {
961N/A // failed to get the path of the executable file
961N/A returnValue = SERVICE_RETURN_ERROR;
5385N/A debug("Could not get the path of the executable file.");
961N/A }
961N/A else
961N/A {
1878N/A debug(
1878N/A "When determining the service bin path, the module file name is '%s'.",
1878N/A fileName);
1298N/A
961N/A if (result == MAX_PATH)
961N/A {
961N/A // buffer was too small, executable name is probably not valid
961N/A returnValue = SERVICE_RETURN_ERROR;
1295N/A debug("The name of the module file is too long.");
961N/A }
961N/A else
961N/A {
1878N/A if ((strlen(fileName) + strlen(" start ") + strlen(_instanceDir) +
1878N/A 2 * strlen("\"\"")) < COMMAND_SIZE)
961N/A {
1301N/A sprintf(serviceBinPath, "\"%s\" start \"%s\"", fileName,
961N/A _instanceDir);
961N/A }
961N/A else
961N/A {
1878N/A char * msg =
1878N/A "The name of the resulting windows service command is too long.\n";
1298N/A debug(msg);
961N/A // buffer was too small, executable name is probably not valid
961N/A returnValue = SERVICE_RETURN_ERROR;
1298N/A fprintf(stdout, msg);
961N/A }
961N/A }
961N/A }
961N/A
961N/A return returnValue;
961N/A} // createServiceBinPath
961N/A
961N/A// ----------------------------------------------------
961N/A// Returns the service name that maps the command used to start the
961N/A// product. All commands are supposed to be unique because they have
961N/A// the instance dir as parameter.
961N/A//
1295N/A// The functions returns SERVICE_RETURN_OK if we could get a service name
961N/A// and SERVICE_RETURN_ERROR otherwise.
961N/A// The serviceName buffer must be allocated OUTSIDE the function and its
961N/A// minimum size must be of 256 (the maximum string length of a Service Name).
961N/A// ----------------------------------------------------
961N/A
961N/AServiceReturnCode getServiceName(char* cmdToRun, char* serviceName)
961N/A{
961N/A // returned status code
961N/A ServiceReturnCode returnValue = SERVICE_RETURN_OK;
961N/A
961N/A // retrieve list of services
961N/A ServiceDescriptor* serviceList = NULL;
961N/A int nbServices = -1;
1298N/A
1298N/A strcpy(serviceName, "");
1298N/A
1878N/A debug("Attempting to get the service name assuming command to run is '%s'.",
1878N/A cmdToRun);
1298N/A
961N/A returnValue = getServiceList(&serviceList, &nbServices);
961N/A
961N/A // go through the list of services and search for the service name
961N/A // whose display name is [displayName]
961N/A if (returnValue == SERVICE_RETURN_OK)
961N/A {
961N/A int i;
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A if (nbServices > 0)
961N/A {
961N/A for (i = 0; i<nbServices; i++)
961N/A {
961N/A ServiceDescriptor curService = serviceList[i];
961N/A if (curService.cmdToRun != NULL)
961N/A {
961N/A if (_stricmp(cmdToRun, curService.cmdToRun) == 0)
961N/A {
961N/A if (strlen(curService.serviceName) < MAX_SERVICE_NAME)
961N/A {
961N/A // This function assumes that there are at least
961N/A // MAX_SERVICE_NAME (256) characters reserved in
961N/A // servicename.
961N/A sprintf(serviceName, curService.serviceName);
961N/A returnValue = SERVICE_RETURN_OK;
961N/A }
1295N/A else
1295N/A {
1878N/A debug("The service name found is too long: '%s'",
1878N/A curService.serviceName);
1295N/A }
961N/A break;
961N/A }
961N/A }
961N/A }
961N/A free (serviceList);
961N/A }
961N/A }
961N/A else
961N/A {
961N/A debug("getServiceName: could not get service list.");
961N/A }
1298N/A
1298N/A debug("The service name was found to be '%s'.", serviceName);
1878N/A
961N/A return returnValue;
961N/A
961N/A} // getServiceName
961N/A
961N/A// ----------------------------------------------------
961N/A// Set the current status for the service.
961N/A//
961N/A// statusToSet current service status to set
961N/A// win32ExitCode determine which exit code to use
961N/A// serviceExitCode service code to return in case win32ExitCode says so
961N/A// checkPoint incremental value use to report progress during a lenghty
961N/A// operation (start, stop...).
961N/A// waitHint estimated time required for a pending operation (in ms); if
961N/A// the service has not updated the checkpoint or change the state then
961N/A// the service controler thinks the service should be stopped!
961N/A// serviceStatusHandle the handle used to set the service status
961N/A// The functions returns SERVICE_RETURN_OK if we could start the service
961N/A// and SERVICE_RETURN_ERROR otherwise.
961N/A// ----------------------------------------------------
961N/A
961N/AServiceReturnCode updateServiceStatus (
961N/ADWORD statusToSet,
961N/ADWORD win32ExitCode,
961N/ADWORD serviceExitCode,
961N/ADWORD checkPoint,
961N/ADWORD waitHint,
961N/ASERVICE_STATUS_HANDLE *serviceStatusHandle
961N/A)
961N/A{
961N/A ServiceReturnCode returnValue;
961N/A
1298N/A
1298N/A
961N/A // elaborate service type:
961N/A // SERVICE_WIN32_OWN_PROCESS means this is not a driver and there is
961N/A // only one service in the process
961N/A DWORD serviceType = SERVICE_WIN32_OWN_PROCESS;
961N/A
961N/A // elaborate the commands supported by the service:
961N/A // - STOP customer has performed a stop-ds (or NET STOP)
961N/A // - SHUTDOWN the system is rebooting
5025N/A // - INTERROGATE service controler can interrogate the service
961N/A // - No need to support PAUSE/CONTINUE
961N/A //
961N/A // Note: INTERROGATE *must* be supported by the service handler
961N/A DWORD controls;
961N/A SERVICE_STATUS serviceStatus;
961N/A BOOL success;
1298N/A
1298N/A debug("Updating the service status. statusToSet=%d win32ExitCode=%d serviceExitCode=%d checkPoint=%d waitHint=%d",
1298N/A statusToSet, win32ExitCode, serviceExitCode,
1298N/A checkPoint, waitHint);
1878N/A
961N/A if (statusToSet == SERVICE_START_PENDING)
961N/A {
5025N/A debug("Service start pending: no controls accepted.");
961N/A // do not accept any command when the service is starting up...
961N/A controls = SERVICE_ACCEPT_NONE;
961N/A }
961N/A else
961N/A {
961N/A controls =
961N/A SERVICE_ACCEPT_STOP
961N/A | SERVICE_ACCEPT_SHUTDOWN
961N/A | SERVICE_CONTROL_INTERROGATE;
961N/A }
961N/A
961N/A // fill in the status structure
961N/A serviceStatus.dwServiceType = serviceType;
961N/A serviceStatus.dwCurrentState = statusToSet;
961N/A serviceStatus.dwControlsAccepted = controls;
961N/A serviceStatus.dwWin32ExitCode = win32ExitCode;
961N/A serviceStatus.dwServiceSpecificExitCode = serviceExitCode;
961N/A serviceStatus.dwCheckPoint = checkPoint;
961N/A serviceStatus.dwWaitHint = waitHint;
961N/A
961N/A
961N/A // set the service status
961N/A
961N/A success = SetServiceStatus(
961N/A *serviceStatusHandle,
961N/A &serviceStatus
961N/A );
961N/A
961N/A if (!success)
961N/A {
1878N/A debugError("Failed to set the service status. Last error = %d.",
1878N/A GetLastError());
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A }
961N/A else
961N/A {
961N/A returnValue = SERVICE_RETURN_OK;
961N/A }
961N/A
961N/A return returnValue;
961N/A} // updateServiceStatus
961N/A
961N/A// ----------------------------------------------------
961N/A// This function is the "main" of the service. It has been registered
961N/A// to the SCM by the main right after the service has been started through
961N/A// NET START command.
961N/A//
961N/A// The job of the serviceMain is
961N/A//
961N/A// 1- to register a handler to manage the commands STOP, PAUSE, CONTINUE,
961N/A// SHUTDOWN and INTERROGATE sent by the SCM
961N/A// 2- to start the main application using "start-ds"
961N/A//
961N/A// The serviceMain will return only when the service is terminated.
961N/A// ----------------------------------------------------
961N/Avoid serviceMain(int argc, char* argv[])
961N/A{
961N/A // returned status
1295N/A char cmdToRun[COMMAND_SIZE];
961N/A char serviceName[MAX_SERVICE_NAME];
961N/A ServiceReturnCode code;
961N/A // a checkpoint value indicate the progress of an operation
961N/A DWORD checkPoint = CHECKPOINT_FIRST_VALUE;
961N/A SERVICE_STATUS_HANDLE serviceStatusHandle;
5025N/A BOOL running;
961N/A
1298N/A // __debugbreak();
1298N/A
5385N/A debug("serviceMain");
1878N/A
961N/A code = createServiceBinPath(cmdToRun);
961N/A
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A code = getServiceName(cmdToRun, serviceName);
1295N/A if (code != SERVICE_RETURN_OK)
1295N/A {
1295N/A debug("serviceMain: could not get service name.");
1295N/A }
1295N/A }
1295N/A else
1295N/A {
1295N/A debug("serviceMain: failed to create service bin path.");
961N/A }
961N/A
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A // first register the service control handler to the SCM
961N/A code = registerServiceHandler(serviceName,
961N/A (LPHANDLER_FUNCTION) serviceHandler,
961N/A &serviceStatusHandle);
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A _serviceStatusHandle = &serviceStatusHandle;
961N/A }
1295N/A else
1295N/A {
1295N/A debug("serviceMain: failed to register service handler.");
1295N/A }
961N/A }
961N/A
961N/A
961N/A // update the service status to START_PENDING
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A _serviceCurStatus = SERVICE_START_PENDING;
961N/A code = updateServiceStatus (
961N/A SERVICE_START_PENDING,
961N/A NO_ERROR,
961N/A 0,
961N/A checkPoint++,
961N/A TIMEOUT_CREATE_EVENT,
961N/A _serviceStatusHandle);
961N/A }
961N/A
961N/A // create an event to signal the application termination
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A _terminationEvent = CreateEvent(
961N/A NULL, // handle is not inherited by the child process
961N/A TRUE, // event has to be reset manually after a signal
961N/A FALSE, // initial state is "non signaled"
961N/A NULL // the event has no name
961N/A );
961N/A }
961N/A
5025N/A if (isServerRunning(&running, TRUE) != SERVICE_RETURN_OK)
961N/A {
5025N/A running = FALSE;
961N/A }
961N/A
5025N/A // start the application if not already started
5025N/A if (!running && code == SERVICE_RETURN_OK)
961N/A {
961N/A WORD argCount = 1;
961N/A const char *argc[] = {_instanceDir};
961N/A code = doStartApplication();
961N/A
961N/A switch (code)
961N/A {
961N/A case SERVICE_RETURN_OK:
5025N/A // start is ok: do nothing for the moment.
961N/A break;
961N/A
961N/A default:
5385N/A debugError("serviceMain: doStartApplication() failed");
961N/A code = SERVICE_RETURN_ERROR;
961N/A _serviceCurStatus = SERVICE_STOPPED;
961N/A updateServiceStatus (
5025N/A _serviceCurStatus,
5025N/A ERROR_SERVICE_SPECIFIC_ERROR,
5025N/A -1,
5025N/A CHECKPOINT_NO_ONGOING_OPERATION,
5025N/A TIMEOUT_NONE,
5025N/A _serviceStatusHandle);
961N/A reportLogEvent(
5025N/A EVENTLOG_ERROR_TYPE,
5025N/A WIN_EVENT_ID_SERVER_START_FAILED,
5025N/A argCount, argc
961N/A );
961N/A }
961N/A }
961N/A else
961N/A {
961N/A updateServiceStatus (
5025N/A _serviceCurStatus,
5025N/A ERROR_SERVICE_SPECIFIC_ERROR,
5025N/A 0,
5025N/A CHECKPOINT_NO_ONGOING_OPERATION,
5025N/A TIMEOUT_NONE,
5025N/A _serviceStatusHandle);
961N/A }
961N/A
961N/A // if all is ok wait for the application to die before we leave
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
5025N/A BOOL updatedRunningStatus = FALSE;
5025N/A DWORD returnValue;
5025N/A int refreshPeriodSeconds = 10;
5385N/A char *refreshPeriodEnv = getenv("OPENDJ_WINDOWS_SERVICE_REFRESH_PERIOD");
5025N/A if (refreshPeriodEnv != NULL)
5025N/A {
5025N/A refreshPeriodSeconds = (int)strtol(refreshPeriodEnv, (char **)NULL, 10);
5025N/A if (refreshPeriodSeconds < 0)
5025N/A {
5025N/A refreshPeriodSeconds = 10;
5025N/A }
5025N/A }
5025N/A debug("Refresh period in seconds is %d.", refreshPeriodSeconds);
5025N/A while (TRUE)
5025N/A {
5025N/A if (refreshPeriodSeconds == 0 && updatedRunningStatus)
5025N/A {
5025N/A returnValue = WaitForSingleObject (_terminationEvent, INFINITE);
5025N/A break;
5025N/A }
5025N/A else
5025N/A {
5025N/A running = FALSE;
5025N/A if (updatedRunningStatus)
5025N/A {
5025N/A Sleep(5000);
5025N/A }
5025N/A else
5025N/A {
5025N/A returnValue = WaitForSingleObject (_terminationEvent,
5025N/A refreshPeriodSeconds * 1000);
5025N/A if (returnValue == WAIT_OBJECT_0)
5025N/A {
5025N/A debug("The application has exited.");
5025N/A break;
5025N/A }
5025N/A }
5025N/A code = isServerRunning(&running, FALSE);
5025N/A if (code != SERVICE_RETURN_OK)
5025N/A {
5025N/A debug("checking in serviceMain: error interrogating status.");
5025N/A }
5025N/A else if (running)
5025N/A {
5025N/A _serviceCurStatus = SERVICE_RUNNING;
5025N/A if (!updatedRunningStatus)
5025N/A {
5025N/A WORD argCount = 1;
5025N/A const char *argc[] = {_instanceDir};
5025N/A updateServiceStatus (
5025N/A _serviceCurStatus,
5025N/A NO_ERROR,
5025N/A 0,
5025N/A checkPoint ++,
5025N/A TIMEOUT_NONE,
5025N/A _serviceStatusHandle
5025N/A );
5025N/A reportLogEvent(
5025N/A EVENTLOG_SUCCESS,
5025N/A WIN_EVENT_ID_SERVER_STARTED,
5025N/A argCount, argc
5025N/A );
5025N/A updatedRunningStatus = TRUE;
5025N/A }
5025N/A }
5025N/A else
5025N/A {
5025N/A WORD argCount = 1;
5025N/A const char *argc[] = {_instanceDir};
5025N/A _serviceCurStatus = SERVICE_STOPPED;
5025N/A debug("checking in serviceMain serviceHandler: service stopped.");
5025N/A
5025N/A updateServiceStatus (
5025N/A _serviceCurStatus,
5025N/A ERROR_SERVICE_SPECIFIC_ERROR,
5025N/A -1,
5025N/A CHECKPOINT_NO_ONGOING_OPERATION,
5025N/A TIMEOUT_NONE,
5025N/A _serviceStatusHandle);
5025N/A reportLogEvent(
5025N/A EVENTLOG_ERROR_TYPE,
5025N/A WIN_EVENT_ID_SERVER_STOPPED_OUTSIDE_SCM,
5025N/A argCount, argc);
5025N/A break;
5025N/A }
5025N/A }
5025N/A }
961N/A }
961N/A // update the service status to STOPPED if it's not already done
961N/A if ((_serviceCurStatus != SERVICE_STOPPED) &&
5025N/A (_serviceStatusHandle != NULL))
961N/A {
961N/A _serviceCurStatus = SERVICE_STOPPED;
961N/A updateServiceStatus (
5025N/A _serviceCurStatus,
5025N/A NO_ERROR,
5025N/A 0,
5025N/A CHECKPOINT_NO_ONGOING_OPERATION,
5025N/A TIMEOUT_NONE,
5025N/A _serviceStatusHandle
5025N/A );
961N/A }
5385N/A debug("serviceMain returning.");
961N/A} // serviceMain
961N/A
961N/A
961N/A// ----------------------------------------------------
961N/A// Notify the serviceMain that service is now terminated.
961N/A//
961N/A// terminationEvent the event upon which serviceMain is blocked
961N/A// ----------------------------------------------------
961N/Avoid doTerminateService(HANDLE terminationEvent)
961N/A{
1298N/A debug("Faking a service termination so serviceMain can return.");
961N/A SetEvent(terminationEvent);
961N/A return;
961N/A
961N/A} // doTerminateService
961N/A
961N/A// ----------------------------------------------------
961N/A// This function is the handler of the service. It is processing the
961N/A// commands send by the SCM. Commands can be: STOP, PAUSE, CONTINUE,
961N/A// SHUTDOWN and INTERROGATE.
961N/A// controlCode the code of the command
961N/A// ----------------------------------------------------
961N/A
961N/Avoid serviceHandler(DWORD controlCode)
961N/A{
961N/A ServiceReturnCode code;
961N/A DWORD checkpoint;
961N/A BOOL running;
1298N/A debug("serviceHandler called with controlCode=%d.", controlCode);
961N/A switch (controlCode)
961N/A {
961N/A case SERVICE_CONTROL_SHUTDOWN:
961N/A // If system is shuting down then stop the service
961N/A // -> no break here
1298N/A debug("serviceHandler: shutdown");
961N/A case SERVICE_CONTROL_STOP:
961N/A {
961N/A // update service status to STOP_PENDING
1298N/A debug("serviceHandler: stop");
961N/A _serviceCurStatus = SERVICE_STOP_PENDING;
961N/A checkpoint = CHECKPOINT_FIRST_VALUE;
961N/A updateServiceStatus (
961N/A _serviceCurStatus,
961N/A NO_ERROR,
961N/A 0,
961N/A checkpoint++,
961N/A TIMEOUT_STOP_SERVICE,
961N/A _serviceStatusHandle
961N/A );
961N/A
961N/A // let's try to stop the application whatever may be the status above
961N/A // (best effort mode)
961N/A code = doStopApplication();
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A WORD argCount = 1;
961N/A const char *argc[] = {_instanceDir};
961N/A _serviceCurStatus = SERVICE_STOPPED;
961N/A updateServiceStatus (
961N/A _serviceCurStatus,
961N/A NO_ERROR,
961N/A 0,
961N/A CHECKPOINT_NO_ONGOING_OPERATION,
961N/A TIMEOUT_NONE,
961N/A _serviceStatusHandle
961N/A );
961N/A
961N/A // again, let's ignore the above status and
961N/A // notify serviceMain that service has stopped
961N/A doTerminateService (_terminationEvent);
961N/A reportLogEvent(
961N/A EVENTLOG_SUCCESS,
961N/A WIN_EVENT_ID_SERVER_STOP,
961N/A argCount, argc
961N/A );
961N/A }
961N/A else
961N/A {
961N/A WORD argCount = 1;
961N/A const char *argc[] = {_instanceDir};
5385N/A debug("serviceHandler: The server could not be stopped.");
961N/A // We could not stop the server
961N/A reportLogEvent(
961N/A EVENTLOG_ERROR_TYPE,
961N/A WIN_EVENT_ID_SERVER_STOP_FAILED,
961N/A argCount, argc
961N/A );
961N/A }
961N/A break;
961N/A }
961N/A
961N/A
961N/A // Request to pause the service
961N/A // ----------------------------
961N/A case SERVICE_CONTROL_PAUSE:
1295N/A // not supported
1295N/A debug("serviceHandler: pause.");
1295N/A break;
961N/A
961N/A // Request to resume the service
961N/A // -----------------------------
961N/A case SERVICE_CONTROL_CONTINUE:
1295N/A // not supported
1295N/A debug("serviceHandler: continue.");
1295N/A break;
961N/A
961N/A // Interrogate the service status
961N/A // ------------------------------
961N/A case SERVICE_CONTROL_INTERROGATE:
1295N/A debug("serviceHandler: interrogate.");
5025N/A code = isServerRunning(&running, TRUE);
1295N/A if (code != SERVICE_RETURN_OK)
1295N/A {
1295N/A debug("serviceHandler: error interrogating.");
1295N/A }
1295N/A else if (running)
1295N/A {
1295N/A _serviceCurStatus = SERVICE_RUNNING;
1295N/A debug("serviceHandler: service running.");
1295N/A }
1295N/A else
1295N/A {
1295N/A _serviceCurStatus = SERVICE_STOPPED;
1295N/A debug("serviceHandler: service stopped.");
1295N/A }
1295N/A updateServiceStatus (
1295N/A _serviceCurStatus,
1295N/A NO_ERROR,
1295N/A 0,
1295N/A CHECKPOINT_NO_ONGOING_OPERATION,
1295N/A TIMEOUT_NONE,
1295N/A _serviceStatusHandle
1295N/A );
961N/A break;
961N/A
961N/A // Other codes are ignored
961N/A default:
961N/A
961N/A break;
961N/A }
5385N/A debug("serviceHandler returning.");
961N/A} // serviceHandler
961N/A
961N/A// ---------------------------------------------------------------
961N/A// Retrieve the binaryPathName from the SCM database for a given service.
961N/A//
961N/A// scm is the SCM handler (must not be NULL)
961N/A// serviceName the name of the service.
1878N/A// It is up to the caller of the function to allocate at least COMMAND_SIZE
1878N/A// bytes in binPathName.
961N/A// The function returns SERVICE_RETURN_OK if we could create the binary
961N/A// path name and SERVICE_RETURN_ERROR otherwise.
961N/A// ---------------------------------------------------------------
961N/A
961N/AServiceReturnCode getBinaryPathName(HANDLE scm, char* serviceName,
961N/Achar* binPathName)
961N/A{
961N/A ServiceReturnCode returnValue;
961N/A
961N/A // handle to the service
961N/A SC_HANDLE myService = NULL;
961N/A
961N/A
961N/A BOOL getConfigOk = FALSE;
961N/A DWORD configSize = 4096;
961N/A LPQUERY_SERVICE_CONFIG serviceConfig =
961N/A (LPQUERY_SERVICE_CONFIG)malloc(configSize);
961N/A
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A
961N/A // if SCM exists then retrieve the config info of the service
961N/A if (scm != NULL)
961N/A {
961N/A myService = OpenService(
961N/A scm,
961N/A serviceName,
961N/A SERVICE_QUERY_CONFIG
961N/A );
961N/A }
961N/A
1298N/A if (myService == NULL)
1298N/A {
5385N/A debugError("getBinaryPathName: Failed to open the service '%s'.", serviceName);
1298N/A }
1298N/A else
961N/A {
961N/A while (!getConfigOk)
961N/A {
961N/A DWORD bytesNeeded;
961N/A
961N/A getConfigOk = QueryServiceConfig(
961N/A myService,
961N/A serviceConfig,
961N/A configSize,
961N/A &bytesNeeded
961N/A );
961N/A
961N/A if (!getConfigOk)
961N/A {
961N/A DWORD errCode = GetLastError();
961N/A if (errCode == ERROR_INSUFFICIENT_BUFFER)
961N/A {
1298N/A // buffer not big enough...
961N/A configSize += bytesNeeded;
961N/A serviceConfig =
961N/A (LPQUERY_SERVICE_CONFIG)realloc(serviceConfig, configSize);
961N/A continue;
961N/A }
961N/A else
961N/A {
5385N/A debug("getBinaryPathName: error calling QueryServiceConfig. Code [%d]",
1878N/A errCode);
961N/A break;
961N/A }
961N/A }
961N/A else
961N/A {
1295N/A if (strlen(serviceConfig->lpBinaryPathName) < COMMAND_SIZE)
961N/A {
961N/A sprintf(binPathName, serviceConfig->lpBinaryPathName);
961N/A returnValue = SERVICE_RETURN_OK;
961N/A }
1295N/A else
1295N/A {
5385N/A debug("getBinaryPathName: the length of the binary path name is too big. serviceName='%s', binaryPath='%s'",
1878N/A serviceName, serviceConfig->lpBinaryPathName);
1295N/A }
961N/A }
961N/A }
5385N/A if (!CloseServiceHandle(myService))
5385N/A {
5385N/A debug("getBinaryPathName: error closing handle of service. Code [%d]",
5385N/A GetLastError());
5385N/A }
961N/A }
961N/A
961N/A // free buffers
961N/A if (serviceConfig != NULL)
961N/A {
961N/A free(serviceConfig);
961N/A }
961N/A
961N/A return returnValue;
961N/A} // getBinaryPathName
961N/A
961N/A// ---------------------------------------------------------------
3899N/A// Returns the list of Windows services being created on the current host.
961N/A// The function allocates the memory for the returned buffer.
961N/A// serviceList contains the list of services.
961N/A// nbServices the number of services returned in the list.
961N/A// The functions returns SERVICE_RETURN_OK if we could create the service
961N/A// list and SERVICE_RETURN_ERROR otherwise.
961N/A// ---------------------------------------------------------------
961N/A
961N/AServiceReturnCode getServiceList(ServiceDescriptor** serviceList,
961N/Aint *nbServices)
961N/A{
961N/A ServiceReturnCode returnValue;
961N/A
961N/A // open Service Control Manager
961N/A SC_HANDLE scm = NULL;
961N/A // get the list of services being configured in the SCM database
961N/A // 1- first try with a single data structure ENUM_SERVICE_STATUS
961N/A ENUM_SERVICE_STATUS serviceData;
961N/A ENUM_SERVICE_STATUS* lpServiceData = &serviceData;
961N/A DWORD dataSize = sizeof (serviceData);
961N/A DWORD neededSize;
961N/A DWORD resumeHandle = 0;
961N/A unsigned long nbSvc = 0;
961N/A
961N/A if (openScm(SC_MANAGER_ENUMERATE_SERVICE, &scm) == SERVICE_RETURN_OK)
961N/A {
961N/A BOOL svcStatusOk = EnumServicesStatus(
961N/A scm, // handle to the SCM
961N/A SERVICE_WIN32, // for OWN_PROCESS | SHARE_PROCESS
961N/A SERVICE_STATE_ALL, // all services (runing & stopped)
961N/A &serviceData, // output buffer
961N/A dataSize, // output buffer size
961N/A &neededSize, // sized needed to get the entries
961N/A &nbSvc, // number of services
961N/A &resumeHandle // next service entry to read
961N/A );
961N/A
961N/A if (! svcStatusOk)
961N/A {
961N/A DWORD lastError = GetLastError();
961N/A if (lastError != ERROR_MORE_DATA)
961N/A {
1298N/A debug("getServiceList: generic error. Code [%d]", lastError);
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A }
961N/A else
961N/A {
961N/A // buffer is not big enough: try again with a proper size
961N/A dataSize += neededSize;
961N/A lpServiceData = (ENUM_SERVICE_STATUS*)calloc(
961N/A dataSize, sizeof(ENUM_SERVICE_STATUS));
961N/A
961N/A svcStatusOk = EnumServicesStatus(
961N/A scm, // handle to the SCM
961N/A SERVICE_WIN32, // for OWN_PROCESS | SHARE_PROCESS
961N/A SERVICE_STATE_ALL, // all services (running & stopped)
961N/A lpServiceData, // output buffer
961N/A dataSize, // output buffer size
961N/A &neededSize, // sized needed to get the entries
961N/A &nbSvc, // number of services
961N/A &resumeHandle // next service entry to read
961N/A );
961N/A
961N/A if (! svcStatusOk)
961N/A {
961N/A DWORD lastError = GetLastError();
961N/A if (lastError != ERROR_MORE_DATA)
961N/A {
961N/A returnValue = SERVICE_RETURN_ERROR;
1878N/A debug("getServiceList: second try generic error. Code [%d]",
1878N/A lastError);
961N/A }
961N/A else
961N/A {
961N/A // Data buffer is not large enough. This case should
961N/A // never happen as proper buffer size has been
961N/A // provided!...
961N/A debug("getServiceList: buffer error");
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A }
961N/A }
961N/A else
961N/A {
961N/A returnValue = SERVICE_RETURN_OK;
961N/A }
961N/A }
961N/A }
961N/A else
961N/A {
961N/A returnValue = SERVICE_RETURN_OK;
961N/A }
961N/A }
961N/A else
961N/A {
1295N/A debug("getServiceList: error opening scm.");
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A }
961N/A
961N/A // now elaborate the list of service to return...
961N/A if (returnValue == SERVICE_RETURN_OK)
961N/A {
961N/A int i;
961N/A int aux = (int)nbSvc;
961N/A ServiceDescriptor* l;
961N/A
961N/A ENUM_SERVICE_STATUS* curService = lpServiceData;
961N/A
961N/A *nbServices = aux;
961N/A if (aux > 0)
961N/A {
1295N/A char binPath[COMMAND_SIZE];
961N/A l = (ServiceDescriptor*)calloc(sizeof(ServiceDescriptor), aux);
961N/A for (i = 0; i < aux; i++)
961N/A {
1298N/A l[i].serviceName = _strdup(curService->lpServiceName);
1298N/A l[i].displayName = _strdup(curService->lpDisplayName);
961N/A
961N/A if (getBinaryPathName(scm, l[i].serviceName, binPath) ==
961N/A SERVICE_RETURN_OK)
961N/A {
1298N/A l[i].cmdToRun = _strdup(binPath);
961N/A }
1298N/A else
1295N/A {
1878N/A debug("Error getting binary path name of service: %s",
1878N/A l[i].serviceName);
1295N/A }
961N/A curService++;
961N/A }
961N/A *serviceList = l;
961N/A }
961N/A }
961N/A
961N/A // close the handle to the SCM
961N/A if (scm != NULL)
961N/A {
961N/A CloseServiceHandle (scm);
961N/A // free the result buffer
961N/A if (lpServiceData != NULL)
961N/A {
961N/A free (lpServiceData);
961N/A }
961N/A }
961N/A
961N/A return returnValue;
961N/A} // getServiceList
961N/A
961N/A// ---------------------------------------------------------------
961N/A// Function used to know if a given service name is in use or not.
961N/A// Returns SERVICE_IN_USE if the provided service name is in use.
961N/A// Returns NOT_SERVICE_IN_USE if the provided service name is not in use.
961N/A// Returns SERVICE_RETURN_ERROR if the function could not determine if the
961N/A// service name is in use or not.
961N/A// ---------------------------------------------------------------
961N/A
961N/AServiceReturnCode serviceNameInUse(char* serviceName)
961N/A{
961N/A ServiceReturnCode returnValue;
961N/A
961N/A // retrieve list of services
961N/A ServiceDescriptor* serviceList = NULL;
961N/A ServiceDescriptor curService;
961N/A int nbServices = -1;
961N/A int i;
961N/A
1298N/A debug("Determining if service name '%s' is in use.", serviceName);
1878N/A
961N/A // go through the list of services and search for the service name
961N/A if (getServiceList(&serviceList, &nbServices) == SERVICE_RETURN_OK)
961N/A {
961N/A returnValue = SERVICE_NOT_IN_USE;
961N/A
961N/A if (nbServices > 0)
961N/A {
961N/A for (i = 0; i < nbServices && (returnValue == SERVICE_NOT_IN_USE);
961N/A i++)
961N/A {
961N/A curService = serviceList[i];
961N/A if (curService.serviceName == NULL)
961N/A {
961N/A debug("The service name is NULL.\n");
961N/A }
961N/A else
961N/A {
961N/A if (strcmp (serviceName, curService.serviceName) == 0)
961N/A {
961N/A // found the service!
1298N/A debug("The service name '%s' is in use.", serviceName);
961N/A returnValue = SERVICE_IN_USE;
961N/A }
961N/A }
961N/A }
961N/A free(serviceList);
961N/A }
961N/A }
961N/A else
961N/A {
1878N/A debugError("Could not determine if the service name '%s' is in use because listing the services failed.",
1878N/A serviceName);
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A }
961N/A return returnValue;
961N/A} // serviceNameInUse
961N/A
961N/A// ---------------------------------------------------------------
5385N/A// Build a service name for OpenDJ and make sure
961N/A// the service name is unique on the system. To achieve this requirement
5385N/A// the service name looks like <baseName> for the first OpenDJ and
969N/A// <baseName>-n if there are more than one.
961N/A//
961N/A// The functions returns SERVICE_RETURN_OK if we could create a service
961N/A// name and SERVICE_RETURN_ERROR otherwise.
961N/A// The serviceName buffer must be allocated OUTSIDE the function and its
961N/A// minimum size must be of 256 (the maximum string length of a Service Name).
961N/A// ---------------------------------------------------------------
961N/A
969N/AServiceReturnCode createServiceName(char* serviceName, char* baseName)
961N/A{
961N/A ServiceReturnCode returnValue = SERVICE_RETURN_OK;
961N/A int i = 1;
961N/A BOOL ended = FALSE;
961N/A ServiceReturnCode nameInUseResult;
1298N/A strcpy(serviceName, "");
961N/A while (!ended)
961N/A {
961N/A if (i == 1)
961N/A {
969N/A sprintf(serviceName, baseName);
961N/A }
961N/A else
961N/A {
969N/A sprintf(serviceName, "%s-%d", baseName, i);
961N/A }
961N/A
961N/A nameInUseResult = serviceNameInUse(serviceName);
961N/A
961N/A if (nameInUseResult == SERVICE_IN_USE)
961N/A {
961N/A // this service name is already in use: try another one...
961N/A i++;
961N/A }
961N/A else if (nameInUseResult == SERVICE_NOT_IN_USE)
961N/A {
961N/A // this service name is not used so it's a good candidate
961N/A ended = TRUE;
961N/A }
961N/A else
961N/A {
961N/A // an error occurred checking the service name
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A ended = TRUE;
961N/A }
961N/A }
961N/A
1298N/A debug("createServiceName returning serviceName='%s' and returnValue=%d",
1878N/A serviceName, returnValue);
1298N/A
961N/A return returnValue;
961N/A} // createServiceName
961N/A
961N/A
961N/A// ---------------------------------------------------------------
961N/A// Create a service in the SCM database. Once the service is created,
961N/A// we can view it with "service list".
961N/A// displayName is the display name of the service
961N/A// description is the description of the service
961N/A// cmdToRun is the command to be run by the SCM upon NET START
961N/A//
961N/A// The function returns SERVICE_RETURN_OK if we could create the service and
961N/A// SERVICE_RETURN_ERROR otherwise.
961N/A// ---------------------------------------------------------------
961N/A
961N/AServiceReturnCode createServiceInScm(char* displayName, char* description,
961N/Achar* cmdToRun)
961N/A{
961N/A ServiceReturnCode returnValue;
961N/A SC_HANDLE scm = NULL;
961N/A SC_HANDLE myService = NULL;
961N/A
961N/A // local vars
961N/A // - serviceName is the service name
961N/A char* serviceName = (char*) calloc(1, MAX_SERVICE_NAME);
961N/A
969N/A // elaborate the service name based on the displayName provided
969N/A returnValue = createServiceName(serviceName, displayName);
961N/A
961N/A // create the service
961N/A if (returnValue == SERVICE_RETURN_OK)
961N/A {
1878N/A if (openScm(SC_MANAGER_ALL_ACCESS, &scm) != SERVICE_RETURN_OK)
961N/A {
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A debug("createServiceInScm: openScm did not work.");
961N/A }
961N/A }
961N/A else
961N/A {
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A debug("createServiceInScm: createServiceName did not work.");
961N/A }
961N/A
961N/A if (returnValue == SERVICE_RETURN_OK)
961N/A {
1298N/A debug("Creating the service '%s'.", serviceName);
961N/A myService = CreateService(
961N/A scm,
961N/A serviceName, // name of service
969N/A serviceName, // service name to display
961N/A SERVICE_ALL_ACCESS, // desired access
961N/A SERVICE_WIN32_OWN_PROCESS, // service type
961N/A SERVICE_AUTO_START, // start service during
961N/A // system startup
961N/A SERVICE_ERROR_NORMAL, // error control type
961N/A cmdToRun, // path to service's binary
961N/A NULL, // no load ordering group
961N/A NULL, // no tag identifier
961N/A NULL, // no dependencies
961N/A NULL, // LocalSystem account
961N/A NULL // no password
961N/A );
961N/A }
961N/A
961N/A if ((returnValue == SERVICE_RETURN_OK) && (myService == NULL))
961N/A {
961N/A DWORD errCode = GetLastError();
1878N/A debugError("Failed to create the service '%s'. Last error = %d.",
1878N/A serviceName, errCode);
961N/A if (errCode == ERROR_DUPLICATE_SERVICE_NAME)
961N/A {
961N/A returnValue = DUPLICATED_SERVICE_NAME;
961N/A }
961N/A else if (errCode == ERROR_SERVICE_EXISTS)
961N/A {
961N/A returnValue = SERVICE_ALREADY_EXISTS;
961N/A }
961N/A else
961N/A {
1878N/A if (errCode == ERROR_INVALID_HANDLE)
1878N/A {
1878N/A debugError("The handle seems to be invalid.");
1878N/A }
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A }
961N/A }
961N/A
961N/A // add description field
961N/A if (returnValue == SERVICE_RETURN_OK)
961N/A {
961N/A BOOL success;
961N/A SERVICE_DESCRIPTION serviceDescription;
961N/A serviceDescription.lpDescription = description;
961N/A success = ChangeServiceConfig2(
961N/A myService,
961N/A SERVICE_CONFIG_DESCRIPTION,
961N/A (LPVOID) &serviceDescription
961N/A );
961N/A
961N/A if (!success)
961N/A {
1878N/A debugError(
1878N/A "Failed to add a description to the service '%s'. Last error = %d.",
1878N/A serviceName, GetLastError());
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A }
961N/A }
961N/A
961N/A // close handles
961N/A if (myService != NULL)
961N/A {
961N/A CloseServiceHandle (myService);
961N/A }
961N/A
961N/A if (scm != NULL)
961N/A {
961N/A CloseServiceHandle (scm);
961N/A }
961N/A
961N/A // free names
961N/A if (serviceName != NULL)
961N/A {
961N/A free (serviceName);
961N/A }
961N/A
1298N/A debug("createServiceInScm returning %d.", returnValue);
1878N/A
961N/A return returnValue;
961N/A} // createServiceInScm
961N/A
961N/A
961N/A// ---------------------------------------------------------------
961N/A// Remove a service with the name serviceName from SCM.
961N/A// If the service could be removed returns SERVICE_RETURN_OK.
961N/A// If the service cannot be removed because still in use by any process
961N/A// then returned status is SERVICE_MARKED_FOR_DELETION.
961N/A// If an error occurs returns SERVICE_RETURN_ERROR.
961N/A// ---------------------------------------------------------------
961N/AServiceReturnCode removeServiceFromScm(char* serviceName)
961N/A{
961N/A // local vars
961N/A ServiceReturnCode returnValue = SERVICE_RETURN_OK;
961N/A SC_HANDLE scm = NULL;
961N/A SC_HANDLE myService = NULL;
961N/A SERVICE_STATUS serviceStatus;
961N/A
1298N/A debug("Removing service '%s' from the Service Control Manager.", serviceName);
1878N/A
961N/A returnValue = openScm(GENERIC_WRITE, &scm);
961N/A
961N/A // open the service
961N/A if (returnValue == SERVICE_RETURN_OK)
961N/A {
1300N/A debug("About to open service '%s'.", serviceName);
961N/A myService = OpenService(
961N/A scm,
961N/A serviceName,
961N/A SERVICE_ALL_ACCESS | DELETE
961N/A );
1300N/A debug("After opening service myService=%d.", myService);
961N/A if (myService == NULL)
961N/A {
1878N/A debugError("Failed to open the service '%s'. Last error = %d",
1878N/A serviceName, GetLastError());
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A }
961N/A }
961N/A
961N/A if (returnValue == SERVICE_RETURN_OK)
961N/A {
1300N/A BOOL success;
1300N/A debug("About to query the service '%s'.", serviceName);
1300N/A success = QueryServiceStatus(
961N/A myService,
961N/A &serviceStatus
961N/A );
961N/A if (!success)
961N/A {
1878N/A debugError("Failed to query the status for service '%s'. Last error = %d",
1878N/A serviceName, GetLastError());
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A }
961N/A }
961N/A
961N/A // stop the service if necessary
961N/A if (returnValue == SERVICE_RETURN_OK)
961N/A {
1300N/A debug("Successfully queried the service '%s'.", serviceName);
961N/A if (serviceStatus.dwCurrentState != SERVICE_STOPPED)
961N/A {
1298N/A BOOL success;
1298N/A debug("Attempting to stop the service '%s'.", serviceName);
1298N/A success = ControlService (
961N/A myService,
961N/A SERVICE_CONTROL_STOP,
961N/A &serviceStatus
961N/A );
961N/A if (!success)
961N/A {
961N/A DWORD errCode = GetLastError();
1878N/A debugError("Failed to stop the service '%s'. Last error = %d.",
1878N/A serviceName, errCode);
961N/A if (errCode == ERROR_SERVICE_MARKED_FOR_DELETE)
961N/A {
961N/A returnValue = SERVICE_MARKED_FOR_DELETION;
961N/A }
961N/A else
961N/A {
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A }
961N/A }
961N/A else
961N/A {
961N/A Sleep (500);
961N/A }
961N/A }
961N/A }
961N/A
961N/A // remove the service
961N/A if (returnValue == SERVICE_RETURN_OK)
961N/A {
1298N/A BOOL success;
1300N/A debug("Deleting the service '%s'.", serviceName);
1298N/A success = DeleteService (myService);
961N/A if (!success)
961N/A {
961N/A DWORD errCode = GetLastError();
1878N/A debugError("Failed to delete the service '%s'. Last error = %d.",
1878N/A serviceName, errCode);
961N/A if (errCode == ERROR_SERVICE_MARKED_FOR_DELETE)
961N/A {
961N/A returnValue = SERVICE_MARKED_FOR_DELETION;
961N/A }
961N/A else
961N/A {
961N/A returnValue = SERVICE_RETURN_ERROR;
961N/A }
961N/A }
961N/A }
961N/A
961N/A // close handles
961N/A if (myService != NULL)
961N/A {
961N/A CloseServiceHandle (myService);
961N/A }
961N/A
961N/A if (scm != NULL)
961N/A {
961N/A CloseServiceHandle (scm);
961N/A }
961N/A
961N/A return returnValue;
961N/A
961N/A} // removeServiceFromScm
961N/A
961N/A
961N/A// ---------------------------------------------------------------
5385N/A// Function called to create a service for the OpenDJ instance
961N/A// where this executable is installed.
961N/A// The first argument that is passed is the displayName of the service
961N/A// and the second the description,
961N/A//
961N/A// Returns 0 if the service was successfully created.
961N/A// Returns 1 if the service already existed for this instance.
961N/A// Returns 2 if the service name we created already exists.
961N/A// Returns 3 if an error occurred.
961N/A// ---------------------------------------------------------------
961N/Aint createService(char* displayName, char* description)
961N/A{
961N/A int returnCode = 0;
1295N/A char cmdToRun[COMMAND_SIZE];
961N/A ServiceReturnCode code;
961N/A
1878N/A debug("Creating service displayName='%s' description='%s'.", displayName,
1878N/A description);
961N/A code = createServiceBinPath(cmdToRun);
961N/A
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A char serviceName[MAX_SERVICE_NAME];
961N/A code = getServiceName(cmdToRun, serviceName);
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
1298N/A debug("Service '%s' already exists.", displayName);
961N/A // There is a valid serviceName for the command to run, so
5385N/A // OpenDJ is registered as a service.
961N/A code = SERVICE_ALREADY_EXISTS;
961N/A createRegistryKey(serviceName);
961N/A }
961N/A else
961N/A {
1298N/A debug("Could not find service '%s', so creating it now.", displayName);
961N/A // We could not find a serviceName for the command to run, so
961N/A // try to create the service.
961N/A code = createServiceInScm(displayName, description, cmdToRun);
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A code = getServiceName(cmdToRun, serviceName);
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A createRegistryKey(serviceName);
961N/A }
1295N/A else
1295N/A {
1298N/A debug("Could not get a service name for command to run.");
1295N/A }
961N/A }
961N/A }
961N/A }
1295N/A else
1295N/A {
1295N/A debug("createService could not create bin path.");
1295N/A }
961N/A switch (code)
961N/A {
961N/A case SERVICE_RETURN_OK:
961N/A returnCode = 0;
1295N/A debug("Service successfully created.");
961N/A break;
961N/A case SERVICE_ALREADY_EXISTS:
961N/A returnCode = 1;
1295N/A debug("Service already exists.");
961N/A break;
961N/A case DUPLICATED_SERVICE_NAME:
961N/A returnCode = 2;
1295N/A debug("Duplicated service name.");
961N/A break;
961N/A default:
961N/A returnCode = 3;
1295N/A debug("Unexpected error creating service.");
961N/A }
961N/A
961N/A return returnCode;
961N/A} // createService
961N/A
961N/A// ---------------------------------------------------------------
5385N/A// Function called to know if the OpenDJ instance where this
961N/A// executable is installed is running as a service or not.
961N/A// Returns 0 if the instance is running as a service and print the
961N/A// serviceName in the standard output.
961N/A// Returns 1 if the instance is not running as a service.
961N/A// Returns 2 if an error occurred or we cannot determine if Open DS
961N/A// is running as a service or not.
961N/A// ---------------------------------------------------------------
961N/Aint serviceState()
961N/A{
961N/A int returnCode = 0;
1295N/A char cmdToRun[COMMAND_SIZE];
961N/A char serviceName[MAX_SERVICE_NAME];
961N/A ServiceReturnCode code;
961N/A
1298N/A strcpy(serviceName, "");
1295N/A debug("Getting service state.");
961N/A code = createServiceBinPath(cmdToRun);
1878N/A debug("Created the service bin path. code=%d. cmdToRun='%s'.", code,
1878N/A cmdToRun);
961N/A
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A code = getServiceName(cmdToRun, serviceName);
1878N/A
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A // There is a valid serviceName for the command to run, so
5385N/A // OpenDJ is registered as a service.
961N/A fprintf(stdout, serviceName);
961N/A returnCode = 0;
1298N/A debug("Service '%s' is enabled.", serviceName);
961N/A }
961N/A else
961N/A {
961N/A returnCode = 1;
1878N/A debug("Service '%s' is disabled.", serviceName);
961N/A }
961N/A }
961N/A else
961N/A {
961N/A returnCode = 2;
1295N/A debug("An error occurred getting the service status.");
961N/A }
961N/A
961N/A return returnCode;
961N/A} // serviceState
961N/A
969N/A// ---------------------------------------------------------------
969N/A// Function called to remove the service associated with a given
969N/A// service name.
969N/A// Returns 0 if the service was successfully removed.
969N/A// Returns 1 if the service does not exist.
969N/A// Returns 2 if the service was marked for deletion but is still in
969N/A// use.
969N/A// Returns 3 if an error occurred.
969N/A// ---------------------------------------------------------------
969N/Aint removeServiceWithServiceName(char *serviceName)
969N/A{
969N/A int returnCode = 0;
969N/A ServiceReturnCode code = serviceNameInUse(serviceName);
1295N/A
5385N/A debug("Removing service with name %s.", serviceName);
1295N/A
969N/A if (code != SERVICE_IN_USE)
969N/A {
969N/A returnCode = 1;
1295N/A debug("Service does not exist.");
969N/A }
969N/A else
969N/A {
969N/A code = removeServiceFromScm(serviceName);
961N/A
969N/A switch (code)
969N/A {
969N/A case SERVICE_RETURN_OK:
969N/A removeRegistryKey(serviceName);
969N/A returnCode = 0;
1295N/A debug("Service successfully removed.");
969N/A break;
969N/A case SERVICE_MARKED_FOR_DELETION:
969N/A removeRegistryKey(serviceName);
969N/A returnCode = 2;
1295N/A debug("Service marked for deletion.");
969N/A break;
969N/A default:
969N/A returnCode = 3;
1295N/A debug("Unexpected error removing service.");
969N/A }
969N/A }
1295N/A
969N/A return returnCode;
969N/A} // removeServiceWithServiceName
961N/A
961N/A// ---------------------------------------------------------------
5385N/A// Function called to remove the service for the OpenDJ instance
961N/A// where this executable is installed.
961N/A// Returns 0 if the service was successfully removed.
961N/A// Returns 1 if the service does not exist.
961N/A// Returns 2 if the service was marked for deletion but is still in
961N/A// use.
961N/A// Returns 3 if an error occurred.
961N/A// ---------------------------------------------------------------
961N/Aint removeService()
961N/A{
961N/A int returnCode = 0;
1295N/A char cmdToRun[COMMAND_SIZE];
961N/A char serviceName[MAX_SERVICE_NAME];
961N/A ServiceReturnCode code;
961N/A
5385N/A debug("removeService");
961N/A code = createServiceBinPath(cmdToRun);
961N/A
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A code = getServiceName(cmdToRun, serviceName);
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
969N/A returnCode = removeServiceWithServiceName(serviceName);
961N/A }
961N/A else
961N/A {
961N/A returnCode = 1;
961N/A }
961N/A }
961N/A else
961N/A {
961N/A returnCode = 2;
961N/A }
961N/A
5385N/A debug("removeService returning %d.", returnCode);
961N/A return returnCode;
961N/A} // removeService
961N/A
961N/A
969N/A
961N/A// ---------------------------------------------------------------
961N/A// Function called to start the service where this executable is installed.
961N/A// Returns 0 if the service runs.
961N/A// Returns 1 if an error occurred.
961N/A// ---------------------------------------------------------------
961N/A
961N/Aint startService()
961N/A{
961N/A int returnCode;
961N/A char serviceName[MAX_SERVICE_NAME];
1295N/A char cmdToRun[COMMAND_SIZE];
961N/A ServiceReturnCode code;
961N/A
5385N/A debug("startService");
961N/A code = createServiceBinPath(cmdToRun);
961N/A
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A code = getServiceName(cmdToRun, serviceName);
961N/A }
961N/A
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A BOOL success;
961N/A SERVICE_TABLE_ENTRY serviceTable[] =
961N/A {
961N/A {serviceName, (LPSERVICE_MAIN_FUNCTION) serviceMain},
961N/A {NULL, NULL}
961N/A };
961N/A _eventLog = registerEventLog(serviceName);
961N/A
961N/A // register the service to the SCM. The function will return once the
961N/A // service is terminated.
961N/A success = StartServiceCtrlDispatcher(serviceTable);
961N/A if (!success)
961N/A {
961N/A WORD argCount = 2;
961N/A DWORD lastError = GetLastError();
961N/A const char *argc[2];
961N/A argc[0] = _instanceDir;
961N/A if (lastError == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
961N/A {
961N/A argc[1] =
961N/A "startService: StartServiceCtrlDispatcher did not work: \
5025N/AERROR_FAILED_SERVICE_CONTROLLER_CONNECT.";
961N/A }
961N/A else if (lastError == ERROR_INVALID_DATA)
961N/A {
961N/A argc[1] =
961N/A "startService: StartServiceCtrlDispatcher did not work: \
5025N/AERROR_INVALID_DATA.";
961N/A }
961N/A else if (lastError == ERROR_SERVICE_ALREADY_RUNNING)
961N/A {
961N/A argc[1] =
961N/A "startService: StartServiceCtrlDispatcher did not work: \
5025N/AERROR_SERVICE_ALREADY_RUNNING.";
961N/A }
961N/A else
961N/A {
961N/A argc[1] =
961N/A "startService: StartServiceCtrlDispatcher did not work.";
961N/A }
961N/A code = SERVICE_RETURN_ERROR;
961N/A reportLogEvent(
961N/A EVENTLOG_ERROR_TYPE,
961N/A WIN_EVENT_ID_SERVER_START_FAILED,
961N/A argCount, argc
961N/A );
5385N/A debugError("startService: For instance dir '%s', %s", argc[0], argc[1]);
961N/A }
961N/A deregisterEventLog();
961N/A }
961N/A else
961N/A {
961N/A debug("startService: Could not get service name.");
961N/A }
961N/A
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A returnCode = 0;
961N/A }
961N/A else
961N/A {
961N/A returnCode = 1;
961N/A }
961N/A return returnCode;
961N/A
961N/A} // startService
961N/A
961N/A
961N/A
961N/Aint main(int argc, char* argv[])
961N/A{
961N/A char* subcommand;
961N/A int returnCode = 0;
1298N/A int i;
1878N/A
1298N/A updateDebugFlag(argv, argc);
1298N/A
1298N/A debug("main called.");
1298N/A for (i = 0; i < argc; i++) {
1298N/A debug(" argv[%d] = '%s'", i, argv[i]);
1298N/A }
1298N/A
1298N/A // __debugbreak();
1298N/A
961N/A if (argc <= 1)
961N/A {
1295N/A fprintf(stdout,
969N/A "Subcommand required: create, state, remove, start or cleanup.\n");
961N/A returnCode = -1;
961N/A }
961N/A else
961N/A {
961N/A subcommand = argv[1];
961N/A if (strcmp(subcommand, "create") == 0)
961N/A {
961N/A if (argc <= 4)
961N/A {
1295N/A fprintf(stdout,
969N/A "Subcommand create requires instance dir, service name and description.\n");
961N/A returnCode = -1;
961N/A }
961N/A else
961N/A {
1298N/A _instanceDir = _strdup(argv[2]);
961N/A returnCode = createService(argv[3], argv[4]);
961N/A free(_instanceDir);
961N/A }
961N/A }
961N/A else if (strcmp(subcommand, "state") == 0)
961N/A {
961N/A if (argc <= 2)
961N/A {
1295N/A fprintf(stdout,
969N/A "Subcommand state requires instance dir.\n");
961N/A returnCode = -1;
961N/A }
961N/A else
961N/A {
1298N/A _instanceDir = _strdup(argv[2]);
961N/A returnCode = serviceState();
961N/A free(_instanceDir);
961N/A }
961N/A }
961N/A else if (strcmp(subcommand, "remove") == 0)
961N/A {
961N/A if (argc <= 2)
961N/A {
1295N/A fprintf(stdout,
969N/A "Subcommand remove requires instance dir.\n");
961N/A returnCode = -1;
961N/A }
961N/A else
961N/A {
1298N/A _instanceDir = _strdup(argv[2]);
961N/A returnCode = removeService();
961N/A free(_instanceDir);
961N/A }
961N/A }
961N/A else if (strcmp(subcommand, "start") == 0)
961N/A {
961N/A if (argc <= 2)
961N/A {
1295N/A fprintf(stdout,
969N/A "Subcommand start requires instance dir.\n");
961N/A returnCode = -1;
961N/A }
961N/A else
961N/A {
1298N/A _instanceDir = _strdup(argv[2]);
961N/A returnCode = startService();
961N/A free(_instanceDir);
961N/A }
961N/A }
961N/A else if (strcmp(subcommand, "isrunning") == 0)
961N/A {
961N/A if (argc <= 2)
961N/A {
1295N/A fprintf(stdout,
969N/A "Subcommand isrunning requires instance dir.\n");
961N/A returnCode = -1;
961N/A }
961N/A else
961N/A {
961N/A BOOL running;
961N/A ServiceReturnCode code;
1298N/A _instanceDir = _strdup(argv[2]);
5025N/A code = isServerRunning(&running, TRUE);
961N/A if (code == SERVICE_RETURN_OK)
961N/A {
961N/A returnCode = 0;
961N/A }
961N/A else
961N/A {
961N/A returnCode = -1;
961N/A }
961N/A free(_instanceDir);
961N/A }
961N/A
961N/A }
969N/A else if (strcmp(subcommand, "cleanup") == 0)
961N/A {
961N/A if (argc <= 2)
961N/A {
1295N/A fprintf(stdout,
969N/A "Subcommand cleanup requires service name.\n");
961N/A returnCode = -1;
961N/A }
961N/A else
961N/A {
1298N/A char* serviceName = _strdup(argv[2]);
969N/A returnCode = removeServiceWithServiceName(serviceName);
969N/A free(serviceName);
969N/A }
969N/A }
961N/A
961N/A else
961N/A {
1295N/A fprintf(stdout, "Unknown subcommand: [%s]\n", subcommand);
961N/A returnCode = -1;
961N/A }
961N/A }
961N/A
1298N/A debug("main returning %d.", returnCode);
1878N/A
961N/A return returnCode;
961N/A} // main
961N/A