/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file \
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying * information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2013 ForgeRock AS
*/
#include "service.h"
int _serviceCurStatus;
// ----------------------------------------------------
// Register a service handler to the service control dispatcher.
// A service handler will manage the control function such as:
// stop, pause, continue, shutdown, interrogate. The control functions
// are sent by the service control dispatcher upon user request
// (ie. NET STOP)
//
// serviceName the internal name of the service (unique in the system)
// serviceHandler the handler of the service
// serviceStatusHandle the service status handle returned by the SCM
// The functions returns SERVICE_RETURN_OK if we could start the service
// and SERVICE_RETURN_ERROR otherwise.
// ----------------------------------------------------
char* serviceName,
)
{
// register the service to the service control dispatcher (SCM)
);
if (serviceStatusHandle == NULL)
{
}
else
{
}
return returnValue;
} // registerServiceHandler
// ---------------------------------------------------
// Reports a log event of a given type, id and arguments
// serviceBinPath the binary associated with the service.
// The function returns TRUE if the event could be logged and FALSE otherwise.
// ---------------------------------------------------
const char** args)
{
if (argCount > 0)
{
// report the event
_eventLog, // event log handle
eventType, // info, warning, error
WIN_FACILITY_NAME_OPENDJ, // unique category for OPENDJ
NULL, // no user security identifier
argCount, // number of args
0, // raw data size
args, // args
NULL // no raw data
);
}
else
{
// report the event
_eventLog, // event log handle
eventType, // info, warning, error
WIN_FACILITY_NAME_OPENDJ, // unique category for OPENDJ
NULL, // no user security identifier
argCount, // number of args
0, // raw data size
NULL, // args
NULL // no raw data
);
}
return reportOk;
}
// ---------------------------------------------------------------
// Get a handle to the Service Control Manager (SCM).
// accessRights the desired access rights; generic access are:
// - GENERIC_READ use to get the list of services
// - GENERIC_WRITE use to create & remove a service
// - GENERIC_EXECUTE
// - GENERIC_ALL
// scm the handler to the SCM
// The function returns SERVICE_RETURN_OK if we could get the SCM
// and SERVICE_RETURN_ERROR otherwise.
// ---------------------------------------------------------------
{
// open Service Control Manager
NULL, // local machine
NULL, // ServicesActive database
accessRights // desired rights
);
{
debugError("Failed to open the Service Control Manager. Last error = %d",
GetLastError());
}
else
{
debug("Successfully opened the Service Control Manager.");
}
return returnValue;
} // openScm
// ---------------------------------------------------
// Creates the registry key to send events based on the name of the service.
// serviceName the serviceName.
// serviceBinPath the binary associated with the service.
// The function returns TRUE if the key could be registered (or was already
// registered) and FALSE otherwise.
// ---------------------------------------------------
{
// true if the server is already registered
// false as soon as an error occurs
// Create the event source subkey (or open it if it already exists)
long result;
// get the full path to the current executable file: is safe to do it
// here because we already required it to figure out to get the service
// name based on the command to run associated with it.
NULL,
);
// Check whether the Registry Key is already created,
// If so don't create a new one.
0,
KEY_QUERY_VALUE, // to query the values of a registry key.
&hkey // OUT
);
if (result == ERROR_SUCCESS)
{
}
if (success)
{
subkey, //
0, // reserved
NULL, // key object class
REG_OPTION_NON_VOLATILE, // option
KEY_WRITE, // desired access
NULL, // hkey cannot be inherited
&hkey, // OUT
&disposition // OUT new key / existing key
);
if (result != ERROR_SUCCESS)
{
}
}
if (success)
{
hkey, // subkey handle
"EventMessageFile", // value name
0, // must be zero
REG_EXPAND_SZ, // value type
* sizeof(TCHAR) // length of value data
);
if (result != ERROR_SUCCESS)
{
debugError("RegSetValueEx('EventMessageFile') failed, result=%d.",
result);
}
}
// Set the supported event types
if (success)
{
hkey, // subkey handle
"TypesSupported", // value name
0, // must be zero
REG_DWORD, // value type
sizeof(DWORD) // length of value data
);
if (result != ERROR_SUCCESS)
{
}
}
// Set the category message file
if (success)
{
hkey, // subkey handle
"CategoryMessageFile", // value name
0, // must be zero
REG_EXPAND_SZ, // value type
*sizeof(TCHAR) // length of value data
);
if (result != ERROR_SUCCESS)
{
debugError("RegSetValueEx('CategoryMessageFile') failed, result=%d.",
result);
}
}
// Set the number of categories: 1 (OPENDJ)
if (success)
{
hkey, // subkey handle
"CategoryCount", // value name
0, // must be zero
REG_DWORD, // value type
sizeof(DWORD) // length of value data
);
if (result != ERROR_SUCCESS)
{
}
}
// close the key before leaving
{
RegCloseKey (hkey);
}
if (alreadyRegistered || success)
{
return TRUE;
}
else
{
debugError("Could not create a registry key.");
return FALSE;
}
} // createRegistryKey
// ---------------------------------------------------
// Removes the registry key to send events based on the name of the service.
// serviceName the serviceName.
// The function returns TRUE if the key could be unregistered (or it was not
// registered) and FALSE otherwise.
// ---------------------------------------------------
{
// Create the event source subkey (or open it if it already exists)
long result;
// Check whether the Registry Key is already created,
// If so don't create a new one.
0,
KEY_QUERY_VALUE, // to query the values of a registry key.
&hkey // OUT
);
if (result != ERROR_SUCCESS)
{
debug("The registry key for service '%s' does not exist, so we do not need to remove it.",
// Assume that the registry key does not exist.
returnValue = TRUE;
}
else
{
if (result == ERROR_SUCCESS)
{
returnValue = TRUE;
}
else
{
}
}
return returnValue;
} // removeRegistryKey
// ---------------------------------------------------
// Register the source of event and returns the handle
// for the event log.
// serviceName the serviceName.
// ---------------------------------------------------
{
// subkey under Eventlog registry key
NULL, // local host
subkey // subkey under Eventlog registry key
);
return eventLog;
} // registerEventLog
// ---------------------------------------------------
// Deregister the source of event.
// ---------------------------------------------------
void deregisterEventLog()
{
{
debug("Deregistering the Event Log.");
}
}
// ----------------------------------------------------
// Check if the server is running or not.
// The functions returns SERVICE_RETURN_OK if we could determine if
// the server is running or not and false otherwise.
// ----------------------------------------------------
{
if (mustDebug)
{
debug("Determining if the server is running.");
}
{
int fd;
if (mustDebug)
{
"When determining whether the server is running, the lock file name is '%s'.",
lockFile);
}
if (fd != -1)
{
if (mustDebug)
{
}
// Test if there is a lock
/* Lock some bytes and read them. Then unlock. */
{
if (mustDebug)
{
}
}
else
{
{
if (mustDebug)
{
}
}
else
{
}
}
}
else
{
if (mustDebug)
{
debug("Could not open lock file '%s', which means the server is not running.",
lockFile);
}
}
}
else
{
debugError("Lock file path is too long.");
}
return returnValue;
} // isServerRunning
// ----------------------------------------------------
// Start the application using start-ds.bat
// The functions returns SERVICE_RETURN_OK if we could start the server
// and SERVICE_RETURN_ERROR otherwise.
// ----------------------------------------------------
{
// init out params
debug("doStartApplication");
{
if (createOk)
{
// At this point start-ds.bat has been launched. Try to wait till it
// returns. At the end of start-ds.bat we can be sure that the server (at
// least) tried to start: the script checks that the file created during
// startup is deleted (file logs\server.starting).
if (nWaitForStartDS != NULL)
{
debug("doStartApplication: OPENDJ_WINDOWS_SERVICE_STARTDS_WAIT env var set to %s",
if (wait <= 0)
{
}
}
else
{
debug("doStartApplication: OPENDJ_WINDOWS_SERVICE_STARTDS_WAIT is not set. Using default %d milliseconds.",
}
if (waitOk)
{
debug("doStartApplication: waited properly for process end.");
if (startDSExit != 0)
{
}
}
}
else
{
debug("The batch file process could not be created property");
}
{
// Just check once if the server is running or not: since the wait
// wait was successful, if the server is getting the lock, it already
// got it.
if (running)
{
debug("doStartApplication: server running.");
}
else
{
debug("doStartApplication: server not running.");
}
}
else if (createOk)
{
// Try to see if server is really running
{
if (nTries <= 0)
{
}
}
else
{
}
"doStartApplication: the spawn of the batch command worked. Command: '%s'",
command);
{
nTries--;
{
break;
}
if (!running)
{
debug("Sleeping for 5 seconds to allow the process to get the lock. %d tries remaining.",
nTries);
Sleep(5000);
}
}
if (running)
{
debug("doStartApplication: server running.");
}
else
{
debug("doStartApplication: server not running.");
}
}
else
{
}
}
else
{
debug("doStartApplication: the command path name is too long.");
}
return returnValue;
} // doStartApplication
// ----------------------------------------------------
// Stop the application using stop-ds.bat
// The functions returns SERVICE_RETURN_OK if we could stop the server
// and SERVICE_RETURN_ERROR otherwise.
// ----------------------------------------------------
{
// init out params
debug("doStopApplication");
{
// launch the command
{
// Try to see if server is really stopped
debug("doStopApplication: the spawn of the process worked.");
// Wait to be able to launch the java process in order it to free the lock
// on the file.
Sleep(3000);
{
{
break;
}
if (running)
{
Sleep(2000);
}
}
if (!running)
{
debug("doStopApplication: server stopped.");
}
else
{
debug("doStopApplication: server NOT stopped.");
}
}
else
{
}
}
else
{
debug("doStopApplication: the command path name is too long.");
}
return returnValue;
} // doStopApplication
// ---------------------------------------------------------------
// Build the path to the binary that contains serviceMain.
// Actually, the binary is the current executable file...
// serviceBinPath the path to the service binary.
// instanceDir the instanceDirectory.
// The string stored in serviceBinPath looks like
// <SERVER_ROOT>/lib/opendj_service.exe start <_instanceDir>
// It is up to the caller of the function to allocate
// at least COMMAND_SIZE bytes in serviceBinPath.
// The function returns SERVICE_RETURN_OK if we could create the binary
// path name and SERVICE_RETURN_ERROR otherwise.
// ---------------------------------------------------------------
{
// get the full path to the current executable file
NULL, // get the path to the current executable file
);
if (result == 0)
{
// failed to get the path of the executable file
debug("Could not get the path of the executable file.");
}
else
{
"When determining the service bin path, the module file name is '%s'.",
fileName);
{
// buffer was too small, executable name is probably not valid
debug("The name of the module file is too long.");
}
else
{
{
}
else
{
char * msg =
"The name of the resulting windows service command is too long.\n";
// buffer was too small, executable name is probably not valid
}
}
}
return returnValue;
} // createServiceBinPath
// ----------------------------------------------------
// Returns the service name that maps the command used to start the
// product. All commands are supposed to be unique because they have
// the instance dir as parameter.
//
// The functions returns SERVICE_RETURN_OK if we could get a service name
// and SERVICE_RETURN_ERROR otherwise.
// The serviceName buffer must be allocated OUTSIDE the function and its
// minimum size must be of 256 (the maximum string length of a Service Name).
// ----------------------------------------------------
{
// returned status code
// retrieve list of services
debug("Attempting to get the service name assuming command to run is '%s'.",
cmdToRun);
// go through the list of services and search for the service name
// whose display name is [displayName]
if (returnValue == SERVICE_RETURN_OK)
{
int i;
if (nbServices > 0)
{
for (i = 0; i<nbServices; i++)
{
{
{
{
// This function assumes that there are at least
// MAX_SERVICE_NAME (256) characters reserved in
// servicename.
}
else
{
debug("The service name found is too long: '%s'",
}
break;
}
}
}
free (serviceList);
}
}
else
{
debug("getServiceName: could not get service list.");
}
return returnValue;
} // getServiceName
// ----------------------------------------------------
// Set the current status for the service.
//
// statusToSet current service status to set
// win32ExitCode determine which exit code to use
// serviceExitCode service code to return in case win32ExitCode says so
// checkPoint incremental value use to report progress during a lenghty
// operation (start, stop...).
// waitHint estimated time required for a pending operation (in ms); if
// the service has not updated the checkpoint or change the state then
// the service controler thinks the service should be stopped!
// serviceStatusHandle the handle used to set the service status
// The functions returns SERVICE_RETURN_OK if we could start the service
// and SERVICE_RETURN_ERROR otherwise.
// ----------------------------------------------------
)
{
// elaborate service type:
// SERVICE_WIN32_OWN_PROCESS means this is not a driver and there is
// only one service in the process
// elaborate the commands supported by the service:
// - STOP customer has performed a stop-ds (or NET STOP)
// - SHUTDOWN the system is rebooting
// - INTERROGATE service controler can interrogate the service
//
// Note: INTERROGATE *must* be supported by the service handler
debug("Updating the service status. statusToSet=%d win32ExitCode=%d serviceExitCode=%d checkPoint=%d waitHint=%d",
if (statusToSet == SERVICE_START_PENDING)
{
debug("Service start pending: no controls accepted.");
// do not accept any command when the service is starting up...
}
else
{
controls =
}
// fill in the status structure
// set the service status
);
if (!success)
{
debugError("Failed to set the service status. Last error = %d.",
GetLastError());
}
else
{
}
return returnValue;
} // updateServiceStatus
// ----------------------------------------------------
// Query the current status of the service serviceName into returnedStatus
// return true if it was successful, false otherwise
// ----------------------------------------------------
{
{
debugError("getServiceStatus: openScm did not work. Last error = %d",
GetLastError());
return FALSE;
}
{
debugError("getServiceStatus: openService did not work. Last error = %d",
GetLastError());
}
else
{
{
}
else
{
debugError("getServiceStatus: Failed to query the service status. Last error = %d",
GetLastError());
}
// close the service handle
}
// close the service control manager handle
return ret;
}
// ----------------------------------------------------
// This function is the "main" of the service. It has been registered
// to the SCM by the main right after the service has been started through
// NET START command.
//
// The job of the serviceMain is
//
// 1- to register a handler to manage the commands STOP, PAUSE, CONTINUE,
// SHUTDOWN and INTERROGATE sent by the SCM
// 2- to start the main application using "start-ds"
//
// The serviceMain will return only when the service is terminated.
// ----------------------------------------------------
{
// returned status
// a checkpoint value indicate the progress of an operation
// __debugbreak();
debug("serviceMain");
if (code == SERVICE_RETURN_OK)
{
if (code != SERVICE_RETURN_OK)
{
debug("serviceMain: could not get service name.");
}
}
else
{
debug("serviceMain: failed to create service bin path.");
}
if (code == SERVICE_RETURN_OK)
{
// first register the service control handler to the SCM
if (code == SERVICE_RETURN_OK)
{
}
else
{
debug("serviceMain: failed to register service handler.");
}
}
// update the service status to START_PENDING
if (code == SERVICE_RETURN_OK)
{
0,
checkPoint++,
}
// create an event to signal the application termination
if (code == SERVICE_RETURN_OK)
{
NULL, // handle is not inherited by the child process
TRUE, // event has to be reset manually after a signal
FALSE, // initial state is "non signaled"
NULL // the event has no name
);
}
{
}
// start the application if not already started
{
code = doStartApplication();
switch (code)
{
case SERVICE_RETURN_OK:
// start is ok: do nothing for the moment.
break;
default:
debugError("serviceMain: doStartApplication() failed");
-1,
);
}
}
else
{
0,
}
// if all is ok wait for the application to die before we leave
if (code == SERVICE_RETURN_OK)
{
if (refreshPeriodEnv != NULL)
{
if (refreshPeriodSeconds < 0)
{
refreshPeriodSeconds = 10;
}
}
while (TRUE)
{
if (refreshPeriodSeconds == 0 && updatedRunningStatus)
{
break;
}
else
{
if (updatedRunningStatus)
{
Sleep(5000);
}
else
{
refreshPeriodSeconds * 1000);
if (returnValue == WAIT_OBJECT_0)
{
debug("The application has exited.");
break;
}
}
if (code != SERVICE_RETURN_OK)
{
debug("checking in serviceMain: error interrogating status.");
}
else if (running)
{
if (!updatedRunningStatus)
{
0,
checkPoint ++,
);
);
}
}
else
{
// Check current Status
if (!(success &&
((state == SERVICE_STOPPED) ||
(state == SERVICE_STOP_PENDING))))
{
debug("checking in serviceMain serviceHandler: service stopped with error.");
-1,
}
break;
}
}
}
}
// update the service status to STOPPED if it's not already done
if ((_serviceCurStatus != SERVICE_STOPPED) &&
(_serviceStatusHandle != NULL))
{
0,
);
}
debug("serviceMain returning.");
} // serviceMain
// ----------------------------------------------------
// Notify the serviceMain that service is now terminated.
//
// terminationEvent the event upon which serviceMain is blocked
// ----------------------------------------------------
{
debug("Faking a service termination so serviceMain can return.");
return;
} // doTerminateService
// ----------------------------------------------------
// This function is the handler of the service. It is processing the
// commands send by the SCM. Commands can be: STOP, PAUSE, CONTINUE,
// SHUTDOWN and INTERROGATE.
// controlCode the code of the command
// ----------------------------------------------------
{
switch (controlCode)
{
case SERVICE_CONTROL_SHUTDOWN:
// If system is shuting down then stop the service
// -> no break here
debug("serviceHandler: shutdown");
case SERVICE_CONTROL_STOP:
{
// update service status to STOP_PENDING
debug("serviceHandler: stop");
0,
checkpoint++,
);
// let's try to stop the application whatever may be the status above
// (best effort mode)
code = doStopApplication();
if (code == SERVICE_RETURN_OK)
{
0,
);
// again, let's ignore the above status and
// notify serviceMain that service has stopped
);
}
else
{
debug("serviceHandler: The server could not be stopped.");
// We could not stop the server
);
}
break;
}
// Request to pause the service
// ----------------------------
case SERVICE_CONTROL_PAUSE:
// not supported
debug("serviceHandler: pause.");
break;
// Request to resume the service
// -----------------------------
case SERVICE_CONTROL_CONTINUE:
// not supported
debug("serviceHandler: continue.");
break;
// Interrogate the service status
// ------------------------------
debug("serviceHandler: interrogate.");
if (code != SERVICE_RETURN_OK)
{
debug("serviceHandler: error interrogating.");
}
else if (running)
{
debug("serviceHandler: service running.");
}
else
{
debug("serviceHandler: service stopped.");
}
0,
);
break;
// Other codes are ignored
default:
break;
}
debug("serviceHandler returning.");
} // serviceHandler
// ---------------------------------------------------------------
// Retrieve the binaryPathName from the SCM database for a given service.
//
// scm is the SCM handler (must not be NULL)
// serviceName the name of the service.
// It is up to the caller of the function to allocate at least COMMAND_SIZE
// bytes in binPathName.
// The function returns SERVICE_RETURN_OK if we could create the binary
// path name and SERVICE_RETURN_ERROR otherwise.
// ---------------------------------------------------------------
char* binPathName)
{
// handle to the service
// if SCM exists then retrieve the config info of the service
{
scm,
);
}
{
}
else
{
while (!getConfigOk)
{
);
if (!getConfigOk)
{
if (errCode == ERROR_INSUFFICIENT_BUFFER)
{
// buffer not big enough...
continue;
}
else
{
debug("getBinaryPathName: error calling QueryServiceConfig. Code [%d]",
errCode);
break;
}
}
else
{
{
}
else
{
debug("getBinaryPathName: the length of the binary path name is too big. serviceName='%s', binaryPath='%s'",
}
}
}
if (!CloseServiceHandle(myService))
{
debug("getBinaryPathName: error closing handle of service. Code [%d]",
GetLastError());
}
}
// free buffers
if (serviceConfig != NULL)
{
}
return returnValue;
} // getBinaryPathName
// ---------------------------------------------------------------
// Returns the list of Windows services being created on the current host.
// The function allocates the memory for the returned buffer.
// serviceList contains the list of services.
// nbServices the number of services returned in the list.
// The functions returns SERVICE_RETURN_OK if we could create the service
// list and SERVICE_RETURN_ERROR otherwise.
// ---------------------------------------------------------------
int *nbServices)
{
// open Service Control Manager
// get the list of services being configured in the SCM database
// 1- first try with a single data structure ENUM_SERVICE_STATUS
unsigned long nbSvc = 0;
{
scm, // handle to the SCM
SERVICE_WIN32, // for OWN_PROCESS | SHARE_PROCESS
SERVICE_STATE_ALL, // all services (runing & stopped)
&serviceData, // output buffer
dataSize, // output buffer size
&neededSize, // sized needed to get the entries
&nbSvc, // number of services
&resumeHandle // next service entry to read
);
if (! svcStatusOk)
{
if (lastError != ERROR_MORE_DATA)
{
}
else
{
// buffer is not big enough: try again with a proper size
dataSize += neededSize;
dataSize, sizeof(ENUM_SERVICE_STATUS));
scm, // handle to the SCM
SERVICE_WIN32, // for OWN_PROCESS | SHARE_PROCESS
SERVICE_STATE_ALL, // all services (running & stopped)
lpServiceData, // output buffer
dataSize, // output buffer size
&neededSize, // sized needed to get the entries
&nbSvc, // number of services
&resumeHandle // next service entry to read
);
if (! svcStatusOk)
{
if (lastError != ERROR_MORE_DATA)
{
debug("getServiceList: second try generic error. Code [%d]",
}
else
{
// Data buffer is not large enough. This case should
// never happen as proper buffer size has been
// provided!...
debug("getServiceList: buffer error");
}
}
else
{
}
}
}
else
{
}
}
else
{
debug("getServiceList: error opening scm.");
}
// now elaborate the list of service to return...
if (returnValue == SERVICE_RETURN_OK)
{
int i;
*nbServices = aux;
if (aux > 0)
{
for (i = 0; i < aux; i++)
{
{
}
else
{
debug("Error getting binary path name of service: %s",
l[i].serviceName);
}
curService++;
}
*serviceList = l;
}
}
// close the handle to the SCM
{
// free the result buffer
if (lpServiceData != NULL)
{
}
}
return returnValue;
} // getServiceList
// ---------------------------------------------------------------
// Function used to know if a given service name is in use or not.
// Returns SERVICE_IN_USE if the provided service name is in use.
// Returns NOT_SERVICE_IN_USE if the provided service name is not in use.
// Returns SERVICE_RETURN_ERROR if the function could not determine if the
// service name is in use or not.
// ---------------------------------------------------------------
{
// retrieve list of services
int i;
// go through the list of services and search for the service name
{
if (nbServices > 0)
{
i++)
{
curService = serviceList[i];
{
debug("The service name is NULL.\n");
}
else
{
{
// found the service!
}
}
}
}
}
else
{
debugError("Could not determine if the service name '%s' is in use because listing the services failed.",
}
return returnValue;
} // serviceNameInUse
// ---------------------------------------------------------------
// Build a service name for OpenDJ and make sure
// the service name is unique on the system. To achieve this requirement
// the service name looks like <baseName> for the first OpenDJ and
// <baseName>-n if there are more than one.
//
// The functions returns SERVICE_RETURN_OK if we could create a service
// name and SERVICE_RETURN_ERROR otherwise.
// The serviceName buffer must be allocated OUTSIDE the function and its
// minimum size must be of 256 (the maximum string length of a Service Name).
// ---------------------------------------------------------------
{
int i = 1;
while (!ended)
{
if (i == 1)
{
}
else
{
}
if (nameInUseResult == SERVICE_IN_USE)
{
// this service name is already in use: try another one...
i++;
}
else if (nameInUseResult == SERVICE_NOT_IN_USE)
{
// this service name is not used so it's a good candidate
}
else
{
// an error occurred checking the service name
}
}
debug("createServiceName returning serviceName='%s' and returnValue=%d",
return returnValue;
} // createServiceName
// ---------------------------------------------------------------
// Create a service in the SCM database. Once the service is created,
// we can view it with "service list".
// displayName is the display name of the service
// description is the description of the service
// cmdToRun is the command to be run by the SCM upon NET START
//
// The function returns SERVICE_RETURN_OK if we could create the service and
// SERVICE_RETURN_ERROR otherwise.
// ---------------------------------------------------------------
char* cmdToRun)
{
// local vars
// - serviceName is the service name
// elaborate the service name based on the displayName provided
// create the service
if (returnValue == SERVICE_RETURN_OK)
{
{
debug("createServiceInScm: openScm did not work.");
}
}
else
{
debug("createServiceInScm: createServiceName did not work.");
}
if (returnValue == SERVICE_RETURN_OK)
{
scm,
serviceName, // name of service
serviceName, // service name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_AUTO_START, // start service during
// system startup
SERVICE_ERROR_NORMAL, // error control type
cmdToRun, // path to service's binary
NULL, // no load ordering group
NULL, // no tag identifier
NULL, // no dependencies
NULL, // LocalSystem account
NULL // no password
);
}
{
debugError("Failed to create the service '%s'. Last error = %d.",
if (errCode == ERROR_DUPLICATE_SERVICE_NAME)
{
}
else if (errCode == ERROR_SERVICE_EXISTS)
{
}
else
{
if (errCode == ERROR_INVALID_HANDLE)
{
debugError("The handle seems to be invalid.");
}
}
}
// add description field
if (returnValue == SERVICE_RETURN_OK)
{
);
if (!success)
{
"Failed to add a description to the service '%s'. Last error = %d.",
serviceName, GetLastError());
}
}
// close handles
{
}
{
}
// free names
if (serviceName != NULL)
{
free (serviceName);
}
return returnValue;
} // createServiceInScm
// ---------------------------------------------------------------
// Remove a service with the name serviceName from SCM.
// If the service could be removed returns SERVICE_RETURN_OK.
// If the service cannot be removed because still in use by any process
// then returned status is SERVICE_MARKED_FOR_DELETION.
// If an error occurs returns SERVICE_RETURN_ERROR.
// ---------------------------------------------------------------
{
// local vars
// open the service
if (returnValue == SERVICE_RETURN_OK)
{
scm,
);
{
debugError("Failed to open the service '%s'. Last error = %d",
serviceName, GetLastError());
}
}
if (returnValue == SERVICE_RETURN_OK)
{
);
if (!success)
{
debugError("Failed to query the status for service '%s'. Last error = %d",
serviceName, GetLastError());
}
}
// stop the service if necessary
if (returnValue == SERVICE_RETURN_OK)
{
{
);
if (!success)
{
debugError("Failed to stop the service '%s'. Last error = %d.",
{
}
else
{
}
}
else
{
Sleep (500);
}
}
}
// remove the service
if (returnValue == SERVICE_RETURN_OK)
{
if (!success)
{
debugError("Failed to delete the service '%s'. Last error = %d.",
{
}
else
{
}
}
}
// close handles
{
}
{
}
return returnValue;
} // removeServiceFromScm
// ---------------------------------------------------------------
// Function called to create a service for the OpenDJ instance
// where this executable is installed.
// The first argument that is passed is the displayName of the service
// and the second the description,
//
// Returns 0 if the service was successfully created.
// Returns 1 if the service already existed for this instance.
// Returns 2 if the service name we created already exists.
// Returns 3 if an error occurred.
// ---------------------------------------------------------------
{
int returnCode = 0;
if (code == SERVICE_RETURN_OK)
{
if (code == SERVICE_RETURN_OK)
{
// There is a valid serviceName for the command to run, so
// OpenDJ is registered as a service.
}
else
{
// We could not find a serviceName for the command to run, so
// try to create the service.
if (code == SERVICE_RETURN_OK)
{
if (code == SERVICE_RETURN_OK)
{
}
else
{
debug("Could not get a service name for command to run.");
}
}
}
}
else
{
debug("createService could not create bin path.");
}
switch (code)
{
case SERVICE_RETURN_OK:
returnCode = 0;
debug("Service successfully created.");
break;
case SERVICE_ALREADY_EXISTS:
returnCode = 1;
debug("Service already exists.");
break;
case DUPLICATED_SERVICE_NAME:
returnCode = 2;
debug("Duplicated service name.");
break;
default:
returnCode = 3;
debug("Unexpected error creating service.");
}
return returnCode;
} // createService
// ---------------------------------------------------------------
// Function called to know if the OpenDJ instance where this
// executable is installed is running as a service or not.
// Returns 0 if the instance is running as a service and print the
// serviceName in the standard output.
// Returns 1 if the instance is not running as a service.
// Returns 2 if an error occurred or we cannot determine if Open DS
// is running as a service or not.
// ---------------------------------------------------------------
int serviceState()
{
int returnCode = 0;
debug("Getting service state.");
cmdToRun);
if (code == SERVICE_RETURN_OK)
{
if (code == SERVICE_RETURN_OK)
{
// There is a valid serviceName for the command to run, so
// OpenDJ is registered as a service.
returnCode = 0;
}
else
{
returnCode = 1;
}
}
else
{
returnCode = 2;
debug("An error occurred getting the service status.");
}
return returnCode;
} // serviceState
// ---------------------------------------------------------------
// Function called to remove the service associated with a given
// service name.
// Returns 0 if the service was successfully removed.
// Returns 1 if the service does not exist.
// Returns 2 if the service was marked for deletion but is still in
// use.
// Returns 3 if an error occurred.
// ---------------------------------------------------------------
{
int returnCode = 0;
if (code != SERVICE_IN_USE)
{
returnCode = 1;
debug("Service does not exist.");
}
else
{
switch (code)
{
case SERVICE_RETURN_OK:
returnCode = 0;
debug("Service successfully removed.");
break;
returnCode = 2;
debug("Service marked for deletion.");
break;
default:
returnCode = 3;
debug("Unexpected error removing service.");
}
}
return returnCode;
} // removeServiceWithServiceName
// ---------------------------------------------------------------
// Function called to remove the service for the OpenDJ instance
// where this executable is installed.
// Returns 0 if the service was successfully removed.
// Returns 1 if the service does not exist.
// Returns 2 if the service was marked for deletion but is still in
// use.
// Returns 3 if an error occurred.
// ---------------------------------------------------------------
int removeService()
{
int returnCode = 0;
debug("removeService");
if (code == SERVICE_RETURN_OK)
{
if (code == SERVICE_RETURN_OK)
{
}
else
{
returnCode = 1;
}
}
else
{
returnCode = 2;
}
return returnCode;
} // removeService
// ---------------------------------------------------------------
// Function called to start the service where this executable is installed.
// Returns 0 if the service runs.
// Returns 1 if an error occurred.
// ---------------------------------------------------------------
int startService()
{
int returnCode;
debug("startService");
if (code == SERVICE_RETURN_OK)
{
}
if (code == SERVICE_RETURN_OK)
{
{
};
// register the service to the SCM. The function will return once the
// service is terminated.
if (!success)
{
argc[0] = _instanceDir;
{
argc[1] =
"startService: StartServiceCtrlDispatcher did not work: \
ERROR_FAILED_SERVICE_CONTROLLER_CONNECT.";
}
else if (lastError == ERROR_INVALID_DATA)
{
argc[1] =
"startService: StartServiceCtrlDispatcher did not work: \
ERROR_INVALID_DATA.";
}
else if (lastError == ERROR_SERVICE_ALREADY_RUNNING)
{
argc[1] =
"startService: StartServiceCtrlDispatcher did not work: \
ERROR_SERVICE_ALREADY_RUNNING.";
}
else
{
argc[1] =
"startService: StartServiceCtrlDispatcher did not work.";
}
);
}
}
else
{
debug("startService: Could not get service name.");
}
if (code == SERVICE_RETURN_OK)
{
returnCode = 0;
}
else
{
returnCode = 1;
}
return returnCode;
} // startService
{
char* subcommand;
int returnCode = 0;
int i;
debug("main called.");
for (i = 0; i < argc; i++) {
}
// __debugbreak();
if (argc <= 1)
{
"Subcommand required: create, state, remove, start or cleanup.\n");
returnCode = -1;
}
else
{
{
if (argc <= 4)
{
"Subcommand create requires instance dir, service name and description.\n");
returnCode = -1;
}
else
{
}
}
{
if (argc <= 2)
{
"Subcommand state requires instance dir.\n");
returnCode = -1;
}
else
{
returnCode = serviceState();
}
}
{
if (argc <= 2)
{
"Subcommand remove requires instance dir.\n");
returnCode = -1;
}
else
{
returnCode = removeService();
}
}
{
if (argc <= 2)
{
"Subcommand start requires instance dir.\n");
returnCode = -1;
}
else
{
returnCode = startService();
}
}
{
if (argc <= 2)
{
"Subcommand isrunning requires instance dir.\n");
returnCode = -1;
}
else
{
if (code == SERVICE_RETURN_OK)
{
returnCode = 0;
}
else
{
returnCode = -1;
}
}
}
{
if (argc <= 2)
{
"Subcommand cleanup requires service name.\n");
returnCode = -1;
}
else
{
}
}
else
{
returnCode = -1;
}
}
return returnCode;
} // main