service.c revision 5385
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* You can obtain a copy of the license at 961N/A* See the License for the specific language governing permissions 961N/A* and limitations under the License. 961N/A* When distributing Covered Code, include this CDDL HEADER in each 5025N/A* file and include the License file \ 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] 5025N/A* Copyright 2008-2010 Sun Microsystems, Inc. 5385N/A* Portions Copyright 2011 ForgeRock AS 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// 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 // register the service to the service control dispatcher (SCM) 961N/A}
// registerServiceHandler 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/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// 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 // open Service Control Manager 1298N/A debug(
"Successfully opened the Service Control Manager.");
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/A // true if the server is already registered 961N/A // false as soon as an error occurs 961N/A // Create the event source subkey (or open it if it already exists) 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 // Check whether the Registry Key is already created, 961N/A // If so don't create a new one. 961N/A "EventMessageFile",
// value name 961N/A // Set the supported event types 961N/A "TypesSupported",
// value name 961N/A // Set the category message file 961N/A "CategoryMessageFile",
// value name 5385N/A // Set the number of categories: 1 (OPENDJ) 961N/A "CategoryCount",
// value name 961N/A // close the key before leaving 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/A // Create the event source subkey (or open it if it already exists) 961N/A // Check whether the Registry Key is already created, 961N/A // If so don't create a new one. 1878N/A debug(
"The registry key for service '%s' does not exist, so we do not need to remove it.",
961N/A // Assume that the registry key does not exist. 961N/A// --------------------------------------------------- 961N/A// Register the source of event and returns the handle 961N/A// serviceName the serviceName. 961N/A// --------------------------------------------------- 961N/A // subkey under Eventlog registry key 961N/A// --------------------------------------------------- 961N/A// Deregister the source of event. 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/A "When determining whether the server is running, the lock file name is '%s'.",
961N/A // Test if there is a lock 961N/A /* Lock some bytes and read them. Then unlock. */ 5025N/A debug(
"Could not open lock file '%s', which means the server is not running.",
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// ---------------------------------------------------- 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 5385N/A debug(
"doStartApplication: OPENDJ_WINDOWS_SERVICE_STARTDS_WAIT env var set to %s",
5385N/A debug(
"doStartApplication: OPENDJ_WINDOWS_SERVICE_STARTDS_WAIT is not set. Using default %d milliseconds.",
5072N/A debug(
"doStartApplication: waited properly for process end.");
5072N/A debug(
"The batch file process could not be created property");
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 961N/A // Try to see if server is really running 5385N/A debug(
"OPENDJ_WINDOWS_SERVICE_START_NTRIES is not set. Using default %d tries.",
nTries);
5072N/A "doStartApplication: the spawn of the batch command worked. Command: '%s'",
3899N/A debug(
"Sleeping for 5 seconds to allow the process to get the lock. %d tries remaining.",
1295N/A debug(
"doStartApplication: the command path name is too long.");
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/A // Try to see if server is really stopped 1295N/A debug(
"doStopApplication: the spawn of the process worked.");
961N/A // Wait to be able to launch the java process in order it to free the lock 1295N/A debug(
"doStopApplication: the command path name is too long.");
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 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 // get the full path to the current executable file 961N/A NULL,
// get the path to the current executable file 961N/A // failed to get the path of the executable file 5385N/A debug(
"Could not get the path of the executable file.");
1878N/A "When determining the service bin path, the module file name is '%s'.",
961N/A // buffer was too small, executable name is probably not valid 1878N/A "The name of the resulting windows service command is too long.\n";
961N/A // buffer was too small, executable name is probably not valid 961N/A}
// createServiceBinPath 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. 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 // returned status code 961N/A // retrieve list of services 1878N/A debug(
"Attempting to get the service name assuming command to run is '%s'.",
961N/A // go through the list of services and search for the service name 961N/A // whose display name is [displayName] 961N/A // This function assumes that there are at least 961N/A // MAX_SERVICE_NAME (256) characters reserved in 961N/A debug(
"getServiceName: could not get service list.");
961N/A// ---------------------------------------------------- 961N/A// Set the current status for the service. 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 // 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 // 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 // Note: INTERROGATE *must* be supported by the service handler 1298N/A debug(
"Updating the service status. statusToSet=%d win32ExitCode=%d serviceExitCode=%d checkPoint=%d waitHint=%d",
5025N/A debug(
"Service start pending: no controls accepted.");
961N/A // do not accept any command when the service is starting up... 961N/A // fill in the status structure 961N/A // set the service status 961N/A}
// updateServiceStatus 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// The job of the serviceMain is 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// The serviceMain will return only when the service is terminated. 961N/A// ---------------------------------------------------- 961N/A // a checkpoint value indicate the progress of an operation 1295N/A debug(
"serviceMain: failed to create service bin path.");
961N/A // first register the service control handler to the SCM 1295N/A debug(
"serviceMain: failed to register service handler.");
961N/A // update the service status to START_PENDING 961N/A // create an event to signal the application termination 961N/A NULL,
// handle is not inherited by the child process 961N/A TRUE,
// event has to be reset manually after a signal 5025N/A // start the application if not already started 5025N/A // start is ok: do nothing for the moment. 961N/A // if all is ok wait for the application to die before we leave 5025N/A debug(
"checking in serviceMain: error interrogating status.");
5025N/A debug(
"checking in serviceMain serviceHandler: service stopped.");
961N/A // update the service status to STOPPED if it's not already done 961N/A// ---------------------------------------------------- 961N/A// Notify the serviceMain that service is now terminated. 961N/A// terminationEvent the event upon which serviceMain is blocked 961N/A// ---------------------------------------------------- 1298N/A debug(
"Faking a service termination so serviceMain can return.");
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 // If system is shuting down then stop the service 961N/A // update service status to STOP_PENDING 961N/A // let's try to stop the application whatever may be the status above 961N/A // again, let's ignore the above status and 961N/A // notify serviceMain that service has stopped 5385N/A debug(
"serviceHandler: The server could not be stopped.");
961N/A // We could not stop the server 961N/A // Request to pause the service 961N/A // ---------------------------- 961N/A // Request to resume the service 961N/A // ----------------------------- 961N/A // Interrogate the service status 961N/A // ------------------------------ 961N/A // Other codes are ignored 961N/A// --------------------------------------------------------------- 961N/A// Retrieve the binaryPathName from the SCM database for a given service. 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 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 // handle to the service 961N/A // if SCM exists then retrieve the config info of the service 1298N/A // buffer not big enough... 5385N/A debug(
"getBinaryPathName: error calling QueryServiceConfig. Code [%d]",
5385N/A debug(
"getBinaryPathName: the length of the binary path name is too big. serviceName='%s', binaryPath='%s'",
5385N/A debug(
"getBinaryPathName: error closing handle of service. Code [%d]",
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 // open Service Control Manager 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 // buffer is not big enough: try again with a proper size 1878N/A debug(
"getServiceList: second try generic error. Code [%d]",
961N/A // Data buffer is not large enough. This case should 961N/A // never happen as proper buffer size has been 961N/A // now elaborate the list of service to return... 1878N/A debug(
"Error getting binary path name of service: %s",
961N/A // close the handle to the SCM 961N/A // free the result buffer 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 // retrieve list of services 961N/A // go through the list of services and search for the service name 1878N/A debugError(
"Could not determine if the service name '%s' is in use because listing the services failed.",
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// 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 // this service name is already in use: try another one... 961N/A // this service name is not used so it's a good candidate 961N/A // an error occurred checking the service name 1298N/A debug(
"createServiceName returning serviceName='%s' and returnValue=%d",
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// The function returns SERVICE_RETURN_OK if we could create the service and 961N/A// SERVICE_RETURN_ERROR otherwise. 961N/A// --------------------------------------------------------------- 961N/A // - serviceName is the service name 969N/A // elaborate the service name based on the displayName provided 961N/A debug(
"createServiceInScm: openScm did not work.");
961N/A debug(
"createServiceInScm: createServiceName did not work.");
961N/A // add description field 1878N/A "Failed to add a description to the service '%s'. Last error = %d.",
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/A // stop the service if necessary 961N/A}
// removeServiceFromScm 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// 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/A // There is a valid serviceName for the command to run, so 5385N/A // OpenDJ is registered as a service. 961N/A // We could not find a serviceName for the command to run, so 961N/A // try to create the service. 1298N/A debug(
"Could not get a service name for command to run.");
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/A // There is a valid serviceName for the command to run, so 5385N/A // OpenDJ is registered as a service. 1295N/A debug(
"An error occurred getting the service status.");
969N/A// --------------------------------------------------------------- 969N/A// Function called to remove the service associated with a given 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// Returns 3 if an error occurred. 969N/A// --------------------------------------------------------------- 969N/A}
// removeServiceWithServiceName 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// Returns 3 if an error occurred. 961N/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 // register the service to the SCM. The function will return once the 961N/A // service is terminated. 961N/A "startService: StartServiceCtrlDispatcher did not work: \ 5025N/AERROR_FAILED_SERVICE_CONTROLLER_CONNECT.";
961N/A "startService: StartServiceCtrlDispatcher did not work: \ 961N/A "startService: StartServiceCtrlDispatcher did not work: \ 5025N/AERROR_SERVICE_ALREADY_RUNNING.";
961N/A "startService: StartServiceCtrlDispatcher did not work.";
961N/A debug(
"startService: Could not get service name.");
969N/A "Subcommand required: create, state, remove, start or cleanup.\n");
969N/A "Subcommand create requires instance dir, service name and description.\n");
969N/A "Subcommand state requires instance dir.\n");
969N/A "Subcommand remove requires instance dir.\n");
969N/A "Subcommand start requires instance dir.\n");
969N/A "Subcommand isrunning requires instance dir.\n");
969N/A "Subcommand cleanup requires service name.\n");