service.c revision 9b60953030838eeb32fb14a72d418ae5b71ef608
/*
* 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 at
* 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
*
*
* Portions Copyright 2007 Sun Microsystems, Inc.
*/
#include "service.h"
int _serviceCurStatus;
char *_instanceDir = NULL;
// ----------------------------------------------------
// 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
// ---------------------------------------------------
// Debug utility. If the _eventLog is not NULL and the DEBUG variable is
// TRUE send the message to the event log.
// If the _eventLog is NULL and the DEBUG variable is TRUE send the message
// to the standard output.
// ---------------------------------------------------
{
{
{
const char* args[1];
// report the event
_eventLog, // event log handle
EVENTLOG_INFORMATION_TYPE, // info, warning, error
WIN_FACILITY_NAME_OPENDS, // unique category for OPENDS
NULL, // no user security identifier
1, // number of args
0, // raw data size
(const char**)args, // args
NULL // no war data
);
}
else
{
}
}
}
// ---------------------------------------------------
// 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_OPENDS, // unique category for OPENDS
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_OPENDS, // unique category for OPENDS
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
);
{
debug("scm is NULL.");
}
else
{
}
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)
char subkey [MAX_REGISTRY_KEY];
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)
{
debug("RegCreateKeyEx failed.");
}
}
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)
{
}
}
// 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)
{
}
}
// Set the number of categories: 1 (OPENDS)
if (success)
{
long result = RegSetValueEx(
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
{
debug("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)
char subkey [MAX_REGISTRY_KEY];
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)
{
// Assume that the registry key does not exist.
returnValue = TRUE;
}
else
{
if (result == ERROR_SUCCESS)
{
returnValue = TRUE;
}
}
return returnValue;
} // removeRegistryKey
// ---------------------------------------------------
// Register the source of event and returns the handle
// for the event log.
// serviceName the serviceName.
// ---------------------------------------------------
{
// subkey under Eventlog registry key
char subkey [MAX_SERVICE_NAME];
NULL, // local host
subkey // subkey under Eventlog registry key
);
return eventLog;
} // registerEventLog
// ---------------------------------------------------
// Deregister the source of event.
// ---------------------------------------------------
void deregisterEventLog()
{
{
}
}
// ----------------------------------------------------
// 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.
// ----------------------------------------------------
{
char* relativePath = "\\locks\\server.lock";
{
int fd;
if (fd != -1)
{
// Test if there is a lock
/* Lock some bytes and read them. Then unlock. */
{
}
else
{
{
}
else
{
debug("Unexpected error locking");
}
}
}
else
{
}
}
else
{
}
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
char* relativePath = "\\bat\\start-ds.bat";
char command[COMMAND_SIZE];
{
// launch the command
{
// Try to see if server is really running
int nTries = 10;
// 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)
{
}
else
{
}
}
else
{
}
}
else
{
}
return returnValue;
} // doStartApplication
// ----------------------------------------------------
// Start 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
char* relativePath = "\\bat\\stop-ds.bat";
char command[COMMAND_SIZE];
{
// launch the command
{
// Try to see if server is really stopped
int nTries = 10;
// 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)
{
}
else
{
}
}
else
{
}
}
else
{
}
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/service.exe start <_instanceDir>
// It is up to the caller of the function to allocate
// at least MAX_PATH 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
}
else
{
{
// buffer was too small, executable name is probably not valid
}
else
{
< MAX_PATH)
{
}
else
{
// 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 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).
// ----------------------------------------------------
{
// returned status code
// retrieve list of services
int nbServices = -1;
// 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.
}
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 interogate the service
//
// Note: INTERROGATE *must* be supported by the service handler
if (statusToSet == SERVICE_START_PENDING)
{
// do not accept any command when the service is starting up...
}
else
{
controls =
}
// fill in the status structure
// set the service status
);
if (!success)
{
}
else
{
}
return returnValue;
} // updateServiceStatus
// ----------------------------------------------------
// 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
char serviceName[MAX_SERVICE_NAME];
// a checkpoint value indicate the progress of an operation
if (code == SERVICE_RETURN_OK)
{
}
if (code == SERVICE_RETURN_OK)
{
// first register the service control handler to the SCM
if (code == SERVICE_RETURN_OK)
{
}
}
// 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
);
}
// update the service status to START_PENDING
if (code == SERVICE_RETURN_OK)
{
0,
checkPoint++,
);
}
// start the application
if (code == SERVICE_RETURN_OK)
{
const char *argc[] = {_instanceDir};
code = doStartApplication();
switch (code)
{
case SERVICE_RETURN_OK:
// start is ok
0,
);
);
break;
default:
-1,
);
}
}
else
{
0,
}
// if all is ok wait for the application to die before we leave
if (code == SERVICE_RETURN_OK)
{
}
// update the service status to STOPPED if it's not already done
if ((_serviceCurStatus != SERVICE_STOPPED) &&
(_serviceStatusHandle != NULL))
{
0,
);
}
} // serviceMain
// ----------------------------------------------------
// Notify the serviceMain that service is now terminated.
//
// terminationEvent the event upon which serviceMain is blocked
// ----------------------------------------------------
{
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
case SERVICE_CONTROL_STOP:
{
// update service status to STOP_PENDING
debug("Stop called");
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)
{
const char *argc[] = {_instanceDir};
0,
);
// again, let's ignore the above status and
// notify serviceMain that service has stopped
);
}
else
{
const char *argc[] = {_instanceDir};
// We could not stop the server
);
}
break;
}
// Request to pause the service
// ----------------------------
case SERVICE_CONTROL_PAUSE:
// not supported
break;
// Request to resume the service
// -----------------------------
case SERVICE_CONTROL_CONTINUE:
// not supported
break;
// Interrogate the service status
// ------------------------------
if (code != SERVICE_RETURN_OK)
{
}
else if (running)
{
}
else
{
}
0,
);
break;
// Other codes are ignored
default:
break;
}
} // 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 MAX_PATH bytes
// in binPathName.
// The function returns SERVICE_RETURN_OK if we could create the binary
// path name and SERVICE_RETURN_ERROR otherwise.
// ---------------------------------------------------------------
char* binPathName)
{
// pathtname to return
char* binPathname = NULL;
// handle to the service
// if SCM exists then retrieve the config info of the service
{
scm,
);
}
{
while (!getConfigOk)
{
);
if (!getConfigOk)
{
if (errCode == ERROR_INSUFFICIENT_BUFFER)
{
// buffer nor big enough...
continue;
}
else
{
break;
}
}
else
{
{
}
}
}
}
// free buffers
if (serviceConfig != NULL)
{
}
return returnValue;
} // getBinaryPathName
// ---------------------------------------------------------------
// Returns the list of NT 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
DWORD resumeHandle = 0;
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)
{
char msg[200];
// error
}
else
{
debug("getServiceList: error More Data.");
// 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)
{
}
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
{
}
// 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++)
{
{
}
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 nbServices = -1;
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
{
}
return returnValue;
} // serviceNameInUse
// ---------------------------------------------------------------
// Build a service name for OpenDS and make sure
// the service name is unique on the system. To achieve this requirement
// the service name looks like <baseName> for the first OpenDS 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
}
}
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
);
}
{
if (errCode == ERROR_DUPLICATE_SERVICE_NAME)
{
}
else if (errCode == ERROR_SERVICE_EXISTS)
{
}
else
{
}
}
// add description field
if (returnValue == SERVICE_RETURN_OK)
{
);
if (!success)
{
}
}
// 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,
);
{
}
}
if (returnValue == SERVICE_RETURN_OK)
{
);
if (!success)
{
}
}
// stop the service if necessary
if (returnValue == SERVICE_RETURN_OK)
{
{
);
if (!success)
{
{
}
else
{
}
}
else
{
Sleep (500);
}
}
}
// remove the service
if (returnValue == SERVICE_RETURN_OK)
{
if (!success)
{
{
}
else
{
}
}
}
// close handles
{
}
{
}
return returnValue;
} // removeServiceFromScm
// ---------------------------------------------------------------
// Function called to create a service for the OpenDS 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)
{
char serviceName[MAX_SERVICE_NAME];
if (code == SERVICE_RETURN_OK)
{
// There is a valid serviceName for the command to run, so
// OpenDS is registered as a service.
debug("createService: service already exists for this instance.");
}
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)
{
}
}
}
}
switch (code)
{
case SERVICE_RETURN_OK:
returnCode = 0;
break;
case SERVICE_ALREADY_EXISTS:
returnCode = 1;
break;
case DUPLICATED_SERVICE_NAME:
returnCode = 2;
break;
default:
returnCode = 3;
}
return returnCode;
} // createService
// ---------------------------------------------------------------
// Function called to know if the OpenDS 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;
char serviceName[MAX_SERVICE_NAME];
if (code == SERVICE_RETURN_OK)
{
if (code == SERVICE_RETURN_OK)
{
// There is a valid serviceName for the command to run, so
// OpenDS is registered as a service.
returnCode = 0;
}
else
{
returnCode = 1;
}
}
else
{
returnCode = 2;
}
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 removeServiceWithServiceName(char *serviceName)
{
int returnCode = 0;
if (code != SERVICE_IN_USE)
{
returnCode = 1;
}
else
{
switch (code)
{
case SERVICE_RETURN_OK:
returnCode = 0;
break;
returnCode = 2;
break;
default:
returnCode = 3;
}
}
return returnCode;
} // removeServiceWithServiceName
// ---------------------------------------------------------------
// Function called to remove the service for the OpenDS 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;
char serviceName[MAX_SERVICE_NAME];
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;
char serviceName[MAX_SERVICE_NAME];
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)
{
const char *argc[2];
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
// ---------------------------------------------------------------
// Function called to know if the --debug option was passed
// when calling this executable or not. The DEBUG variable is
// updated accordingly.
// ---------------------------------------------------------------
{
int i;
{
{
}
}
}
{
char* subcommand;
int returnCode = 0;
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