0N/A* The contents of this file are subject to the terms of the 0N/A* Common Development and Distribution License, Version 1.0 only 0N/A* (the "License"). You may not use this file except in compliance 0N/A* You can obtain a copy of the license at 0N/A* See the License for the specific language governing permissions 0N/A* and limitations under the License. 0N/A* When distributing Covered Code, include this CDDL HEADER in each 0N/A* file and include the License file \ 0N/A* add the following below this CDDL HEADER, with the fields enclosed 0N/A* by brackets "[]" replaced with your own identifying * information: 0N/A* Portions Copyright [yyyy] [name of copyright owner] 0N/A* Copyright 2008-2010 Sun Microsystems, Inc. 0N/A* Portions Copyright 2011-2013 ForgeRock AS 0N/A// ---------------------------------------------------- 0N/A// Register a service handler to the service control dispatcher. 0N/A// A service handler will manage the control function such as: 0N/A// stop, pause, continue, shutdown, interrogate. The control functions 0N/A// are sent by the service control dispatcher upon user request 0N/A// 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. // ---------------------------------------------------- // register the service to the service control dispatcher (SCM) }
// 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. // --------------------------------------------------- NULL,
// no user security identifier NULL,
// no user security identifier // --------------------------------------------------------------- // 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 // 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,
// ServicesActive database debugError(
"Failed to open the Service Control Manager. Last error = %d",
debug(
"Successfully opened the Service Control Manager.");
// --------------------------------------------------- // 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) // 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. // Check whether the Registry Key is already created, // If so don't create a new one. NULL,
// key object class NULL,
// hkey cannot be inherited "EventMessageFile",
// value name *
sizeof(
TCHAR)
// length of value data debugError(
"RegSetValueEx('EventMessageFile') failed, result=%d.",
// Set the supported event types "TypesSupported",
// value name sizeof(
DWORD)
// length of value data // Set the category message file "CategoryMessageFile",
// value name *
sizeof(
TCHAR)
// length of value data debugError(
"RegSetValueEx('CategoryMessageFile') failed, result=%d.",
// Set the number of categories: 1 (OPENDJ) "CategoryCount",
// value name sizeof(
DWORD)
// length of value data // close the key before leaving // --------------------------------------------------- // 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) // Check whether the Registry Key is already created, // If so don't create a new one. 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. // --------------------------------------------------- // Register the source of event and returns the handle // serviceName the serviceName. // --------------------------------------------------- // subkey under Eventlog registry key subkey // subkey under Eventlog registry key // --------------------------------------------------- // Deregister the source of event. // --------------------------------------------------- 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. // ---------------------------------------------------- debug(
"Determining if the server is running.");
"When determining whether the server is running, the lock file name is '%s'.",
// Test if there is a lock /* Lock some bytes and read them. Then unlock. */ debug(
"Able to lock '%s', so the server is not running.",
lockFile);
debug(
"Unable to lock '%s', so the server is running.",
lockFile);
debug(
"Could not open lock file '%s', which means the server is not running.",
// ---------------------------------------------------- // Start the application using start-ds.bat // The functions returns SERVICE_RETURN_OK if we could start the server // and SERVICE_RETURN_ERROR otherwise. // ---------------------------------------------------- debug(
"doStartApplication");
debug(
"doStartApplication: Launching batch file: %s",
command);
// 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). debug(
"doStartApplication: OPENDJ_WINDOWS_SERVICE_STARTDS_WAIT env var set to %s",
debug(
"doStartApplication: OPENDJ_WINDOWS_SERVICE_STARTDS_WAIT is not set. Using default %d milliseconds.",
debug(
"doStartApplication: waited properly for process end.");
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 debug(
"doStartApplication: server running.");
debug(
"doStartApplication: server not running.");
// Try to see if server is really running debug(
"OPENDJ_WINDOWS_SERVICE_START_NTRIES env var set to %s",
nTriesEnv);
debug(
"OPENDJ_WINDOWS_SERVICE_START_NTRIES is not set. Using default %d tries.",
nTries);
"doStartApplication: the spawn of the batch command worked. Command: '%s'",
debug(
"Sleeping for 5 seconds to allow the process to get the lock. %d tries remaining.",
debug(
"doStartApplication: server running.");
debug(
"doStartApplication: server not running.");
debug(
"doStartApplication: batch command spawn failed. Sent command: '%s'",
command);
debug(
"doStartApplication: the command path name is too long.");
// ---------------------------------------------------- // Stop the application using stop-ds.bat // The functions returns SERVICE_RETURN_OK if we could stop the server // and SERVICE_RETURN_ERROR otherwise. // ---------------------------------------------------- debug(
"doStopApplication");
// 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 debug(
"doStopApplication: server stopped.");
debug(
"doStopApplication: server NOT stopped.");
debug(
"doStopApplication: spawn failed. Sent command: %s",
command);
debug(
"doStopApplication: the command path name is too long.");
// --------------------------------------------------------------- // 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 // 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 // failed to get the path of the executable file debug(
"Could not get the path of the executable file.");
"When determining the service bin path, the module file name is '%s'.",
// buffer was too small, executable name is probably not valid debug(
"The name of the module file is too long.");
"The name of the resulting windows service command is too long.\n";
// buffer was too small, executable name is probably not valid }
// 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). // ---------------------------------------------------- // retrieve list of services debug(
"Attempting to get the service name assuming command to run is '%s'.",
// go through the list of services and search for the service name // whose display name is [displayName] // This function assumes that there are at least // MAX_SERVICE_NAME (256) characters reserved in debug(
"The service name found is too long: '%s'",
debug(
"getServiceName: could not get service list.");
// ---------------------------------------------------- // 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",
debug(
"Service start pending: no controls accepted.");
// do not accept any command when the service is starting up... // fill in the status structure // set the service status debugError(
"Failed to set the service status. Last error = %d.",
// ---------------------------------------------------- // 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",
debugError(
"getServiceStatus: openService did not work. Last error = %d",
debugError(
"getServiceStatus: Failed to query the service status. Last error = %d",
// close the service handle // close the service control manager handle // ---------------------------------------------------- // 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 // 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. // ---------------------------------------------------- // a checkpoint value indicate the progress of an operation debug(
"serviceMain: could not get service name.");
debug(
"serviceMain: failed to create service bin path.");
// first register the service control handler to the SCM debug(
"serviceMain: failed to register service handler.");
// update the service status to START_PENDING // create an event to signal the application termination 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 // start is ok: do nothing for the moment. debugError(
"serviceMain: doStartApplication() failed");
// if all is ok wait for the application to die before we leave debug(
"The application has exited.");
debug(
"checking in serviceMain: error interrogating status.");
debug(
"checking in serviceMain serviceHandler: service stopped with error.");
// update the service status to STOPPED if it's not already done debug(
"serviceMain returning.");
// ---------------------------------------------------- // 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.");
// ---------------------------------------------------- // 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 // ---------------------------------------------------- // If system is shuting down then stop the service debug(
"serviceHandler: shutdown");
// update service status to STOP_PENDING debug(
"serviceHandler: stop");
// let's try to stop the application whatever may be the status above // again, let's ignore the above status and // notify serviceMain that service has stopped debug(
"serviceHandler: The server could not be stopped.");
// We could not stop the server // Request to pause the service // ---------------------------- debug(
"serviceHandler: pause.");
// Request to resume the service // ----------------------------- debug(
"serviceHandler: continue.");
// Interrogate the service status // ------------------------------ debug(
"serviceHandler: interrogate.");
debug(
"serviceHandler: error interrogating.");
debug(
"serviceHandler: service running.");
debug(
"serviceHandler: service stopped.");
// Other codes are ignored debug(
"serviceHandler returning.");
// --------------------------------------------------------------- // 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 // The function returns SERVICE_RETURN_OK if we could create the binary // path name and SERVICE_RETURN_ERROR otherwise. // --------------------------------------------------------------- // if SCM exists then retrieve the config info of the service // buffer not big enough... debug(
"getBinaryPathName: error calling QueryServiceConfig. Code [%d]",
debug(
"getBinaryPathName: the length of the binary path name is too big. serviceName='%s', binaryPath='%s'",
debug(
"getBinaryPathName: error closing handle of service. Code [%d]",
// --------------------------------------------------------------- // 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. // --------------------------------------------------------------- // 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 scm,
// handle to the SCM &
nbSvc,
// number of services // buffer is not big enough: try again with a proper size scm,
// handle to the SCM &
nbSvc,
// number of services debug(
"getServiceList: second try generic error. Code [%d]",
// Data buffer is not large enough. This case should // never happen as proper buffer size has been debug(
"getServiceList: buffer error");
debug(
"getServiceList: error opening scm.");
// now elaborate the list of service to return... for (i = 0; i <
aux; i++)
debug(
"Error getting binary path name of service: %s",
// close the handle to the SCM // free the result buffer // --------------------------------------------------------------- // 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 // go through the list of services and search for the service name debug(
"The service name is NULL.\n");
debugError(
"Could not determine if the service name '%s' is in use because listing the services failed.",
// --------------------------------------------------------------- // 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). // --------------------------------------------------------------- // this service name is already in use: try another one... // this service name is not used so it's a good candidate // an error occurred checking the service name debug(
"createServiceName returning serviceName='%s' and returnValue=%d",
// --------------------------------------------------------------- // 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. // --------------------------------------------------------------- // - serviceName is the service name // elaborate the service name based on the displayName provided debug(
"createServiceInScm: openScm did not work.");
debug(
"createServiceInScm: createServiceName did not work.");
NULL,
// no load ordering group NULL,
// no tag identifier NULL,
// LocalSystem account debugError(
"Failed to create the service '%s'. Last error = %d.",
"Failed to add a description to the service '%s'. Last error = %d.",
// --------------------------------------------------------------- // 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. // --------------------------------------------------------------- debugError(
"Failed to open the service '%s'. Last error = %d",
debugError(
"Failed to query the status for service '%s'. Last error = %d",
// stop the service if necessary debugError(
"Failed to stop the service '%s'. Last error = %d.",
debugError(
"Failed to delete the service '%s'. Last error = %d.",
}
// 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. // --------------------------------------------------------------- // There is a valid serviceName for the command to run, so // OpenDJ is registered as a service. // We could not find a serviceName for the command to run, so // try to create the service. debug(
"Could not get a service name for command to run.");
debug(
"createService could not create bin path.");
debug(
"Service successfully created.");
debug(
"Service already exists.");
debug(
"Duplicated service name.");
debug(
"Unexpected error creating service.");
// --------------------------------------------------------------- // 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. // --------------------------------------------------------------- debug(
"Getting service state.");
debug(
"Created the service bin path. code=%d. cmdToRun='%s'.",
code,
// There is a valid serviceName for the command to run, so // OpenDJ is registered as a service. debug(
"An error occurred getting the service status.");
// --------------------------------------------------------------- // Function called to remove the service associated with a given // 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 // Returns 3 if an error occurred. // --------------------------------------------------------------- debug(
"Service does not exist.");
debug(
"Service successfully removed.");
debug(
"Service marked for deletion.");
debug(
"Unexpected error removing service.");
}
// 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 // Returns 3 if an error occurred. // --------------------------------------------------------------- // --------------------------------------------------------------- // Function called to start the service where this executable is installed. // Returns 0 if the service runs. // Returns 1 if an error occurred. // --------------------------------------------------------------- // register the service to the SCM. The function will return once the // service is terminated. "startService: StartServiceCtrlDispatcher did not work: \ ERROR_FAILED_SERVICE_CONTROLLER_CONNECT.";
"startService: StartServiceCtrlDispatcher did not work: \ "startService: StartServiceCtrlDispatcher did not work: \ ERROR_SERVICE_ALREADY_RUNNING.";
"startService: StartServiceCtrlDispatcher did not work.";
debug(
"startService: Could not get service name.");
for (i = 0; i <
argc; i++) {
"Subcommand required: create, state, remove, start or cleanup.\n");
"Subcommand create requires instance dir, service name and description.\n");
"Subcommand state requires instance dir.\n");
"Subcommand remove requires instance dir.\n");
"Subcommand start requires instance dir.\n");
"Subcommand isrunning requires instance dir.\n");
"Subcommand cleanup requires service name.\n");