opendj-sdk/opends/build-tools/src/windows/EventLogMsg.mc
New file @@ -0,0 +1,103 @@ ;/* ; * 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 ; * trunk/opends/resource/legal-notices/OpenDS.LICENSE ; * or https://OpenDS.dev.java.net/OpenDS.LICENSE. ; * 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. ; */ ;/* ; * ========================================================================== ; * ; * Definition of the messages sent to the Windows Event Log. ; * ; * ========================================================================== ; */ ;/* ; * ========================================================================== ; * Header Section ; * ========================================================================== ; */ MessageIdTypedef = DWORD LanguageNames = ( English = 0x409 : MSG00409 ) SeverityNames = ( Success = 0x0 : WIN_STATUS_SEVERITY_SUCCESS Informational = 0x1 : WIN_STATUS_SEVERITY_INFORMATIONAL Warning = 0x2 : WIN_STATUS_SEVERITY_WARNING Error = 0x3 : WIN_STATUS_SEVERITY_ERROR ) FacilityNames = ( OPENDS = 0xFA0 : WIN_FACILITY_NAME_OPENDS ) ;/* ; * ========================================================================== ; * Message Definition ; * ========================================================================== ; */ MessageId = 0x1 Severity = Success Facility = OPENDS SymbolicName = WIN_EVENT_ID_SERVER_STARTED Language = English OpenDS has started. OpenDS is in %1. . MessageId = 0x2 Severity = Success Facility = OPENDS SymbolicName = WIN_EVENT_ID_SERVER_STOP Language = English OpenDS has shutdown. OpenDS is in %1. . MessageId = 0x3 Severity = Error Facility = OPENDS SymbolicName = WIN_EVENT_ID_SERVER_START_FAILED Language = English OpenDS failed in startup. OpenDS is in %1. . MessageId = 0x4 Severity = Error Facility = OPENDS SymbolicName = WIN_EVENT_ID_SERVER_STOP_FAILED Language = English OpenDS failed in stop. OpenDS is in %1. . MessageId = 0x5 Severity = Informational Facility = OPENDS SymbolicName = WIN_EVENT_ID_DEBUG Language = English %1 . opendj-sdk/opends/build-tools/src/windows/Makefile
New file @@ -0,0 +1,86 @@ # # 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 # trunk/opends/resource/legal-notices/OpenDS.LICENSE # or https://OpenDS.dev.java.net/OpenDS.LICENSE. # 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. # # This is the Makefile than can be used to generate the executables # winlauncher.exe and opends_service.exe that are used by OpenDS in # windows. # # The compilation of winlauncher.exe is straightforward but in the case of # opends_service.exe uses a Message File called EventLogMsg.mc which # makes the compilation a little bit more complex. # During compilation the first step is to generate EventLogMsg.h and # EventLogMsg.res using the rc.exe and mc.exe utilities. # # EventLogMsg.h contains some references to the message IDs that are sent to # the Windows Event Log and is required in order service.c to be compiled. # Once the EvenLogMsg.h file is generated we can compile the service.c and # common.c and finally we link the service.obj, common.obj and # EventLogMsg.res files and we generate the opends_service.exe executable. # CC=cl SERVICE_PROGNAME=opends_service.exe WINLAUNCHER_PROGNAME=winlauncher.exe LINKER=link -nologo LIBS=advapi32.lib CFLAGS= -D_WINDOWS -nologo -MD -W3 -O2 -G6 RC=rc MC=mc SRCS = common.c winlauncher.c service.c SERVICE_OBJS = common.obj service.obj WINLAUNCHER_OBJS = common.obj winlauncher.obj EVENTLOG_H = EventLogMsg.h MC_FILE = EventLogMsg.mc RC_FILE = EventLogMsg.rc RES_FILE = EventLogMsg.res .c.obj: $(CC) $(CFLAGS) -c $< -Fo$@ $(RES_FILE): $(MC) $(MC_FILE) $(RC) /fo $(RES_FILE) $(RC_FILE) all: $(SERVICE_PROGNAME) $(WINLAUNCHER_PROGNAME) $(SERVICE_PROGNAME) : $(RES_FILE) $(SERVICE_OBJS) $(LINKER) /OUT:$(SERVICE_PROGNAME) $(RES_FILE) $(SERVICE_OBJS) $(LIBS) $(WINLAUNCHER_PROGNAME) : $(WINLAUNCHER_OBJS) $(LINKER) $(WINLAUNCHER_OBJS) /OUT:$(WINLAUNCHER_PROGNAME) clean: del $(SERVICE_OBJS) $(EVENTLOG_H) $(WINLAUNCHER_OBJS) $(RC_FILE) $(RES_FILE) $(SERVICE_PROGNAME) $(WINLAUNCHER_PROGNAME) core opendj-sdk/opends/build-tools/src/windows/README
@@ -27,37 +27,55 @@ WHAT is winlauncher.exe ======================== winlauncher.exe is a small windows executable that is intended to be used by the command line files to perform certain operations. It is not intended to be a final user interface and that is one of the reasons why is placed under the lib subdirectory. winlauncher.exe is a small windows executable that is intended to be used by the command line files to perform certain operations. It is not intended to be a final user interface and that is one of the reasons why is placed under the lib subdirectory. See the comments in winlauncher.c file for more information. INSTRUCTIONS TO COMPILE winlauncher See the comments in winlauncher.c file and common.c for more information. WHAT is opends_service.exe ======================== Using Visual C++ and the command line you must set your environment variables to point to your Visual Studio install. You can set the environment variables by changing to the \bin subdirectory of your Visual C++ installation and running the VCVARS32.bat batch file. This will basically update your PATH, INCLUDE and LIB environment variables to point to the correct paths of your Visual Studio install. Go to the directory where the source files winlauncher.c and winlauncher.h are and launch the following command: opends_service.exe is a small windows executable that is intended to be used by the command line files to be able to run OpenDS as a windows service (or not to configure it as windows service). It is not intended to be a final user interface and that is one of the reasons why is placed under the lib subdirectory. > cl winlauncher.c See the comments in service.c file and common.c for more information. INSTRUCTIONS TO COMPILE winlauncher.exe ======================== Using Visual C++ and the command line you must set your environment variables to point to your Visual Studio install. You can set the environment variables by changing to the \bin subdirectory of your Visual C++ installation and running the VCVARS32.bat batch file. This will basically update your PATH, INCLUDE and LIB environment variables to point to the correct paths of your Visual Studio install. Go to the directory where the source files winlauncher.c, winlauncher.h, common.c and common.h are and launch the following command: > cl winlauncher.c common.c This will generate the binary winlauncher.exe. NOTE: An alternative to this mode is to compile winlauncher.exe using the Makefile by running: > nmake all (See INSTRUCTIONS TO COMPILE opends_service.exe for more information). ************************ Using Visual C++ graphical interface you just must to Create a Project and add winlauncher.c and winlauncher.h to the project. You can build winlauncher.c and then winlauncher.exe with the commands in the menu 'Build'. winlauncher.c, winlauncher.h, common.c and common.h to the project. You can build winlauncher.c and then winlauncher.exe with the commands in the menu 'Build'. ************************ @@ -67,6 +85,28 @@ Go to the directory where the source files winlauncher.c and winlauncher.h are and launch the following command: > gcc winlauncher.c -o winlauncher.exe > gcc common.c winlauncher.c -o winlauncher.exe This will generate the binary winlauncher.exe. INSTRUCTIONS TO COMPILE opends_service.exe ======================== service.c (the main code file for opends_service.exe) uses windows resources and so The fastest way of generating opends_service.exe is to do it using the command line. Using Visual C++ and the command line you must set your environment variables to point to your Visual Studio install. You can set the environment variables by changing to the \bin subdirectory of your Visual C++ installation and running the VCVARS32.bat batch file. Then go to the directory where the source files are and run the following command: > nmake all This command will generate both opends_service.exe and winlauncher.exe. See the comments in the file Makefile for more information. opendj-sdk/opends/build-tools/src/windows/common.c
New file @@ -0,0 +1,96 @@ /* * 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 * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * 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 "common.h" // ---------------------------------------------------- // Function used to create a process with the given command. // The information about the process is stored in procInfo. // The function returns TRUE if the process could be created // and FALSE otherwise. // ---------------------------------------------------- BOOL createChildProcess(char* command, BOOL background, PROCESS_INFORMATION* procInfo) { BOOL createOk; STARTUPINFO startInfo; // info to pass to the new process DWORD processFlag; // background process flag // reset process info first ZeroMemory(procInfo, sizeof(PROCESS_INFORMATION)); // initialize handles to pass to the child process ZeroMemory(&startInfo, sizeof(STARTUPINFO)); startInfo.cb = sizeof(STARTUPINFO); startInfo.dwFlags |= STARTF_USESTDHANDLES; // use handles above // Create the child process processFlag = background == TRUE ? DETACHED_PROCESS : 0; createOk = CreateProcess( NULL, // application name command, // command line NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited processFlag, // creation flags NULL, // use parent's environment NULL, // use parent's current directory &startInfo, // STARTUPINFO pointer procInfo // receives PROCESS_INFORMATION ); return createOk; } // createChildProcess // ---------------------------------------------------- // Function used to launch a process for the given command // If the process could be created it returns the pid of // the created process and -1 otherwise. // ---------------------------------------------------- int spawn(const char* command, BOOL background) { DWORD childPid; // child's pid PROCESS_INFORMATION procInfo; // info on the new process BOOL createOk; createOk = createChildProcess((char*)command, background, &procInfo); if(createOk) { childPid = procInfo.dwProcessId; } if (childPid != -1) { return childPid; } else { return -1; } } // spawn opendj-sdk/opends/build-tools/src/windows/common.h
New file @@ -0,0 +1,35 @@ /* * 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 * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * 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. */ // Just some functions and constants to be used by winlauncher.c // and service.c #include <Windows.h> int spawn(const char* command, BOOL background); BOOL createChildProcess(char* command, BOOL background, PROCESS_INFORMATION* procInfo); opendj-sdk/opends/build-tools/src/windows/service.c
New file @@ -0,0 +1,2167 @@ /* * 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 * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * 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; SERVICE_STATUS_HANDLE *_serviceStatusHandle; HANDLE _terminationEvent = NULL; char *_instanceDir = NULL; HANDLE _eventLog = NULL; BOOL DEBUG = FALSE; // ---------------------------------------------------- // 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. // ---------------------------------------------------- ServiceReturnCode registerServiceHandler ( char* serviceName, LPHANDLER_FUNCTION serviceHandler, SERVICE_STATUS_HANDLE* serviceStatusHandle ) { ServiceReturnCode returnValue; // register the service to the service control dispatcher (SCM) *serviceStatusHandle = RegisterServiceCtrlHandler ( serviceName, (LPHANDLER_FUNCTION) serviceHandler ); if (serviceStatusHandle == NULL) { returnValue = SERVICE_RETURN_ERROR; } else { returnValue = SERVICE_RETURN_OK; } 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. // --------------------------------------------------- void debug(char* msg) { if (DEBUG == TRUE) { if (_eventLog != NULL) { const char* args[1]; args[0] = msg; // report the event ReportEvent( _eventLog, // event log handle EVENTLOG_INFORMATION_TYPE, // info, warning, error WIN_FACILITY_NAME_OPENDS, // unique category for OPENDS WIN_EVENT_ID_DEBUG, NULL, // no user security identifier 1, // number of args 0, // raw data size (const char**)args, // args NULL // no war data ); } else { fprintf(stdout, "%s\n", msg); } } } // --------------------------------------------------- // 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. // --------------------------------------------------- BOOL reportLogEvent(WORD eventType, DWORD eventId, WORD argCount, const char** args) { BOOL reportOk; if (argCount > 0) { // report the event reportOk = ReportEvent( _eventLog, // event log handle eventType, // info, warning, error WIN_FACILITY_NAME_OPENDS, // unique category for OPENDS eventId, NULL, // no user security identifier argCount, // number of args 0, // raw data size args, // args NULL // no raw data ); } else { // report the event reportOk = ReportEvent( _eventLog, // event log handle eventType, // info, warning, error WIN_FACILITY_NAME_OPENDS, // unique category for OPENDS eventId, 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. // --------------------------------------------------------------- ServiceReturnCode openScm(DWORD accessRights, SC_HANDLE *scm) { ServiceReturnCode returnValue; // open Service Control Manager *scm = (SC_HANDLE)OpenSCManager ( NULL, // local machine NULL, // ServicesActive database accessRights // desired rights ); if (scm == NULL) { debug("scm is NULL."); returnValue = SERVICE_RETURN_ERROR; } else { returnValue = SERVICE_RETURN_OK; } 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. // --------------------------------------------------- BOOLEAN createRegistryKey(char* serviceName) { // true if the server is already registered BOOL alreadyRegistered = FALSE; // false as soon as an error occurs BOOL success = TRUE; // handle to the created/opened key HKEY hkey = NULL; // Create the event source subkey (or open it if it already exists) char subkey [MAX_REGISTRY_KEY]; long result; DWORD nbCategories = 1; // 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. char execName [MAX_PATH]; GetModuleFileName ( NULL, execName, MAX_PATH ); // Check whether the Registry Key is already created, // If so don't create a new one. sprintf (subkey, EVENT_LOG_KEY, serviceName); result = RegOpenKeyEx( HKEY_LOCAL_MACHINE, subkey, 0, KEY_QUERY_VALUE, // to query the values of a registry key. &hkey // OUT ); if (result == ERROR_SUCCESS) { alreadyRegistered = TRUE; success = FALSE; } if (success) { DWORD disposition; result = RegCreateKeyEx( HKEY_LOCAL_MACHINE, // 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."); success = FALSE; } } if (success) { result = RegSetValueEx( hkey, // subkey handle "EventMessageFile", // value name 0, // must be zero REG_EXPAND_SZ, // value type (LPBYTE)execName, // pointer to value data (DWORD) (lstrlen(execName) + 1) * sizeof(TCHAR) // length of value data ); if (result != ERROR_SUCCESS) { success = FALSE; } } // Set the supported event types if (success) { DWORD supportedTypes = EVENTLOG_SUCCESS | EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; result = RegSetValueEx( hkey, // subkey handle "TypesSupported", // value name 0, // must be zero REG_DWORD, // value type (LPBYTE) &supportedTypes, // pointer to value data sizeof(DWORD) // length of value data ); if (result != ERROR_SUCCESS) { success = FALSE; } } // Set the category message file if (success) { result = RegSetValueEx( hkey, // subkey handle "CategoryMessageFile", // value name 0, // must be zero REG_EXPAND_SZ, // value type (LPBYTE)execName, // pointer to value data (DWORD) (lstrlen(execName) + 1) *sizeof(TCHAR) // length of value data ); if (result != ERROR_SUCCESS) { success = FALSE; } } // 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 (LPBYTE) &nbCategories, // pointer to value data sizeof(DWORD) // length of value data ); if (result != ERROR_SUCCESS) { success = FALSE; } } // close the key before leaving if (hkey != NULL) { 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. // --------------------------------------------------- BOOLEAN removeRegistryKey(char* serviceName) { BOOL returnValue; // Create the event source subkey (or open it if it already exists) char subkey [MAX_REGISTRY_KEY]; long result; HKEY hkey = NULL; // Check whether the Registry Key is already created, // If so don't create a new one. sprintf (subkey, EVENT_LOG_KEY, serviceName); result = RegOpenKeyEx( HKEY_LOCAL_MACHINE, subkey, 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 { result = RegDeleteKey (HKEY_LOCAL_MACHINE, subkey); 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. // --------------------------------------------------- HANDLE registerEventLog(char *serviceName) { HANDLE eventLog = NULL; // subkey under Eventlog registry key char subkey [MAX_SERVICE_NAME]; sprintf (subkey, serviceName); eventLog = RegisterEventSource( NULL, // local host subkey // subkey under Eventlog registry key ); return eventLog; } // registerEventLog // --------------------------------------------------- // Deregister the source of event. // --------------------------------------------------- void deregisterEventLog() { if (_eventLog != NULL) { DeregisterEventSource(_eventLog); } } // ---------------------------------------------------- // 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. // ---------------------------------------------------- ServiceReturnCode isServerRunning(BOOL *running) { ServiceReturnCode returnValue; char* relativePath = "\\locks\\server.lock"; char lockFile[MAX_PATH]; if (strlen(relativePath)+strlen(_instanceDir)+1 < MAX_PATH) { int fd; sprintf(lockFile, "%s%s", _instanceDir, relativePath); fd = _open(lockFile, _O_RDWR); if (fd != -1) { returnValue = SERVICE_RETURN_OK; // Test if there is a lock /* Lock some bytes and read them. Then unlock. */ if(_locking(fd, LK_NBLCK, 1) != -1) { *running = FALSE; } else { if (errno == EACCES) { *running = TRUE; } else { *running = FALSE; returnValue = SERVICE_RETURN_ERROR; debug("Unexpected error locking"); } } _close(fd); } else { *running = FALSE; returnValue = SERVICE_RETURN_ERROR; } } else { *running = FALSE; returnValue = SERVICE_RETURN_ERROR; } 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. // ---------------------------------------------------- ServiceReturnCode doStartApplication() { ServiceReturnCode returnValue; // init out params char* relativePath = "\\bin\\start-ds.bat"; char command[COMMAND_SIZE]; if (strlen(relativePath)+strlen(_instanceDir)+1 < COMMAND_SIZE) { sprintf(command, "\"%s%s\" --windowsNetStart", _instanceDir, relativePath); // launch the command if (spawn(command, FALSE) != 0) { // Try to see if server is really running int nTries = 10; BOOL running = FALSE; // Wait to be able to launch the java process in order it to free the lock // on the file. Sleep(3000); while ((nTries > 0) && !running) { if (isServerRunning(&running) != SERVICE_RETURN_OK) { break; } if (!running) { Sleep(2000); } } if (running) { returnValue = SERVICE_RETURN_OK; } else { returnValue = SERVICE_RETURN_ERROR; } } else { returnValue = SERVICE_RETURN_ERROR; } } else { returnValue = SERVICE_RETURN_ERROR; } 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. // ---------------------------------------------------- ServiceReturnCode doStopApplication() { ServiceReturnCode returnValue; // init out params char* relativePath = "\\bin\\stop-ds.bat"; char command[COMMAND_SIZE]; if (strlen(relativePath)+strlen(_instanceDir)+1 < COMMAND_SIZE) { sprintf(command, "\"%s%s\" --windowsNetStop", _instanceDir, relativePath); // launch the command if (spawn(command, FALSE) != 0) { // Try to see if server is really stopped int nTries = 10; BOOL running = TRUE; // Wait to be able to launch the java process in order it to free the lock // on the file. Sleep(3000); while ((nTries > 0) && running) { if (isServerRunning(&running) != SERVICE_RETURN_OK) { break; } if (running) { Sleep(2000); } } if (!running) { returnValue = SERVICE_RETURN_OK; } else { returnValue = SERVICE_RETURN_ERROR; } } else { returnValue = SERVICE_RETURN_ERROR; } } else { returnValue = SERVICE_RETURN_ERROR; } 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. // --------------------------------------------------------------- ServiceReturnCode createServiceBinPath(char* serviceBinPath) { ServiceReturnCode returnValue = SERVICE_RETURN_OK; // get the full path to the current executable file char fileName [MAX_PATH]; DWORD result = GetModuleFileName ( NULL, // get the path to the current executable file fileName, MAX_PATH ); if (result == 0) { // failed to get the path of the executable file returnValue = SERVICE_RETURN_ERROR; } else { if (result == MAX_PATH) { // buffer was too small, executable name is probably not valid returnValue = SERVICE_RETURN_ERROR; } else { if (strlen(fileName) + strlen(" start ") + strlen(_instanceDir) < MAX_PATH) { sprintf(serviceBinPath, "%s start \"%s\"", fileName, _instanceDir); } else { // buffer was too small, executable name is probably not valid returnValue = SERVICE_RETURN_ERROR; } } } 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). // ---------------------------------------------------- ServiceReturnCode getServiceName(char* cmdToRun, char* serviceName) { // returned status code ServiceReturnCode returnValue = SERVICE_RETURN_OK; // retrieve list of services ServiceDescriptor* serviceList = NULL; int nbServices = -1; returnValue = getServiceList(&serviceList, &nbServices); // go through the list of services and search for the service name // whose display name is [displayName] if (returnValue == SERVICE_RETURN_OK) { int i; returnValue = SERVICE_RETURN_ERROR; if (nbServices > 0) { for (i = 0; i<nbServices; i++) { ServiceDescriptor curService = serviceList[i]; if (curService.cmdToRun != NULL) { if (_stricmp(cmdToRun, curService.cmdToRun) == 0) { if (strlen(curService.serviceName) < MAX_SERVICE_NAME) { // This function assumes that there are at least // MAX_SERVICE_NAME (256) characters reserved in // servicename. sprintf(serviceName, curService.serviceName); returnValue = SERVICE_RETURN_OK; } 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. // ---------------------------------------------------- ServiceReturnCode updateServiceStatus ( DWORD statusToSet, DWORD win32ExitCode, DWORD serviceExitCode, DWORD checkPoint, DWORD waitHint, SERVICE_STATUS_HANDLE *serviceStatusHandle ) { ServiceReturnCode returnValue; // elaborate service type: // SERVICE_WIN32_OWN_PROCESS means this is not a driver and there is // only one service in the process DWORD serviceType = SERVICE_WIN32_OWN_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 // - No need to support PAUSE/CONTINUE // // Note: INTERROGATE *must* be supported by the service handler DWORD controls; SERVICE_STATUS serviceStatus; BOOL success; if (statusToSet == SERVICE_START_PENDING) { // do not accept any command when the service is starting up... controls = SERVICE_ACCEPT_NONE; } else { controls = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_CONTROL_INTERROGATE; } // fill in the status structure serviceStatus.dwServiceType = serviceType; serviceStatus.dwCurrentState = statusToSet; serviceStatus.dwControlsAccepted = controls; serviceStatus.dwWin32ExitCode = win32ExitCode; serviceStatus.dwServiceSpecificExitCode = serviceExitCode; serviceStatus.dwCheckPoint = checkPoint; serviceStatus.dwWaitHint = waitHint; // set the service status success = SetServiceStatus( *serviceStatusHandle, &serviceStatus ); if (!success) { returnValue = SERVICE_RETURN_ERROR; } else { returnValue = SERVICE_RETURN_OK; } 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. // ---------------------------------------------------- void serviceMain(int argc, char* argv[]) { // returned status char cmdToRun[MAX_PATH]; char serviceName[MAX_SERVICE_NAME]; ServiceReturnCode code; // a checkpoint value indicate the progress of an operation DWORD checkPoint = CHECKPOINT_FIRST_VALUE; SERVICE_STATUS_HANDLE serviceStatusHandle; code = createServiceBinPath(cmdToRun); if (code == SERVICE_RETURN_OK) { code = getServiceName(cmdToRun, serviceName); } if (code == SERVICE_RETURN_OK) { // first register the service control handler to the SCM code = registerServiceHandler(serviceName, (LPHANDLER_FUNCTION) serviceHandler, &serviceStatusHandle); if (code == SERVICE_RETURN_OK) { _serviceStatusHandle = &serviceStatusHandle; } } // update the service status to START_PENDING if (code == SERVICE_RETURN_OK) { _serviceCurStatus = SERVICE_START_PENDING; code = updateServiceStatus ( SERVICE_START_PENDING, NO_ERROR, 0, checkPoint++, TIMEOUT_CREATE_EVENT, _serviceStatusHandle); } // create an event to signal the application termination if (code == SERVICE_RETURN_OK) { _terminationEvent = CreateEvent( 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) { _serviceCurStatus = SERVICE_START_PENDING; updateServiceStatus ( _serviceCurStatus, NO_ERROR, 0, checkPoint++, TIMEOUT_START_SERVICE, _serviceStatusHandle ); } // start the application if (code == SERVICE_RETURN_OK) { WORD argCount = 1; const char *argc[] = {_instanceDir}; code = doStartApplication(); switch (code) { case SERVICE_RETURN_OK: // start is ok _serviceCurStatus = SERVICE_RUNNING; updateServiceStatus ( _serviceCurStatus, NO_ERROR, 0, CHECKPOINT_NO_ONGOING_OPERATION, TIMEOUT_NONE, _serviceStatusHandle ); reportLogEvent( EVENTLOG_SUCCESS, WIN_EVENT_ID_SERVER_STARTED, argCount, argc ); break; default: code = SERVICE_RETURN_ERROR; _serviceCurStatus = SERVICE_STOPPED; updateServiceStatus ( _serviceCurStatus, ERROR_SERVICE_SPECIFIC_ERROR, -1, CHECKPOINT_NO_ONGOING_OPERATION, TIMEOUT_NONE, _serviceStatusHandle); reportLogEvent( EVENTLOG_ERROR_TYPE, WIN_EVENT_ID_SERVER_START_FAILED, argCount, argc ); } } else { updateServiceStatus ( _serviceCurStatus, ERROR_SERVICE_SPECIFIC_ERROR, 0, CHECKPOINT_NO_ONGOING_OPERATION, TIMEOUT_NONE, _serviceStatusHandle); } // if all is ok wait for the application to die before we leave if (code == SERVICE_RETURN_OK) { WaitForSingleObject (_terminationEvent, INFINITE); } // update the service status to STOPPED if it's not already done if ((_serviceCurStatus != SERVICE_STOPPED) && (_serviceStatusHandle != NULL)) { _serviceCurStatus = SERVICE_STOPPED; updateServiceStatus ( _serviceCurStatus, NO_ERROR, 0, CHECKPOINT_NO_ONGOING_OPERATION, TIMEOUT_NONE, _serviceStatusHandle ); } } // serviceMain // ---------------------------------------------------- // Notify the serviceMain that service is now terminated. // // terminationEvent the event upon which serviceMain is blocked // ---------------------------------------------------- void doTerminateService(HANDLE terminationEvent) { SetEvent(terminationEvent); 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 // ---------------------------------------------------- void serviceHandler(DWORD controlCode) { ServiceReturnCode code; DWORD checkpoint; BOOL running; 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"); _serviceCurStatus = SERVICE_STOP_PENDING; checkpoint = CHECKPOINT_FIRST_VALUE; updateServiceStatus ( _serviceCurStatus, NO_ERROR, 0, checkpoint++, TIMEOUT_STOP_SERVICE, _serviceStatusHandle ); // let's try to stop the application whatever may be the status above // (best effort mode) code = doStopApplication(); if (code == SERVICE_RETURN_OK) { WORD argCount = 1; const char *argc[] = {_instanceDir}; _serviceCurStatus = SERVICE_STOPPED; updateServiceStatus ( _serviceCurStatus, NO_ERROR, 0, CHECKPOINT_NO_ONGOING_OPERATION, TIMEOUT_NONE, _serviceStatusHandle ); // again, let's ignore the above status and // notify serviceMain that service has stopped doTerminateService (_terminationEvent); reportLogEvent( EVENTLOG_SUCCESS, WIN_EVENT_ID_SERVER_STOP, argCount, argc ); } else { WORD argCount = 1; const char *argc[] = {_instanceDir}; // We could not stop the server reportLogEvent( EVENTLOG_ERROR_TYPE, WIN_EVENT_ID_SERVER_STOP_FAILED, argCount, argc ); } 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 // ------------------------------ case SERVICE_CONTROL_INTERROGATE: code = isServerRunning(&running); if (code != SERVICE_RETURN_OK) { } else if (running) { _serviceCurStatus = SERVICE_RUNNING; } else { _serviceCurStatus = SERVICE_STOPPED; } updateServiceStatus ( _serviceCurStatus, NO_ERROR, 0, CHECKPOINT_NO_ONGOING_OPERATION, TIMEOUT_NONE, _serviceStatusHandle ); 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. // --------------------------------------------------------------- ServiceReturnCode getBinaryPathName(HANDLE scm, char* serviceName, char* binPathName) { ServiceReturnCode returnValue; // pathtname to return char* binPathname = NULL; // handle to the service SC_HANDLE myService = NULL; BOOL getConfigOk = FALSE; DWORD configSize = 4096; LPQUERY_SERVICE_CONFIG serviceConfig = (LPQUERY_SERVICE_CONFIG)malloc(configSize); returnValue = SERVICE_RETURN_ERROR; // if SCM exists then retrieve the config info of the service if (scm != NULL) { myService = OpenService( scm, serviceName, SERVICE_QUERY_CONFIG ); } if (myService != NULL) { while (!getConfigOk) { DWORD bytesNeeded; getConfigOk = QueryServiceConfig( myService, serviceConfig, configSize, &bytesNeeded ); if (!getConfigOk) { DWORD errCode = GetLastError(); if (errCode == ERROR_INSUFFICIENT_BUFFER) { // buffer nor big enough... configSize += bytesNeeded; serviceConfig = (LPQUERY_SERVICE_CONFIG)realloc(serviceConfig, configSize); continue; } else { break; } } else { if (strlen(serviceConfig->lpBinaryPathName) < MAX_PATH) { sprintf(binPathName, serviceConfig->lpBinaryPathName); returnValue = SERVICE_RETURN_OK; } } } } // free buffers if (serviceConfig != NULL) { free(serviceConfig); } 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. // --------------------------------------------------------------- ServiceReturnCode getServiceList(ServiceDescriptor** serviceList, int *nbServices) { ServiceReturnCode returnValue; // open Service Control Manager SC_HANDLE scm = NULL; // get the list of services being configured in the SCM database // 1- first try with a single data structure ENUM_SERVICE_STATUS ENUM_SERVICE_STATUS serviceData; ENUM_SERVICE_STATUS* lpServiceData = &serviceData; DWORD dataSize = sizeof (serviceData); DWORD neededSize; DWORD resumeHandle = 0; unsigned long nbSvc = 0; if (openScm(SC_MANAGER_ENUMERATE_SERVICE, &scm) == SERVICE_RETURN_OK) { BOOL svcStatusOk = EnumServicesStatus( 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) { DWORD lastError = GetLastError(); if (lastError != ERROR_MORE_DATA) { char msg[200]; sprintf(msg, "getServiceList: generic error. Code [%d]", lastError); // error debug(msg); returnValue = SERVICE_RETURN_ERROR; } else { debug("getServiceList: error More Data."); // buffer is not big enough: try again with a proper size dataSize += neededSize; lpServiceData = (ENUM_SERVICE_STATUS*)calloc( dataSize, sizeof(ENUM_SERVICE_STATUS)); svcStatusOk = EnumServicesStatus( 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) { DWORD lastError = GetLastError(); if (lastError != ERROR_MORE_DATA) { returnValue = SERVICE_RETURN_ERROR; } else { // Data buffer is not large enough. This case should // never happen as proper buffer size has been // provided!... debug("getServiceList: buffer error"); returnValue = SERVICE_RETURN_ERROR; } } else { returnValue = SERVICE_RETURN_OK; } } } else { returnValue = SERVICE_RETURN_OK; } } else { returnValue = SERVICE_RETURN_ERROR; } // now elaborate the list of service to return... if (returnValue == SERVICE_RETURN_OK) { int i; int aux = (int)nbSvc; ServiceDescriptor* l; ENUM_SERVICE_STATUS* curService = lpServiceData; *nbServices = aux; if (aux > 0) { char binPath[MAX_PATH]; l = (ServiceDescriptor*)calloc(sizeof(ServiceDescriptor), aux); for (i = 0; i < aux; i++) { l[i].serviceName = strdup(curService->lpServiceName); l[i].displayName = strdup(curService->lpDisplayName); if (getBinaryPathName(scm, l[i].serviceName, binPath) == SERVICE_RETURN_OK) { l[i].cmdToRun = strdup(binPath); } curService++; } *serviceList = l; } } // close the handle to the SCM if (scm != NULL) { CloseServiceHandle (scm); // free the result buffer if (lpServiceData != NULL) { free (lpServiceData); } } 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. // --------------------------------------------------------------- ServiceReturnCode serviceNameInUse(char* serviceName) { ServiceReturnCode returnValue; // retrieve list of services ServiceDescriptor* serviceList = NULL; ServiceDescriptor curService; int nbServices = -1; int i; // go through the list of services and search for the service name if (getServiceList(&serviceList, &nbServices) == SERVICE_RETURN_OK) { returnValue = SERVICE_NOT_IN_USE; if (nbServices > 0) { for (i = 0; i < nbServices && (returnValue == SERVICE_NOT_IN_USE); i++) { curService = serviceList[i]; if (curService.serviceName == NULL) { debug("The service name is NULL.\n"); } else { if (strcmp (serviceName, curService.serviceName) == 0) { // found the service! returnValue = SERVICE_IN_USE; } } } free(serviceList); } } else { returnValue = SERVICE_RETURN_ERROR; } 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 OpenDS for the first OpenDS and // OpenDS-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). // --------------------------------------------------------------- ServiceReturnCode createServiceName(char* serviceName) { ServiceReturnCode returnValue = SERVICE_RETURN_OK; int i = 1; BOOL ended = FALSE; ServiceReturnCode nameInUseResult; while (!ended) { if (i == 1) { sprintf(serviceName, "OpenDS"); } else { sprintf(serviceName, "OpenDS-%d", i); } nameInUseResult = serviceNameInUse(serviceName); 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 ended = TRUE; } else { // an error occurred checking the service name returnValue = SERVICE_RETURN_ERROR; ended = TRUE; } } 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. // --------------------------------------------------------------- ServiceReturnCode createServiceInScm(char* displayName, char* description, char* cmdToRun) { ServiceReturnCode returnValue; SC_HANDLE scm = NULL; SC_HANDLE myService = NULL; // local vars // - serviceName is the service name char* serviceName = (char*) calloc(1, MAX_SERVICE_NAME); // elaborate the service name returnValue = createServiceName(serviceName); // create the service if (returnValue == SERVICE_RETURN_OK) { if (openScm(GENERIC_WRITE, &scm) != SERVICE_RETURN_OK) { returnValue = SERVICE_RETURN_ERROR; debug("createServiceInScm: openScm did not work."); } } else { returnValue = SERVICE_RETURN_ERROR; debug("createServiceInScm: createServiceName did not work."); } if (returnValue == SERVICE_RETURN_OK) { myService = CreateService( scm, serviceName, // name of service displayName, // 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 ((returnValue == SERVICE_RETURN_OK) && (myService == NULL)) { DWORD errCode = GetLastError(); if (errCode == ERROR_DUPLICATE_SERVICE_NAME) { returnValue = DUPLICATED_SERVICE_NAME; } else if (errCode == ERROR_SERVICE_EXISTS) { returnValue = SERVICE_ALREADY_EXISTS; } else { returnValue = SERVICE_RETURN_ERROR; } } // add description field if (returnValue == SERVICE_RETURN_OK) { BOOL success; SERVICE_DESCRIPTION serviceDescription; serviceDescription.lpDescription = description; success = ChangeServiceConfig2( myService, SERVICE_CONFIG_DESCRIPTION, (LPVOID) &serviceDescription ); if (!success) { returnValue = SERVICE_RETURN_ERROR; } } // close handles if (myService != NULL) { CloseServiceHandle (myService); } if (scm != NULL) { CloseServiceHandle (scm); } // 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. // --------------------------------------------------------------- ServiceReturnCode removeServiceFromScm(char* serviceName) { // local vars ServiceReturnCode returnValue = SERVICE_RETURN_OK; SC_HANDLE scm = NULL; SC_HANDLE myService = NULL; SERVICE_STATUS serviceStatus; returnValue = openScm(GENERIC_WRITE, &scm); // open the service if (returnValue == SERVICE_RETURN_OK) { myService = OpenService( scm, serviceName, SERVICE_ALL_ACCESS | DELETE ); if (myService == NULL) { returnValue = SERVICE_RETURN_ERROR; } } if (returnValue == SERVICE_RETURN_OK) { BOOL success = QueryServiceStatus( myService, &serviceStatus ); if (!success) { returnValue = SERVICE_RETURN_ERROR; } } // stop the service if necessary if (returnValue == SERVICE_RETURN_OK) { if (serviceStatus.dwCurrentState != SERVICE_STOPPED) { BOOL success = ControlService ( myService, SERVICE_CONTROL_STOP, &serviceStatus ); if (!success) { DWORD errCode = GetLastError(); if (errCode == ERROR_SERVICE_MARKED_FOR_DELETE) { returnValue = SERVICE_MARKED_FOR_DELETION; } else { returnValue = SERVICE_RETURN_ERROR; } } else { Sleep (500); } } } // remove the service if (returnValue == SERVICE_RETURN_OK) { BOOL success = DeleteService (myService); if (!success) { DWORD errCode = GetLastError(); if (errCode == ERROR_SERVICE_MARKED_FOR_DELETE) { returnValue = SERVICE_MARKED_FOR_DELETION; } else { returnValue = SERVICE_RETURN_ERROR; } } } // close handles if (myService != NULL) { CloseServiceHandle (myService); } if (scm != NULL) { CloseServiceHandle (scm); } 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 createService(char* displayName, char* description) { int returnCode = 0; char cmdToRun[MAX_PATH]; ServiceReturnCode code; code = createServiceBinPath(cmdToRun); if (code == SERVICE_RETURN_OK) { char serviceName[MAX_SERVICE_NAME]; code = getServiceName(cmdToRun, serviceName); if (code == SERVICE_RETURN_OK) { // There is a valid serviceName for the command to run, so // OpenDS is registered as a service. code = SERVICE_ALREADY_EXISTS; createRegistryKey(serviceName); 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. code = createServiceInScm(displayName, description, cmdToRun); if (code == SERVICE_RETURN_OK) { code = getServiceName(cmdToRun, serviceName); if (code == SERVICE_RETURN_OK) { createRegistryKey(serviceName); } } } } 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 cmdToRun[MAX_PATH]; char serviceName[MAX_SERVICE_NAME]; ServiceReturnCode code; code = createServiceBinPath(cmdToRun); if (code == SERVICE_RETURN_OK) { code = getServiceName(cmdToRun, serviceName); if (code == SERVICE_RETURN_OK) { // There is a valid serviceName for the command to run, so // OpenDS is registered as a service. fprintf(stdout, serviceName); returnCode = 0; } else { returnCode = 1; } } else { returnCode = 2; } return returnCode; } // serviceState // --------------------------------------------------------------- // 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 cmdToRun[MAX_PATH]; char serviceName[MAX_SERVICE_NAME]; ServiceReturnCode code; code = createServiceBinPath(cmdToRun); if (code == SERVICE_RETURN_OK) { code = getServiceName(cmdToRun, serviceName); if (code == SERVICE_RETURN_OK) { code = removeServiceFromScm(serviceName); switch (code) { case SERVICE_RETURN_OK: removeRegistryKey(serviceName); returnCode = 0; break; case SERVICE_MARKED_FOR_DELETION: removeRegistryKey(serviceName); returnCode = 2; break; default: returnCode = 3; } } 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]; char cmdToRun[MAX_PATH]; ServiceReturnCode code; code = createServiceBinPath(cmdToRun); if (code == SERVICE_RETURN_OK) { code = getServiceName(cmdToRun, serviceName); } if (code == SERVICE_RETURN_OK) { BOOL success; SERVICE_TABLE_ENTRY serviceTable[] = { {serviceName, (LPSERVICE_MAIN_FUNCTION) serviceMain}, {NULL, NULL} }; _eventLog = registerEventLog(serviceName); // register the service to the SCM. The function will return once the // service is terminated. success = StartServiceCtrlDispatcher(serviceTable); if (!success) { WORD argCount = 2; DWORD lastError = GetLastError(); const char *argc[2]; argc[0] = _instanceDir; if (lastError == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { 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."; } code = SERVICE_RETURN_ERROR; reportLogEvent( EVENTLOG_ERROR_TYPE, WIN_EVENT_ID_SERVER_START_FAILED, argCount, argc ); } deregisterEventLog(); } 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. // --------------------------------------------------------------- void updateDebugFlag(char* argv[], int argc, int startIndex) { int i; DEBUG = FALSE; for (i=startIndex; (i<argc) && !DEBUG; i++) { if (strcmp(argv[i], "--debug") == 0) { DEBUG = TRUE; } } } void formatMessage(DWORD msgId, int count, ...) { char buf[2048]; int result; va_list args; char execName [MAX_PATH]; GetModuleFileName ( NULL, execName, MAX_PATH ); if (count > 0) { va_start(args, count); // Retrieve the English message string. result = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE, (LPBYTE)execName, WIN_EVENT_ID_SERVER_STARTED, //msgId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buf, 2048, &args); } else { result = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE, (LPBYTE)execName, msgId, LANG_NEUTRAL, (LPTSTR) &buf, 2048, NULL); } if (execName != NULL) { fprintf(stderr, "The module is [%s]\n", execName); } else { fprintf(stderr, "The module is NULL\n"); } if (result > 0) { fprintf(stderr, "formatMessage worked: [%s]\n", buf); } else { fprintf(stderr, "formatMessage failed, error is: %d\n", GetLastError()); } } void logMsgTest(char *serviceName) { DWORD ids[] = {WIN_EVENT_ID_SERVER_STARTED, WIN_EVENT_ID_SERVER_STOP, WIN_EVENT_ID_SERVER_START_FAILED, WIN_EVENT_ID_SERVER_STOP_FAILED, WIN_EVENT_ID_DEBUG}; const char* args[] = {"c:\\temp\\OpenDS tarara"}; int evCount = 5; int i; _eventLog = registerEventLog(serviceName); for (i = 0; i<evCount; i++) { if (i != 5) { formatMessage(ids[i], 1, args[0]); if(reportLogEvent(EVENTLOG_SUCCESS, ids[i], 1, args)) { fprintf(stderr, "reportLogEvent successful.\n"); } else { fprintf(stderr, "reportLogEvent failed: %d.\n", GetLastError()); } } else { formatMessage(ids[i], 0); if (reportLogEvent(EVENTLOG_SUCCESS, ids[i], 1, args)) { fprintf(stderr, "reportLogEvent successful.\n"); } else { fprintf(stderr, "reportLogEvent failed: %d.\n", GetLastError()); } } } deregisterEventLog(); } int main(int argc, char* argv[]) { char* subcommand; int returnCode = 0; if (argc <= 1) { fprintf(stderr, "Subcommand required: create, state, remove or start\n"); returnCode = -1; } else { subcommand = argv[1]; if (strcmp(subcommand, "create") == 0) { if (argc <= 4) { fprintf(stderr, "Subcommand create requires instance dir, service name and description.\n"); returnCode = -1; } else { _instanceDir = strdup(argv[2]); updateDebugFlag(argv, argc, 5); returnCode = createService(argv[3], argv[4]); free(_instanceDir); } } else if (strcmp(subcommand, "state") == 0) { if (argc <= 2) { fprintf(stderr, "Subcommand state requires instance dir\n"); returnCode = -1; } else { _instanceDir = strdup(argv[2]); updateDebugFlag(argv, argc, 3); returnCode = serviceState(); free(_instanceDir); } } else if (strcmp(subcommand, "remove") == 0) { if (argc <= 2) { fprintf(stderr, "Subcommand remove requires instance dir\n"); returnCode = -1; } else { _instanceDir = strdup(argv[2]); updateDebugFlag(argv, argc, 3); returnCode = removeService(); free(_instanceDir); } } else if (strcmp(subcommand, "start") == 0) { if (argc <= 2) { fprintf(stderr, "Subcommand start requires instancedir.\n"); returnCode = -1; } else { _instanceDir = strdup(argv[2]); updateDebugFlag(argv, argc, 3); returnCode = startService(); free(_instanceDir); } } else if (strcmp(subcommand, "isrunning") == 0) { if (argc <= 2) { fprintf(stderr, "Subcommand isrunning requires instancedir.\n"); returnCode = -1; } else { BOOL running; ServiceReturnCode code; _instanceDir = strdup(argv[2]); updateDebugFlag(argv, argc, 3); code = isServerRunning(&running); if (code == SERVICE_RETURN_OK) { returnCode = 0; } else { returnCode = -1; } free(_instanceDir); } } else if (strcmp(subcommand, "logevents") == 0) { if (argc <= 2) { fprintf(stderr, "Subcommand logevents requires instancedir.\n"); returnCode = -1; } else { ServiceReturnCode code; char cmdToRun[MAX_PATH]; char serviceName[MAX_SERVICE_NAME]; _instanceDir = strdup(argv[2]); code = createServiceBinPath(cmdToRun); if (code == SERVICE_RETURN_OK) { code = getServiceName(cmdToRun, serviceName); } if (code == SERVICE_RETURN_OK) { logMsgTest(serviceName); returnCode = 0; } else { returnCode = -1; } free(_instanceDir); } } else { fprintf(stderr, "Unknown subcommand: [%s]\n", subcommand); returnCode = -1; } } return returnCode; } // main opendj-sdk/opends/build-tools/src/windows/service.h
New file @@ -0,0 +1,109 @@ /* * 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 * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * 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 <errno.h> #include <fcntl.h> #include <io.h> #include <stdio.h> #include <sys/locking.h> #include "common.h" #include "EventLogMsg.h" #define MAX_SERVICE_NAME 256 // ---------------------------------------------------- // Estimated time for a given operation (in ms). // Note: if the estimated value is too short then the service controler // may consider the service as not alive anymore! so the value // must be as precise as possible (better have it too big rather // than to small) // ---------------------------------------------------- #define TIMEOUT_NONE 0 #define TIMEOUT_CREATE_EVENT 5000 #define TIMEOUT_START_SERVICE 30000 #define TIMEOUT_STOP_SERVICE 30000 // ---------------------------------------------------- // The first value to use for checkpoints // ---------------------------------------------------- #define CHECKPOINT_FIRST_VALUE 1 // ---------------------------------------------------- // Checkpoint value to use to let the SCM knows that there is // no ongoing operation // ---------------------------------------------------- #define CHECKPOINT_NO_ONGOING_OPERATION 0 // ---------------------------------------------------- // Event Log Key. // ---------------------------------------------------- #define EVENT_LOG_KEY "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s" // ---------------------------------------------------- // Max size of the registry key // ---------------------------------------------------- #define MAX_REGISTRY_KEY 512 // ---------------------------------------------------- // Max size of the binary to run the service // ---------------------------------------------------- #define COMMAND_SIZE 2048 #define SERVICE_ACCEPT_NONE 0 typedef struct { char* serviceName; // the name of the service char* displayName; // the display name of the service char* cmdToRun; // the executable to run } ServiceDescriptor; typedef enum { SERVICE_RETURN_OK, SERVICE_RETURN_ERROR, SERVICE_IN_USE, SERVICE_NOT_IN_USE, DUPLICATED_SERVICE_NAME, SERVICE_ALREADY_EXISTS, SERVICE_MARKED_FOR_DELETION } ServiceReturnCode; ServiceReturnCode registerServiceHandler (char* serviceName, LPHANDLER_FUNCTION serviceHandler, SERVICE_STATUS_HANDLE* serviceStatusHandle); ServiceReturnCode serviceNameInUse(char* serviceName); ServiceReturnCode createServiceName(char* serviceName); ServiceReturnCode getServiceList(ServiceDescriptor** serviceList, int *nbServices); ServiceReturnCode createServiceBinPath(char* serviceBinPath); ServiceReturnCode getServiceName(char* cmdToRun, char* serviceName); ServiceReturnCode updateServiceStatus ( DWORD statusToSet, DWORD win32ExitCode, DWORD serviceExitCode, DWORD checkPoint, DWORD waitHint, SERVICE_STATUS_HANDLE *serviceStatusHandle ); void serviceHandler(DWORD controlCode); opendj-sdk/opends/build-tools/src/windows/winlauncher.c
@@ -1,30 +1,30 @@ /* * 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 * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * 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. */ * 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 * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * 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 "winlauncher.h" @@ -36,18 +36,18 @@ // ---------------------------------------------------- BOOL getPidFile(const char* instanceDir, char* pidFile, unsigned int maxSize) { BOOL returnValue; char* relativePath = "\\logs\\server.pid"; if ((strlen(relativePath) + strlen(instanceDir)) < maxSize) { sprintf(pidFile, "%s\\logs\\server.pid", instanceDir); returnValue = TRUE; } else { returnValue = FALSE; } return returnValue; BOOL returnValue; char* relativePath = "\\logs\\server.pid"; if ((strlen(relativePath) + strlen(instanceDir)) < maxSize) { sprintf(pidFile, "%s\\logs\\server.pid", instanceDir); returnValue = TRUE; } else { returnValue = FALSE; } return returnValue; } // getPidFile @@ -57,19 +57,19 @@ // ---------------------------------------------------- BOOL fileExists(const char *fileName) { struct stat finfo; BOOL returnValue = FALSE; if(stat(fileName, &finfo) < 0) { returnValue = FALSE; } else { returnValue = TRUE; } return returnValue; struct stat finfo; BOOL returnValue = FALSE; if(stat(fileName, &finfo) < 0) { returnValue = FALSE; } else { returnValue = TRUE; } return returnValue; } // fileExists @@ -80,28 +80,28 @@ // ---------------------------------------------------- BOOL deletePidFile(const char* instanceDir) { BOOL returnValue = FALSE; char pidFile[PATH_SIZE]; int nTries = 10; // Sometimes the lock on the system in windows takes time to be released. if (getPidFile(instanceDir, pidFile, PATH_SIZE)) BOOL returnValue = FALSE; char pidFile[PATH_SIZE]; int nTries = 10; // Sometimes the lock on the system in windows takes time to be released. if (getPidFile(instanceDir, pidFile, PATH_SIZE)) { while (fileExists(pidFile) && (nTries > 0) && !returnValue) { while (fileExists(pidFile) && (nTries > 0) && !returnValue) { if (remove(pidFile) == 0) { returnValue = TRUE; } else { Sleep(500); nTries--; } } if (remove(pidFile) == 0) { returnValue = TRUE; } else { Sleep(500); nTries--; } } return returnValue; } return returnValue; } // deletePidFile @@ -112,27 +112,35 @@ // ---------------------------------------------------- int getPid(const char* instanceDir) { int returnValue; char pidFile[PATH_SIZE]; FILE *f; char buf[BUF_SIZE]; int read; if (getPidFile(instanceDir, pidFile, PATH_SIZE)) int returnValue; char pidFile[PATH_SIZE]; FILE *f; char buf[BUF_SIZE]; int read; if (getPidFile(instanceDir, pidFile, PATH_SIZE)) { if ((f = fopen(pidFile, "r")) != NULL) { if ((f = fopen(pidFile, "r")) != NULL) { read = fread(buf, 1, sizeof(buf),f); } fclose(f); returnValue = (int)strtol(buf, (char **)NULL, 10); read = fread(buf, 1, sizeof(buf),f); } if (f != NULL) { fclose(f); returnValue = (int)strtol(buf, (char **)NULL, 10); } else { returnValue = 0; fprintf(stderr, "File %s could not be opened", pidFile); returnValue = 0; } return returnValue; } else { returnValue = 0; } return returnValue; } // getPid @@ -143,52 +151,52 @@ // ---------------------------------------------------- BOOL killProcess(int pid) { BOOL processDead; HANDLE procHandle = OpenProcess( PROCESS_TERMINATE // to terminate the process | PROCESS_QUERY_INFORMATION, // to get exit code FALSE, // handle is not inheritable pid ); if (procHandle == NULL) BOOL processDead; HANDLE procHandle = OpenProcess( PROCESS_TERMINATE // to terminate the process | PROCESS_QUERY_INFORMATION, // to get exit code FALSE, // handle is not inheritable pid ); if (procHandle == NULL) { // process already dead processDead = TRUE; } else { if (!TerminateProcess(procHandle, 0)) { // process already dead processDead = TRUE; // failed to terminate the process processDead = FALSE; } else { if (!TerminateProcess(procHandle, 0)) { // failed to terminate the process processDead = FALSE; } else { // wait for the process to end. DWORD exitCode; int nTries = 20; processDead = FALSE; while ((nTries > 0) && !processDead) { GetExitCodeProcess(procHandle, &exitCode); if (exitCode == STILL_ACTIVE) { // process is still alive, let's wait 1 sec and loop again Sleep(1000); nTries--; } else { processDead = TRUE; } } } CloseHandle(procHandle); // wait for the process to end. DWORD exitCode; int nTries = 20; processDead = FALSE; while ((nTries > 0) && !processDead) { GetExitCodeProcess(procHandle, &exitCode); if (exitCode == STILL_ACTIVE) { // process is still alive, let's wait 1 sec and loop again Sleep(1000); nTries--; } else { processDead = TRUE; } } } return processDead; CloseHandle(procHandle); } return processDead; } // killProcess // ---------------------------------------------------- @@ -199,103 +207,31 @@ // ---------------------------------------------------- BOOL createPidFile(const char* instanceDir, int pid) { BOOL returnValue = FALSE; char pidFile[PATH_SIZE]; FILE *f; if (getPidFile(instanceDir, pidFile, PATH_SIZE)) BOOL returnValue = FALSE; char pidFile[PATH_SIZE]; FILE *f; if (getPidFile(instanceDir, pidFile, PATH_SIZE)) { if ((f = fopen(pidFile, "w")) != NULL) { if ((f = fopen(pidFile, "w")) != NULL) { fprintf(f, "%d", pid); fclose (f); returnValue = TRUE; } else { returnValue = FALSE; } fprintf(f, "%d", pid); fclose (f); returnValue = TRUE; } else { returnValue = FALSE; returnValue = FALSE; } return returnValue; } else { returnValue = FALSE; } return returnValue; } // createPidFile // ---------------------------------------------------- // Function used to create a process with the given command. // The information about the process is stored in procInfo. // The function returns TRUE if the process could be created // and FALSE otherwise. // ---------------------------------------------------- BOOL createChildProcess(char* command, BOOL background, PROCESS_INFORMATION* procInfo) { BOOL createOk; STARTUPINFO startInfo; // info to pass to the new process DWORD processFlag; // background process flag // reset process info first ZeroMemory(procInfo, sizeof(PROCESS_INFORMATION)); // initialize handles to pass to the child process ZeroMemory(&startInfo, sizeof(STARTUPINFO)); startInfo.cb = sizeof(STARTUPINFO); startInfo.dwFlags |= STARTF_USESTDHANDLES; // use handles above // Create the child process processFlag = background == TRUE ? DETACHED_PROCESS : 0; createOk = CreateProcess( NULL, // application name command, // command line NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited processFlag, // creation flags NULL, // use parent's environment NULL, // use parent's current directory &startInfo, // STARTUPINFO pointer procInfo // receives PROCESS_INFORMATION ); if (!createOk) { fprintf(stderr, "Failed to create child process [%s]\n", command); } return createOk; } // createChildProcess // ---------------------------------------------------- // Function used to launch a process for the given command // If the process could be created it returns the pid of // the created process and -1 otherwise. // ---------------------------------------------------- int spawn(const char* command) { DWORD childPid; // child's pid PROCESS_INFORMATION procInfo; // info on the new process BOOL createOk; createOk = createChildProcess((char*)command, TRUE, &procInfo); if(createOk) { childPid = procInfo.dwProcessId; } if (childPid != -1) { return childPid; } else { return -1; } } // spawn // ---------------------------------------------------- // Elaborate the command line: "cmd arg1 arg2..." @@ -307,84 +243,84 @@ // ---------------------------------------------------- BOOL getCommandLine(const char* argv[], char* command, unsigned int maxSize) { int curCmdInd = 0; int i = 0; BOOL overflow = FALSE; while ((argv[i] != NULL) && !overflow) { const char* curarg = argv[i++]; if (i > 1) int curCmdInd = 0; int i = 0; BOOL overflow = FALSE; while ((argv[i] != NULL) && !overflow) { const char* curarg = argv[i++]; if (i > 1) { if (curCmdInd + strlen(" ") < maxSize) { if (curCmdInd + strlen(" ") < maxSize) { sprintf (&command[curCmdInd], " "); curCmdInd = strlen(command); } else { overflow = TRUE; } sprintf (&command[curCmdInd], " "); curCmdInd = strlen(command); } else { overflow = TRUE; } } if (curarg[0] != '\0') { int argInd = 0; if (curarg[0] == '"') { // there is a quote: no need to add extra quotes } else { while (curarg[argInd] != ' ' && curarg[argInd] != '\0' && curarg[argInd] != '\n') { argInd++; } } if (curarg[0] != '"' && curarg[argInd] == ' ') { if (curCmdInd + strlen("\"\"") + strlen(curarg) < maxSize) { // no begining quote and white space inside => add quotes sprintf (&command[curCmdInd], "\"%s\"", curarg); curCmdInd = strlen (command); } else { overflow = TRUE; } } else { if (curCmdInd + strlen(curarg) < maxSize) { // no white space or quotes detected, keep the arg as is sprintf (&command[curCmdInd], "%s", curarg); curCmdInd = strlen (command); } else { overflow = TRUE; } } if (curarg[0] != '\0') } else { if (curCmdInd + strlen("\"\"") < maxSize) { int argInd = 0; if (curarg[0] == '"') { // there is a quote: no need to add extra quotes } else { while (curarg[argInd] != ' ' && curarg[argInd] != '\0' && curarg[argInd] != '\n') { argInd++; } } if (curarg[0] != '"' && curarg[argInd] == ' ') { if (curCmdInd + strlen("\"\"") + strlen(curarg) < maxSize) { // no begining quote and white space inside => add quotes sprintf (&command[curCmdInd], "\"%s\"", curarg); curCmdInd = strlen (command); } else { overflow = TRUE; } } else { if (curCmdInd + strlen(curarg) < maxSize) { // no white space or quotes detected, keep the arg as is sprintf (&command[curCmdInd], "%s", curarg); curCmdInd = strlen (command); } else { overflow = TRUE; } } } else { if (curCmdInd + strlen("\"\"") < maxSize) { sprintf (&command[curCmdInd], "\"\""); curCmdInd = strlen (command); } else { overflow = TRUE; } sprintf (&command[curCmdInd], "\"\""); curCmdInd = strlen (command); } } return !overflow; else { overflow = TRUE; } } } return !overflow; } // getCommandLine // ---------------------------------------------------- @@ -410,31 +346,31 @@ // ---------------------------------------------------- int start(const char* instanceDir, char* argv[]) { int returnValue; int childPid; int returnValue; int childPid; char command[COMMAND_SIZE]; if (getCommandLine(argv, command, COMMAND_SIZE)) { childPid = spawn(command, TRUE); char command[COMMAND_SIZE]; if (getCommandLine(argv, command, COMMAND_SIZE)) if (childPid > 0) { childPid = spawn(command); if (childPid > 0) { createPidFile(instanceDir, childPid); returnValue = childPid; } else { returnValue = -1; } createPidFile(instanceDir, childPid); returnValue = childPid; } else { returnValue = -1; returnValue = -1; } return returnValue; } else { returnValue = -1; } return returnValue; } // start @@ -461,22 +397,22 @@ // ---------------------------------------------------- int stop(const char* instanceDir) { int returnCode = -1; int childPid; childPid = getPid(instanceDir); if (childPid != 0) int returnCode = -1; int childPid; childPid = getPid(instanceDir); if (childPid != 0) { if (killProcess(childPid)) { if (killProcess(childPid)) { returnCode = 0; deletePidFile(instanceDir); } returnCode = 0; deletePidFile(instanceDir); } return returnCode; } return returnCode; } // stop @@ -507,20 +443,20 @@ // ---------------------------------------------------- int launch(char* argv[]) { int returnValue; char command[COMMAND_SIZE]; if (getCommandLine(argv, command, COMMAND_SIZE)) { returnValue = spawn(command); } else { returnValue = -1; } return returnValue; int returnValue; char command[COMMAND_SIZE]; if (getCommandLine(argv, command, COMMAND_SIZE)) { returnValue = spawn(command, TRUE); } else { returnValue = -1; } return returnValue; } // launch // ---------------------------------------------------- @@ -534,28 +470,29 @@ // ---------------------------------------------------- int main(int argc, char* argv[]) { int returnCode; char* subcommand = argv[1]; char* instanceDir = argv[2]; argv += 3; if (strcmp(subcommand, "start") == 0) { returnCode = start(instanceDir, argv); } else if (strcmp(subcommand, "stop") == 0) { returnCode = stop(instanceDir); } else if (strcmp(subcommand, "launch") == 0) { returnCode = launch(argv); } else { fprintf(stderr, "Unknown subcommand: [%s]", subcommand); returnCode = -1; } return returnCode; int returnCode; char* subcommand = argv[1]; char* instanceDir = argv[2]; argv += 3; if (strcmp(subcommand, "start") == 0) { returnCode = start(instanceDir, argv); } else if (strcmp(subcommand, "stop") == 0) { returnCode = stop(instanceDir); } else if (strcmp(subcommand, "launch") == 0) { returnCode = launch(argv); } else { fprintf(stderr, "Unknown subcommand: [%s]", subcommand); returnCode = -1; } return returnCode; } opendj-sdk/opends/build-tools/src/windows/winlauncher.h
@@ -1,37 +1,38 @@ /* * 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 * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * 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. */ * 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 * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * 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 <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <process.h> #include <windows.h> #include "common.h" #define PATH_SIZE 1024 #define BUF_SIZE 1024 #define COMMAND_SIZE 2048 opendj-sdk/opends/build.xml
@@ -286,6 +286,10 @@ <fileset dir="${basedir}" includes="**/*.bat" excludes="build/**/* " /> <fileset dir="${basedir}" includes="**/*.ldif" excludes="build/**/*" /> <fileset dir="${basedir}" includes="**/*.txt" excludes="build/**/*" /> <fileset dir="${basedir}" includes="**/*.c" excludes="build/**/*" /> <fileset dir="${basedir}" includes="**/*.h" excludes="build/**/*" /> <fileset dir="${basedir}" includes="**/*.mc" excludes="build/**/*" /> <fileset dir="${basedir}" includes="**/Makefile" excludes="build/**/*" /> <fileset dir="${scripts.dir}" includes="**/*" /> </checkcopyrightdates> </target> @@ -316,6 +320,10 @@ <fileset dir="${basedir}" includes="**/*.bat" excludes="build/**/* " /> <fileset dir="${basedir}" includes="**/*.ldif" excludes="build/**/*" /> <fileset dir="${basedir}" includes="**/*.txt" excludes="build/**/*" /> <fileset dir="${basedir}" includes="**/*.c" excludes="build/**/*" /> <fileset dir="${basedir}" includes="**/*.h" excludes="build/**/*" /> <fileset dir="${basedir}" includes="**/*.mc" excludes="build/**/*" /> <fileset dir="${basedir}" includes="**/Makefile" excludes="build/**/*" /> <fileset dir="${scripts.dir}" includes="**/*" /> </checkeolstyle> </target> opendj-sdk/opends/lib/opends_service.exeBinary files differ
opendj-sdk/opends/lib/winlauncher.exeBinary files differ
opendj-sdk/opends/resource/bin/start-ds
@@ -114,39 +114,11 @@ --configClass org.opends.server.extensions.ConfigFileHandler \ --configFile "${CONFIG_FILE}" --checkStartability "${@}" EC=${?} if test ${EC} -ne 99 if test ${EC} -eq 99 then exit ${EC} fi # See if an "-N" or a "--nodetach" argument was provided as a command-line # argument. If it was, then don't use nohup to send to the background, and # send all output to both the console and a lot file. NODETACH=0 for ARG in "${@}" do if test "${ARG}" = "-N" then NODETACH=1 else ARG=`echo ${ARG} | tr '[A-Z]' '[a-z]'` if test "${ARG}" = "--nodetach" then NODETACH=1 fi fi done if test ${NODETACH} -eq 1 then echo $$ > "${PID_FILE}" rm -f "${PID_FILE}" "${LOG_FILE}" exec "${JAVA_BIN}" ${JAVA_ARGS} ${SCRIPT_NAME_ARG} \ org.opends.server.core.DirectoryServer \ --configClass org.opends.server.extensions.ConfigFileHandler \ --configFile "${CONFIG_FILE}" "${@}" else # # run detach # touch "${STARTING_FILE}" nohup "${JAVA_BIN}" ${JAVA_ARGS} ${SCRIPT_NAME_ARG} \ org.opends.server.core.DirectoryServer \ @@ -156,4 +128,23 @@ "${JAVA_BIN}" -Xms8M -Xmx8M org.opends.server.tools.WaitForFileDelete \ --targetFile "${STARTING_FILE}" --logFile "${LOG_FILE}" exit ${?} else if test ${EC} -eq 100 then # # run no detach # echo $$ > "${PID_FILE}" rm -f "${PID_FILE}" "${LOG_FILE}" exec "${JAVA_BIN}" ${JAVA_ARGS} ${SCRIPT_NAME_ARG} \ org.opends.server.core.DirectoryServer \ --configClass org.opends.server.extensions.ConfigFileHandler \ --configFile "${CONFIG_FILE}" "${@}" else # # an error or the server is already started. Just return the code provided # by checkstartability # exit ${EC} fi fi opendj-sdk/opends/resource/bin/start-ds.bat
@@ -58,13 +58,17 @@ set SCRIPT_NAME_ARG=-Dorg.opends.server.scriptName=start-ds set NODETACH=0 for %%x in (%*) DO if "%%x" == "-N" set NODETACH=1 for %%x in (%*) DO if "%%x" == "--nodetach" set NODETACH=1 "%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.core.DirectoryServer --configClass org.opends.server.extensions.ConfigFileHandler --configFile "%DIR_HOME%\config\config.ldif" --checkStartability %* if "%NODETACH%" == "1" goto runNoDetach goto runDetach if %errorlevel% == 98 goto serverAlreadyStarted if %errorlevel% == 99 goto runDetach if %errorlevel% == 100 goto runNoDetach if %errorlevel% == 101 goto runAsService if %errorlevel% == 102 goto runDetachCalledByWinService goto end :serverAlreadyStarted goto end :runNoDetach if not exist "%DIR_HOME%\logs\server.out" echo. > "%DIR_HOME%\logs\server.out" @@ -74,14 +78,28 @@ :runDetach "%JAVA_BIN%" %JAVA_ARGS% org.opends.server.core.DirectoryServer --configClass org.opends.server.extensions.ConfigFileHandler --configFile "%DIR_HOME%\config\config.ldif" --checkStartability %* if not %errorlevel% == 99 goto end if not exist "%DIR_HOME%\logs\server.out" echo. > "%DIR_HOME%\logs\server.out" if not exist "%DIR_HOME%\logs\server.starting" echo. > "%DIR_HOME%\logs\server.starting" "%DIR_HOME%\lib\winlauncher.exe" start "%DIR_HOME%" "%JAVA_BIN%" %JAVA_ARGS% org.opends.server.core.DirectoryServer --configClass org.opends.server.extensions.ConfigFileHandler --configFile "%DIR_HOME%\config\config.ldif" %* "%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.WaitForFileDelete --targetFile "%DIR_HOME%\logs\server.starting" --logFile "%DIR_HOME%\logs\server.out" goto end :runDetachCalledByWinService rem We write the output of the start command to the winwervice.out file. if not exist "%DIR_HOME%\logs\server.out" echo. > "%DIR_HOME%\logs\server.out" if not exist "%DIR_HOME%\logs\server.starting" echo. > "%DIR_HOME%\logs\server.starting" echo. > "%DIR_HOME%\logs\server.startingservice" echo. > "%DIR_HOME%\logs\winservice.out" "%DIR_HOME%\lib\winlauncher.exe" start "%DIR_HOME%" "%JAVA_BIN%" %JAVA_ARGS% org.opends.server.core.DirectoryServer --configClass org.opends.server.extensions.ConfigFileHandler --configFile "%DIR_HOME%\config\config.ldif" %* "%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.WaitForFileDelete --targetFile "%DIR_HOME%\logs\server.starting" --logFile "%DIR_HOME%\logs\server.out" --outputFile "%DIR_HOME%\logs\winservice.out" erase "%DIR_HOME%\logs\server.startingservice" goto end :runAsService "%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.StartWindowsService "%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.WaitForFileDelete --targetFile "%DIR_HOME%\logs\server.startingservice" rem Type the contents the winwervice.out file and delete it. if exist "%DIR_HOME%\logs\winservice.out" type "%DIR_HOME%\logs\winservice.out" if exist "%DIR_HOME%\logs\winservice.out" erase "%DIR_HOME%\logs\winservice.out" :end opendj-sdk/opends/resource/bin/stop-ds
@@ -105,87 +105,105 @@ export SCRIPT_NAME_ARG # If there were no arguments (or only the -R argument was passed) we assume that # the server to be stopped is the local server. If this is the case we check if # the server is running or not. # If the server is running then try to stop the server with a kill command. If # there are more arguments, try to stop the server using LDAP protocol. NO_ARG_OR_ONLY_RESTART=1 RESTART=0 for ARG in "${@}" do if test "${ARG}" != "-R" then if test "${ARG}" != "--restart" then NO_ARG_OR_ONLY_RESTART=0 else RESTART=1 fi else RESTART=1 fi done "${JAVA_BIN}" ${JAVA_ARGS} ${SCRIPT_NAME_ARG} \ org.opends.server.tools.StopDS --checkStoppability "${@}" EC=${?} if test ${NO_ARG_OR_ONLY_RESTART} -eq 1 STOPPED=1 EXIT_CODE=1 MUST_START_USING_SYSTEM_CALL=1 MUST_STOP_USING_SYSTEM_CALL=1 if test ${EC} -eq 98 # # Already stopped and nothing else to do. # then # Use the code in StopDS class to know if the server is already # stopped. An exit code of 99 means that the server is stopped. STOPPED=0 "${JAVA_BIN}" ${JAVA_ARGS} ${SCRIPT_NAME_ARG} \ org.opends.server.tools.StopDS --checkStoppability EC=${?} if test ${EC} -ne 99 else if test ${EC} -eq 99 # # Already stopped and must start locally. # then STOPPED=1 fi EXIT_CODE=0 if test "${STOPPED}" -eq 1 then if test -f "${INSTANCE_ROOT}/logs/server.pid" STOPPED=0 MUST_START_USING_SYSTEM_CALL=0 else if test ${EC} -eq 100 then kill `cat "${INSTANCE_ROOT}/logs/server.pid"` EXIT_CODE=${?} if test "${EXIT_CODE}" -eq 0 # # Stop using system call # MUST_STOP_USING_SYSTEM_CALL=0 else if test ${EC} -eq 101 then # # Restart using system call # MUST_STOP_USING_SYSTEM_CALL=0 MUST_START_USING_SYSTEM_CALL=0 else if test ${EC} -ne 102 then "${JAVA_BIN}" -Xms8M -Xmx8M \ org.opends.server.tools.WaitForFileDelete \ --targetFile "${INSTANCE_ROOT}/logs/server.pid" \ --logFile "${INSTANCE_ROOT}/logs/errors" EXIT_CODE=${?} if test "${EXIT_CODE}" -eq 0 then STOPPED=0 fi exit ${EC} fi fi fi fi # Delete the pid file if the server is stopped (this can occur if the process has # been killed using kill -9). if test "{$STOPPED}" -eq 0 then if test -f "${INSTANCE_ROOT}/logs/server.pid" then rm "${INSTANCE_ROOT}/logs/server.pid" fi fi # Now if the user wants to restart the server, try to restart it if the server # is stopped. if test "${RESTART}" -eq 1 then if test "${STOPPED}" -eq 0 then "${INSTANCE_ROOT}/bin/start-ds" EXIT_CODE=${?} fi fi exit ${EXIT_CODE} fi if test ${MUST_STOP_USING_SYSTEM_CALL} -eq 0 then if test -f "${INSTANCE_ROOT}/logs/server.pid" then kill `cat "${INSTANCE_ROOT}/logs/server.pid"` EXIT_CODE=${?} if test ${EXIT_CODE} -eq 0 then "${JAVA_BIN}" -Xms8M -Xmx8M org.opends.server.tools.WaitForFileDelete \ --targetFile "${INSTANCE_ROOT}/logs/server.pid" \ --logFile "${INSTANCE_ROOT}/logs/errors" EXIT_CODE=${?} if test ${EXIT_CODE} -eq 0 then STOPPED=0 fi fi fi fi # Delete the pid file if the server is stopped (this can occur if the process # has been killed using kill -9). if test ${STOPPED} -eq 0 then if test -f "${INSTANCE_ROOT}/logs/server.pid" then rm "${INSTANCE_ROOT}/logs/server.pid" fi fi # Now if the user wants to restart the server, try to restart it if the server # is stopped. if test ${MUST_START_USING_SYSTEM_CALL} -eq 0 then if test ${STOPPED} -eq 0 then "${INSTANCE_ROOT}/bin/start-ds" EXIT_CODE=${?} exit ${EXIT_CODE} fi # # The user does not want to start the server locally and it is already stopped. # Just exit. # else if test ${STOPPED} -eq 0 then exit 0 fi fi # If we've gotten here, then we should try to stop the server over LDAP. "${JAVA_BIN}" ${JAVA_ARGS} ${SCRIPT_NAME_ARG} \ org.opends.server.tools.StopDS "${@}" org.opends.server.tools.StopDS "${@}" opendj-sdk/opends/resource/bin/stop-ds.bat
@@ -57,60 +57,52 @@ :setClassPath FOR %%x in ("%DIR_HOME%\lib\*.jar") DO call "%DIR_HOME%\bin\setcp.bat" %%x "%JAVA_BIN%" -Xms8M -Xmx8M %SCRIPT_NAME_ARG% org.opends.server.tools.StopDS --checkStoppability %* set RESTART=0 set NO_ARG_OR_ONLY_RESTART=1 for %%x in (%*) DO set NO_ARG_OR_ONLY_RESTART=0 if "%NO_ARG_OR_ONLY_RESTART%" == "1" goto execute for %%x in (%*) DO if "%%x" == "-R" set RESTART=1 for %%x in (%*) DO if "%%x" == "--restart" set RESTART=1 goto testParameter1 :testParameter1 if not "%1" == "-R" goto testParameter1b goto testParameter2 :testParameter1b if not "%1" == "--restart" goto execute goto testParameter2 :testParameter2 if "%2" == "" set NO_ARG_OR_ONLY_RESTART=1 if "%NO_ARG_OR_ONLY_RESTART%" == "1" goto execute if not "%2" == "-R" goto testParameter2b goto testParameter3 :testParameter2b if not "%2" == "--restart" goto execute goto testParameter3 :testParameter3 if not "%3" == "" goto execute set NO_ARG_OR_ONLY_RESTART=1 goto execute :execute if "%NO_ARG_OR_ONLY_RESTART%" == "0" goto stopWithLDAP rem Use the code in StopDS class to know if the server is already rem stopped. An exit code of 99 means that the server is stopped. "%JAVA_BIN%" %JAVA_ARGS% %SCRIPT_NAME_ARG% org.opends.server.tools.StopDS --checkStoppability if %errorlevel% == 99 goto serverStopped if not exist "%DIR_HOME%\logs\server.pid" goto stopWithLDAP "%DIR_HOME%\lib\winlauncher.exe" stop "%DIR_HOME%" if not %errorlevel% == 0 goto end :serverStopped if exist "%DIR_HOME%\logs\server.pid" erase "%DIR_HOME%\logs\server.pid" if "%RESTART%" == "1" "%DIR_HOME%\bin\start-ds.bat" if %errorlevel% == 98 goto serverAlreadyStopped if %errorlevel% == 99 goto startUsingSystemCall if %errorlevel% == 100 goto stopUsingSystemCall if %errorlevel% == 101 goto restartUsingSystemCall if %errorlevel% == 102 goto stopUsingProtocol if %errorlevel% == 103 goto stopAsWindowsService if %errorlevel% == 104 goto restartAsWindowsService rem An error or we display usage goto end :stopWithLDAP :serverAlreadyStopped if exist "%DIR_HOME%\logs\server.pid" erase "%DIR_HOME%\logs\server.pid" goto end :startUsingSystemCall "%DIR_HOME%\bin\start-ds.bat" goto end :stopUsingSystemCall "%DIR_HOME%\lib\winlauncher.exe" stop "%DIR_HOME%" goto end :restartUsingSystemCall "%DIR_HOME%\lib\winlauncher.exe" stop "%DIR_HOME%" if not %errorlevel% == 0 goto end goto startUsingSystemCall :stopUsingProtocol call "%~dP0\_client-script.bat" %* goto end :stopAsWindowsService "%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.StopWindowsService goto end :restartAsWindowsService "%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.StopWindowsService if not %errorlevel% == 0 goto end "%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.StartWindowsService "%JAVA_BIN%" -Xms8M -Xmx8M org.opends.server.tools.WaitForFileDelete --targetFile "%DIR_HOME%\logs\server.startingservice" rem Type the contents the winwervice.out file and delete it. if exist "%DIR_HOME%\logs\winservice.out" type "%DIR_HOME%\logs\winservice.out" if exist "%DIR_HOME%\logs\winservice.out" erase "%DIR_HOME%\logs\winservice.out" goto end :end opendj-sdk/opends/resource/bin/windowsservice.bat
New file @@ -0,0 +1,33 @@ @echo off rem CDDL HEADER START rem rem The contents of this file are subject to the terms of the rem Common Development and Distribution License, Version 1.0 only rem (the "License"). You may not use this file except in compliance rem with the License. rem rem You can obtain a copy of the license at rem trunk/opends/resource/legal-notices/OpenDS.LICENSE rem or https://OpenDS.dev.java.net/OpenDS.LICENSE. rem See the License for the specific language governing permissions rem and limitations under the License. rem rem When distributing Covered Code, include this CDDL HEADER in each rem file and include the License file at rem trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, rem add the following below this CDDL HEADER, with the fields enclosed rem by brackets "[]" replaced with your own identifying information: rem Portions Copyright [yyyy] [name of copyright owner] rem rem CDDL HEADER END rem rem rem Portions Copyright 2007 Sun Microsystems, Inc. setlocal set OPENDS_INVOKE_CLASS="org.opends.server.tools.ConfigureWindowsService" set SCRIPT_NAME_ARG="-Dorg.opends.server.scriptName=windowsservice" call "%~dP0\_client-script.bat" %* opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java
@@ -71,6 +71,10 @@ */ START_ERROR, /** * Error enabling the Windows service. */ WINDOWS_SERVICE_ERROR, /** * A bug (for instance when we throw an IllegalStateException). */ BUG opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java
@@ -98,7 +98,16 @@ * This is required because the usage message contains '{' characters that * mess up the MessageFormat.format method. */ String msg = getMsg("setup-launcher-usage"); String msg; if (Utils.isWindows()) { msg= getMsg("setup-launcher-usage-windows"); } else { msg= getMsg("setup-launcher-usage-unix"); } msg = msg.replace("{0}", arg); System.err.println(msg); System.exit(1); opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressStep.java
@@ -68,6 +68,10 @@ */ STARTING_SERVER, /** * Enabling Windows service. */ ENABLING_WINDOWS_SERVICE, /** * Installation finished successfully. */ FINISHED_SUCCESSFULLY, opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
@@ -46,6 +46,7 @@ import org.opends.quicksetup.util.Utils; import org.opends.server.util.SetupUtils; /** * This is an abstract class that is in charge of actually performing the * installation. @@ -860,6 +861,18 @@ } /** * This methods enables this server as a Windows service. * @throws InstallException if something goes wrong. */ protected void enableWindowsService() throws InstallException { notifyListeners(getFormattedProgress( getMsg("progress-enabling-windows-service"))); InstallerHelper helper = new InstallerHelper(); helper.enableWindowsService(); } /** * This methods starts the server. * @throws InstallException if something goes wrong. */ @@ -1043,6 +1056,8 @@ getMsg("summary-importing-automatically-generated"))); hmSummary.put(InstallProgressStep.STARTING_SERVER, getFormattedSummary(getMsg("summary-starting"))); hmSummary.put(InstallProgressStep.ENABLING_WINDOWS_SERVICE, getFormattedSummary(getMsg("summary-enabling-windows-service"))); String cmd; if (Utils.isWindows()) opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java
@@ -84,6 +84,33 @@ MSGID_DIRECTORY_SERVER_STARTED); } /** * This methods enables this server as a Windows service. * @throws InstallException if something goes wrong. */ protected void enableWindowsService() throws InstallException { int code = org.opends.server.tools.ConfigureWindowsService.enableService( System.out, System.err); String errorMessage = ResourceProvider.getInstance().getMsg( "error-enabling-windows-service"); switch (code) { case org.opends.server.tools.ConfigureWindowsService.SERVICE_ENABLE_SUCCESS: break; case org.opends.server.tools.ConfigureWindowsService.SERVICE_ALREADY_ENABLED: break; default: throw new InstallException(InstallException.Type.WINDOWS_SERVICE_ERROR, errorMessage, null); } } private String getThrowableMsg(String key, Throwable t) { return getThrowableMsg(key, null, t); opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java
@@ -142,6 +142,13 @@ writeJavaHome(); if (Utils.isWindows()) { notifyListeners(getTaskSeparator()); status = InstallProgressStep.ENABLING_WINDOWS_SERVICE; enableWindowsService(); } if (getUserData().getStartServer()) { notifyListeners(getTaskSeparator()); @@ -211,6 +218,7 @@ hmTime.put(InstallProgressStep.IMPORTING_LDIF, 20); hmTime.put(InstallProgressStep.IMPORTING_AUTOMATICALLY_GENERATED, 20); hmTime.put(InstallProgressStep.ENABLING_WINDOWS_SERVICE, 5); hmTime.put(InstallProgressStep.STARTING_SERVER, 10); int totalTime = 0; @@ -234,6 +242,11 @@ InstallProgressStep.IMPORTING_AUTOMATICALLY_GENERATED); break; } if (Utils.isWindows()) { totalTime += hmTime.get(InstallProgressStep.ENABLING_WINDOWS_SERVICE); steps.add(InstallProgressStep.ENABLING_WINDOWS_SERVICE); } if (getUserData().getStartServer()) { totalTime += hmTime.get(InstallProgressStep.STARTING_SERVER); opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartDownloader.java
@@ -244,6 +244,10 @@ { ratio = 110; } else if (urls[i].endsWith("aspectjrt.jar")) { ratio = 10; } else { ratio = (100 / urls.length); opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java
@@ -180,6 +180,13 @@ startServer(); } if (Utils.isWindows()) { notifyListeners(getTaskSeparator()); status = InstallProgressStep.ENABLING_WINDOWS_SERVICE; enableWindowsService(); } status = InstallProgressStep.FINISHED_SUCCESSFULLY; notifyListeners(null); @@ -240,6 +247,7 @@ hmTime.put(InstallProgressStep.IMPORTING_LDIF, 20); hmTime.put(InstallProgressStep.IMPORTING_AUTOMATICALLY_GENERATED, 20); hmTime.put(InstallProgressStep.ENABLING_WINDOWS_SERVICE, 5); hmTime.put(InstallProgressStep.STARTING_SERVER, 10); int totalTime = 0; @@ -267,6 +275,11 @@ InstallProgressStep.IMPORTING_AUTOMATICALLY_GENERATED); break; } if (Utils.isWindows()) { totalTime += hmTime.get(InstallProgressStep.ENABLING_WINDOWS_SERVICE); steps.add(InstallProgressStep.ENABLING_WINDOWS_SERVICE); } if (getUserData().getStartServer()) { totalTime += hmTime.get(InstallProgressStep.STARTING_SERVER); opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties
@@ -31,8 +31,8 @@ # # Setup command line messages # setup-launcher-usage=This utility may be used to setup the Directory Server.\n\ Usage: {0} {options}\n where {options} include:\n\ setup-launcher-usage-unix=This utility may be used to setup the Directory \ Server.\n\Usage: {0} {options}\n where {options} include:\n\ --cli\n\ Specifies to use the command line setup. If not specified the \ graphical\n\ interface will be launched.\n\ -H or --help\n Displays usage information for this program.\n\n\ @@ -64,6 +64,41 @@ -W {filename} or --rootUserPasswordFile {filename}\n Specifies the path \ to a file containing the password for the initial Administrative\n\ User \ for the Directory Server. setup-launcher-usage-windows=This utility may be used to setup the Directory \ Server.\n\Usage: {0} {options}\n where {options} include:\n\ --cli\n\ Specifies to use the command line setup. If not specified the \ graphical\n\ interface will be launched.\n\ -H or --help\n Displays usage information for this program.\n\n\ The following options will only be taken into account if the option --cli \n\ (command line) is specified\n\ -s or --silentInstall\n Perform a silent installation.\n\ -b {baseDN} or --baseDN {baseDN}\n\ Specifies the base DN for user \ information in the Directory Server.\n Multiple base DNs may be provided by \ using this option multiple times.\n\ -a or --addBaseEntry\n Indicates whether to create the base entry in the \ Directory Server\n database.\n\ -i {ldifFile} or --importLDIF {ldifFile}\n Specifies the path to an LDIF \ file containing data that should be added to\n the Directory Server \ database. Multiple LDIF files may be provided by\n using this option \ multiple times.\n\ -d {numEntries} or --sampleData {numEntries}\n Specifies that the \ database should be populated with the specified number\n\ of sample \ entries.\n\ -p {port} or --ldapPort {port}\n Specifies the port on which the \ Directory Server should listen for LDAP\n communication.\n\ -j {jmxPort} or --jmxPort {jmxPort}\n Specifies the port on which the \ Directory Server should listen for JMX\n communication.\n\ -S or --skipPortCheck\n Skip the check to determine whether the \ specified LDAP port is usable.\n\ -D {rootDN} or --rootUserDN {rootDN}\n Specifies the DN for the initial \ Administrative User for the Directory Server.\n\ -w {password} or --rootUserPassword {password}\n Specifies the password \ for the initial Administrative User for the Directory Server.\n\ -W {filename} or --rootUserPasswordFile {filename}\n Specifies the path \ to a file containing the password for the initial Administrative\n\ User \ for the Directory Server.\n\ -n or --noWindowsService\n Do not enable OpenDS to run as a Windows \ Service. setup-launcher-launching-gui=Launching graphical setup... setup-launcher-gui-launched-failed=\n\nThe graphical Setup launch failed.\n\n\ Launching command line Setup... @@ -489,6 +524,7 @@ summary-importing-automatically-generated=Importing Automatically-Generated \ Data... summary-starting=Starting Directory Server... summary-enabling-windows-service=Enabling Windows Service... summary-install-finished-successfully=<b>OpenDS QuickSetup Completed \ Successfully.</b><br>OpenDS is now installed in {0}.<br><br>Visit the \ <a href="https://opends.dev.java.net/public/docs/user-docs/OpenDS-QuickReference.html"> \ @@ -499,6 +535,7 @@ summary-install-finished-with-error=An error occurred. Check 'Details' text \ area for more information. summary-stopping=Stopping Directory Server... summary-disabling-windows-service=Disabling Windows Service... summary-deleting-external-db-files=Deleting Database Files outside the \ Installation Path... summary-deleting-external-log-files=Deleting Log Files outside the \ @@ -508,12 +545,12 @@ Path... summary-uninstall-finished-successfully-remove-jarfiles=<b>OpenDS Uninstall \ Completed Successfully.</b><br><br>To complete the uninstallation, you must \ delete manually the following files:<br>{0} delete manually the following files and directories:\n{0} summary-uninstall-finished-successfully=<b>OpenDS Uninstall Completed \ Successfully.</b> summary-uninstall-finished-successfully-remove-jarfiles-cli=OpenDS Uninstall \ Completed Successfully.\nTo complete the uninstallation, you must \ delete manually the following files:\n{0} delete manually the following files and directories:\n{0} summary-uninstall-finished-successfully-cli=OpenDS Uninstall Completed \ Successfully. summary-uninstall-finished-with-error=An error occurred. Check 'Details' text \ @@ -536,6 +573,8 @@ ({0} Entries): progress-starting=Starting Directory Server: progress-stopping=Stopping Directory Server: progress-enabling-windows-service=Enabling Windows Service... progress-disabling-windows-service=Disabling Windows Service... progress-deleting-external-db-files=Deleting Database Files outside the \ Installation Path: progress-deleting-external-log-files=Deleting Log Files outside the \ @@ -563,6 +602,8 @@ error-creating-temp-file=An error occurred creating the temporary file. error-writing-to-temp-file=An error occurred writing to temporary file {0}. error-configuring=Error Configuring Directory Server. error-enabling-windows-service=Error Enabling Windows service. error-disabling-windows-service=Error Disabling Windows service. error-creating-base-entry=Error Creating Base Entry. error-importing-ldif=Error Importing LDIF File. error-import-automatically-generated=Error Importing Automatically- Generated \ opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallException.java
@@ -56,6 +56,10 @@ */ STOP_ERROR, /** * Error disabling the Windows service. */ WINDOWS_SERVICE_ERROR, /** * A bug (for instance when we throw an IllegalStateException). */ BUG opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressStep.java
@@ -43,6 +43,10 @@ */ STOPPING_SERVER, /** * Disabling Windows Service. */ DISABLING_WINDOWS_SERVICE, /** * Removing External Database files. */ DELETING_EXTERNAL_DATABASE_FILES, opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java
@@ -28,10 +28,12 @@ package org.opends.quicksetup.uninstaller; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -46,6 +48,8 @@ import org.opends.quicksetup.util.ProgressMessageFormatter; import org.opends.quicksetup.util.Utils; import org.opends.server.tools.ConfigureWindowsService; /** * This class is in charge of performing the uninstallation of Open DS. * @@ -66,6 +70,8 @@ private UninstallException ue; private Boolean isWindowsServiceEnabled; /** * Uninstaller constructor. * @param userData the object containing the information provided by the user @@ -149,6 +155,8 @@ getFormattedSummary(getMsg("summary-uninstall-not-started"))); hmSummary.put(UninstallProgressStep.STOPPING_SERVER, getFormattedSummary(getMsg("summary-stopping"))); hmSummary.put(UninstallProgressStep.DISABLING_WINDOWS_SERVICE, getFormattedSummary(getMsg("summary-disabling-windows-service"))); hmSummary.put(UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES, getFormattedSummary(getMsg("summary-deleting-external-db-files"))); hmSummary.put(UninstallProgressStep.DELETING_EXTERNAL_LOG_FILES, @@ -163,7 +171,16 @@ { if (userData.getRemoveLibrariesAndTools()) { String[] arg = {getLibrariesPath()}; String[] arg = new String[1]; if (Utils.isWindows()) { arg[0] = getUninstallBatFile()+getLineBreak()+ getTab()+getLibrariesPath(); } else { arg[0] = getLibrariesPath(); } successMsg = getMsg( "summary-uninstall-finished-successfully-remove-jarfiles-cli", arg); @@ -201,6 +218,7 @@ HashMap<UninstallProgressStep, Integer> hmTime = new HashMap<UninstallProgressStep, Integer>(); hmTime.put(UninstallProgressStep.STOPPING_SERVER, 15); hmTime.put(UninstallProgressStep.DISABLING_WINDOWS_SERVICE, 5); hmTime.put(UninstallProgressStep.DELETING_EXTERNAL_DATABASE_FILES, 30); hmTime.put(UninstallProgressStep.DELETING_EXTERNAL_LOG_FILES, 5); hmTime.put(UninstallProgressStep.REMOVING_EXTERNAL_REFERENCES, 5); @@ -214,6 +232,11 @@ totalTime += hmTime.get(UninstallProgressStep.STOPPING_SERVER); steps.add(UninstallProgressStep.STOPPING_SERVER); } if (isWindowsServiceEnabled()) { totalTime += hmTime.get(UninstallProgressStep.DISABLING_WINDOWS_SERVICE); steps.add(UninstallProgressStep.DISABLING_WINDOWS_SERVICE); } totalTime += hmTime.get(UninstallProgressStep.DELETING_INSTALLATION_FILES); steps.add(UninstallProgressStep.DELETING_INSTALLATION_FILES); @@ -482,8 +505,18 @@ */ private void doUninstall() { PrintStream origErr = System.err; PrintStream origOut = System.out; try { PrintStream err = new ErrorPrintStream(); PrintStream out = new OutputPrintStream(); if (!Utils.isCli()) { System.setErr(err); System.setOut(out); } boolean displaySeparator = false; if (getUserData().getStopServer()) { @@ -491,6 +524,12 @@ stopServer(); displaySeparator = true; } if (isWindowsServiceEnabled()) { status = UninstallProgressStep.DISABLING_WINDOWS_SERVICE; disableWindowsService(); displaySeparator = true; } Set<String> dbsToDelete = getUserData().getExternalDbsToRemove(); if (dbsToDelete.size() > 0) @@ -562,6 +601,11 @@ String msg = getFormattedError(ue, true); notifyListeners(msg); } if (!Utils.isCli()) { System.setErr(origErr); System.setOut(origOut); } } /** @@ -882,6 +926,43 @@ } /** * Returns the path to the quicksetup jar file. * @return the path to the quicksetup jar file. */ private String getQuicksetupJarPath() { return Utils.getPath(getLibrariesPath(), "quicksetup.jar"); } /** * Returns the path to the opends jar file. * @return the path to the opends jar file. */ private String getOpenDSJarPath() { return Utils.getPath(getLibrariesPath(), "OpenDS.jar"); } /** * Returns the path to the aspectj jar file. * @return the path to the aspectj jar file. */ private String getAspectJJarPath() { return Utils.getPath(getLibrariesPath(), "aspectjrt.jar"); } /** * Returns the path to the uninstall.bat file. * @return the path to the uninstall.bat file. */ private String getUninstallBatFile() { return Utils.getPath(Utils.getInstallPathFromClasspath(), "uninstall.bat"); } /** * Returns the path to the backup files under the install path. * @return the path to the backup files under the install path. */ @@ -1142,8 +1223,12 @@ */ class InstallationFilesToDeleteFilter implements FileFilter { File quicksetupFile = new File(getQuicksetupJarPath()); File openDSFile = new File(getOpenDSJarPath()); File librariesFile = new File(getLibrariesPath()); File uninstallBatFile = new File(getUninstallBatFile()); File installationPath = new File(Utils.getInstallPathFromClasspath()); /** * {@inheritDoc} @@ -1171,8 +1256,15 @@ }; boolean accept = !installationPath.equals(file)&& !equalsOrDescendant(file, librariesFile); !installationPath.equals(file) && !librariesFile.equals(file) && !quicksetupFile.equals(file) && !openDSFile.equals(file); if (accept && Utils.isWindows() && Utils.isCli()) { accept = !uninstallBatFile.equals(file); } for (int i=0; i<uData.length && accept; i++) { @@ -1183,4 +1275,162 @@ return accept; } } private boolean isWindowsServiceEnabled() { if (isWindowsServiceEnabled == null) { if (ConfigureWindowsService.serviceState(null, null) == ConfigureWindowsService.SERVICE_STATE_ENABLED) { isWindowsServiceEnabled = Boolean.TRUE; } else { isWindowsServiceEnabled = Boolean.FALSE; } } return isWindowsServiceEnabled.booleanValue(); } /** * This methods disables this server as a Windows service. * @throws UninstallException if something goes wrong. */ protected void disableWindowsService() throws UninstallException { notifyListeners(getFormattedProgress( getMsg("progress-disabling-windows-service"))); int code = ConfigureWindowsService.disableService(System.out, System.err); String errorMessage = getMsg("error-disabling-windows-service"); switch (code) { case ConfigureWindowsService.SERVICE_DISABLE_SUCCESS: break; case ConfigureWindowsService.SERVICE_ALREADY_DISABLED: break; default: throw new UninstallException( UninstallException.Type.WINDOWS_SERVICE_ERROR, errorMessage, null); } } /** * This class is used to notify the UninstallProgressUpdateListeners of events * that are written to the standard error. These classes just create an * ErrorPrintStream and then they do a call to System.err with it. * * The class just reads what is written to the standard error, obtains an * formatted representation of it and then notifies the * UninstallProgressUpdateListeners with the formatted messages. * */ protected class ErrorPrintStream extends PrintStream { private boolean isFirstLine; /** * Default constructor. * */ public ErrorPrintStream() { super(new ByteArrayOutputStream(), true); isFirstLine = true; } /** * {@inheritDoc} */ public void println(String msg) { if (isFirstLine) { notifyListeners(getFormattedLogError(msg)); } else { notifyListeners(formatter.getLineBreak() + getFormattedLogError(msg)); } isFirstLine = false; } /** * {@inheritDoc} */ public void write(byte[] b, int off, int len) { if (b == null) { throw new NullPointerException("b is null"); } if (off + len > b.length) { throw new IndexOutOfBoundsException( "len + off are bigger than the length of the byte array"); } println(new String(b, off, len)); } } /** * This class is used to notify the UninstallProgressUpdateListeners of events * that are written to the standard output. These classes just create an * OutputPrintStream and then they do a call to System.out with it. * * The class just reads what is written to the standard output, obtains an * formatted representation of it and then notifies the * UninstallProgressUpdateListeners with the formatted messages. * */ protected class OutputPrintStream extends PrintStream { private boolean isFirstLine; /** * Default constructor. * */ public OutputPrintStream() { super(new ByteArrayOutputStream(), true); isFirstLine = true; } /** * {@inheritDoc} */ public void println(String msg) { if (isFirstLine) { notifyListeners(getFormattedLog(msg)); } else { notifyListeners(formatter.getLineBreak() + getFormattedLog(msg)); } isFirstLine = false; } /** * {@inheritDoc} */ public void write(byte[] b, int off, int len) { if (b == null) { throw new NullPointerException("b is null"); } if (off + len > b.length) { throw new IndexOutOfBoundsException( "len + off are bigger than the length of the byte array"); } println(new String(b, off, len)); } } } opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -127,6 +127,7 @@ import org.opends.server.schema.TelephoneNumberEqualityMatchingRule; import org.opends.server.schema.TelephoneNumberSubstringMatchingRule; import org.opends.server.schema.TelephoneNumberSyntax; import org.opends.server.tools.ConfigureWindowsService; import org.opends.server.types.AcceptRejectWarn; import org.opends.server.types.AttributeType; import org.opends.server.types.AttributeUsage; @@ -154,6 +155,7 @@ import org.opends.server.types.Schema; import org.opends.server.types.WritabilityMode; import org.opends.server.util.MultiOutputStream; import org.opends.server.util.SetupUtils; import org.opends.server.util.TimeThread; import org.opends.server.util.Validator; import org.opends.server.util.args.ArgumentException; @@ -205,6 +207,43 @@ private static boolean serverLocked = false; /** * Return codes used when the hidden option --checkStartability is used. * NOTE: when checkstartability is specified is recommended not to allocate * a lot of memory for the JVM (Using -Xms and -Xmx options) as there might * be calls to Runtime.exec. */ /** * Returned when the user specified the --checkStartability option with other * options like printing the usage, dumping messages, displaying version, etc. */ private static int NOTHING_TO_DO = 0; /** * Returned when the user specified the --checkStartability option with * some incompatible arguments. */ private static int CHECK_ERROR = 1; /** * The server is already started. */ private static int SERVER_ALREADY_STARTED = 98; /** * The server must be started as detached process. */ private static int START_AS_DETACH = 99; /** * The server must be started as a non-detached process. */ private static int START_AS_NON_DETACH = 100; /** * The server must be started as a window service. */ private static int START_AS_WINDOWS_SERVICE = 101; /** * The server must be started as detached and it is being called from the * Windows Service. */ private static int START_AS_DETACH_CALLED_FROM_WINDOWS_SERVICE = 102; // The policy to use regarding single structural objectclass enforcement. private AcceptRejectWarn singleStructuralClassPolicy; @@ -2539,8 +2578,6 @@ } } /** * Retrieves the time that the Directory Server was started, in milliseconds * since the epoch. @@ -7662,6 +7699,7 @@ { // Define the arguments that may be provided to the server. BooleanArgument checkStartability = null; BooleanArgument windowsNetStart = null; BooleanArgument displayUsage = null; BooleanArgument dumpMessages = null; BooleanArgument fullVersion = null; @@ -7705,6 +7743,12 @@ checkStartability.setHidden(true); argParser.addArgument(checkStartability); windowsNetStart = new BooleanArgument("windowsnetstart", null, "windowsNetStart", MSGID_DSCORE_DESCRIPTION_WINDOWS_NET_START); windowsNetStart.setHidden(true); argParser.addArgument(windowsNetStart); version = new BooleanArgument("version", 'v', "version", MSGID_DSCORE_DESCRIPTION_VERSION); @@ -7782,14 +7826,15 @@ // something else like display the version number. In that case, we // don't need to write the PID file at all and can just execute the // intended command. If that command was successful, then we'll have an // exit code of 0. Otherwise, it will have an exit code that is // something other than 0, 98, or 99 to indicate that a problem // occurred. // exit code of NOTHING_TO_DO (0). Otherwise, it will have an exit code // that is something other than NOTHING_TO_DO, SERVER_ALREADY_STARTED, // START_AS_DETACH, START_AS_NON_DETACH, START_AS_WINDOWS_SERVICE to // indicate that a problem occurred. if (argParser.usageDisplayed()) { // We're just trying to display usage, and that's already been done so // exit with a code of zero. System.exit(0); System.exit(NOTHING_TO_DO); } else if (fullVersion.isPresent() || version.isPresent() || systemInfo.isPresent() || dumpMessages.isPresent()) @@ -7808,44 +7853,11 @@ String[] newArgs = new String[newArgList.size()]; newArgList.toArray(newArgs); main(newArgs); System.exit(0); System.exit(NOTHING_TO_DO); } else { // We're trying to start the server, so see if it's already running by // trying to grab an exclusive lock on the server lock file. If it // succeeds, then the server isn't running and we can try to start. // Otherwise, the server is running and this attempt should fail. String lockFile = LockFileManager.getServerLockFileName(); try { StringBuilder failureReason = new StringBuilder(); if (LockFileManager.acquireExclusiveLock(lockFile, failureReason)) { // The server isn't running, so it can be started. LockFileManager.releaseLock(lockFile, failureReason); System.exit(99); } else { // The server's already running. int msgID = MSGID_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK; String message = getMessage(msgID, lockFile, String.valueOf(failureReason)); System.err.println(message); System.exit(98); } } catch (Exception e) { // We'll treat this as if the server is running because we won't // be able to start it anyway. int msgID = MSGID_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK; String message = getMessage(msgID, lockFile, stackTraceToSingleLineString(e)); System.err.println(message); System.exit(98); } System.exit(checkStartability(argParser)); } } else if (argParser.usageDisplayed()) @@ -8159,5 +8171,134 @@ RDN rdn = RDN.create(cnType, new AttributeValue(cnType, monitorName)); return monitorRootDN.concat(rdn); } /** * Returns the error code that we return when we are checking the startability * of the server. * If there are conflicting arguments (like asking to run the server in non * detach mode when the server is configured to run as a window service) it * returns CHECK_ERROR (1). * @param argParser the ArgumentParser with the arguments already parsed. * @return the error code that we return when we are checking the startability * of the server. */ private static int checkStartability(ArgumentParser argParser) { int returnValue; boolean isServerRunning; BooleanArgument noDetach = (BooleanArgument)argParser.getArgumentForLongID("nodetach"); BooleanArgument windowsNetStart = (BooleanArgument)argParser.getArgumentForLongID("windowsnetstart"); boolean noDetachPresent = noDetach.isPresent(); boolean windowsNetStartPresent = windowsNetStart.isPresent(); // We're trying to start the server, so see if it's already running by // trying to grab an exclusive lock on the server lock file. If it // succeeds, then the server isn't running and we can try to start. // Otherwise, the server is running and this attempt should fail. String lockFile = LockFileManager.getServerLockFileName(); try { StringBuilder failureReason = new StringBuilder(); if (LockFileManager.acquireExclusiveLock(lockFile, failureReason)) { // The server isn't running, so it can be started. LockFileManager.releaseLock(lockFile, failureReason); isServerRunning = false; } else { // The server's already running. int msgID = MSGID_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK; String message = getMessage(msgID, lockFile, String.valueOf(failureReason)); System.err.println(message); isServerRunning = true; } } catch (Exception e) { // We'll treat this as if the server is running because we won't // be able to start it anyway. int msgID = MSGID_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK; String message = getMessage(msgID, lockFile, stackTraceToSingleLineString(e)); System.err.println(message); isServerRunning = true; } if (isServerRunning) { returnValue = SERVER_ALREADY_STARTED; } else { boolean configuredAsService = isRunningAsWindowsService(); if (configuredAsService) { if (noDetachPresent) { // Conflicting arguments returnValue = CHECK_ERROR; int msgID = MSGID_DSCORE_ERROR_NODETACH_AND_WINDOW_SERVICE; String message = getMessage(msgID, (Object[])null); System.err.println(message); } else { if (windowsNetStartPresent) { // start-ds.bat is being called through net start, so return // START_AS_DETACH_CALLED_FROM_WINDOWS_SERVICE so that the batch // file actually starts the server. returnValue = START_AS_DETACH_CALLED_FROM_WINDOWS_SERVICE; } else { returnValue = START_AS_WINDOWS_SERVICE; } } } else { if (noDetachPresent) { returnValue = START_AS_NON_DETACH; } else { returnValue = START_AS_DETACH; } } } return returnValue; } /** * Returns true if this server is configured to run as a windows service. * @return <CODE>true</CODE> if this server is configured to run as a windows * service and <CODE>false</CODE> otherwise. */ public static boolean isRunningAsWindowsService() { boolean isRunningAsWindowsService; if (SetupUtils.isWindows()) { isRunningAsWindowsService = ConfigureWindowsService.serviceState(null, null) == ConfigureWindowsService.SERVICE_STATE_ENABLED; } else { isRunningAsWindowsService = false; } return isRunningAsWindowsService; } } opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java
@@ -5984,8 +5984,6 @@ public static final int MSGID_DSCORE_DESCRIPTION_CHECK_STARTABILITY = CATEGORY_MASK_CORE | SEVERITY_MASK_INFORMATIONAL | 596; /** * The message ID for the message that will be used if an entry includes an * attribute with no values. This takes two arguments, which are the DN of @@ -5995,6 +5993,20 @@ CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 597; /** * The message ID for the message that will be used when the user asks to run * the server in no-detach mode and the server is configured to run as a * service. This message does not take arguments. */ public static final int MSGID_DSCORE_ERROR_NODETACH_AND_WINDOW_SERVICE = CATEGORY_MASK_CORE | SEVERITY_MASK_FATAL_ERROR | 598; /** * The message ID for the message that will be used as the description for the * windowsNetStart command-line argument. This does not take any arguments. */ public static final int MSGID_DSCORE_DESCRIPTION_WINDOWS_NET_START = CATEGORY_MASK_CORE | SEVERITY_MASK_INFORMATIONAL | 599; /** * Associates a set of generic messages with the message IDs defined @@ -7269,8 +7281,12 @@ "information needed by the configuration handler to " + "obtain the Directory Server configuration."); registerMessage(MSGID_DSCORE_DESCRIPTION_CHECK_STARTABILITY, "Used to determine whether to write a server PID file " + "and attempt to start the server."); "Used to determine whether a server can be started or not" + "and the mode to be used to start it."); registerMessage(MSGID_DSCORE_DESCRIPTION_WINDOWS_NET_START, "Used by the window service code to inform that start-ds "+ "is being called from the window services after a call "+ "to net start"); registerMessage(MSGID_DSCORE_DESCRIPTION_VERSION, "Display Directory Server version information"); registerMessage(MSGID_DSCORE_DESCRIPTION_FULLVERSION, @@ -7290,6 +7306,9 @@ registerMessage(MSGID_DSCORE_ERROR_PARSING_ARGS, "An error occurred while attempting to parse the " + "provided set of command line arguments: %s."); registerMessage(MSGID_DSCORE_ERROR_NODETACH_AND_WINDOW_SERVICE, "OpenDS is configured to run as a window service and it "+ "cannot run in no-detach mode."); registerMessage(MSGID_DSCORE_CANNOT_BOOTSTRAP, "An error occurred while attempting to bootstrap the " + "Directory Server: %s."); @@ -8154,6 +8173,10 @@ registerMessage(MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES, "You do not have sufficient privileges to use the " + "proxied authorization control."); registerMessage(MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES, "You do not have sufficient privileges to use the " + "proxied authorization control."); } } opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -7608,7 +7608,6 @@ CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 799; /** * The message ID for the message that will be used to prompt the user to * enter "yes" or "no". This does not take any arguments. @@ -7685,6 +7684,7 @@ public static final int MSGID_INSTALLDS_PROMPT_JMXPORT = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 809; /** * The message ID for the message that will be used to print the result code * for an error encountered in a client tool. This takes two arguments, @@ -7711,6 +7711,232 @@ public static final int MSGID_TOOL_MATCHED_DN = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 812; /** * The message ID for the message that will be used to inform that the windows * service name for the OpenDS could not be found. This message takes no * arguments. */ public static final int MSGID_WINDOWS_SERVICE_NOT_FOUND = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 813; /** * The message ID for the message that will be used to inform that the windows * service for OpenDS could not be started. This message takes no arguments. */ public static final int MSGID_WINDOWS_SERVICE_START_ERROR = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 814; /** * The message ID for the message that will be used to inform that the windows * service for OpenDS could not be stopped. This message takes no arguments. */ public static final int MSGID_WINDOWS_SERVICE_STOP_ERROR = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 815; /** * The message ID for the message that will be used as the description for the * configure windows service tool. This does not take any arguments. */ public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_TOOL_DESCRIPTION = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 816; /** * The message ID for the message that will be used as the description of the * showUsage argument. This does not take any arguments. */ public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_SHOWUSAGE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 817; /** * The message ID for the message that will be used as the description of the * enableService argument. This does not take any arguments. */ public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_ENABLE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 818; /** * The message ID for the message that will be used as the description of the * disableService argument. This does not take any arguments. */ public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_DISABLE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 819; /** * The message ID for the message that will be used as the description of the * serviceState argument. This does not take any arguments. */ public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_STATE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 820; /** * The message ID for the message that will be used if an error occurs while * initializing the command-line arguments. This takes a single argument, * which is an explanation of the problem that occurred. */ public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_CANNOT_INITIALIZE_ARGS = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 821; /** * The message ID for the message that will be used if an error occurs while * parsing the command-line arguments. This takes a single argument, which is * an explanation of the problem that occurred. */ public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_ERROR_PARSING_ARGS = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 822; /** * The message ID for the message that will be used if an error occurs if * the user provided too many arguments. This does not take any argument. */ public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_TOO_MANY_ARGS = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 823; /** * The message ID for the message that will be used if an error occurs if * the user provided too few arguments. This does not take any argument. */ public static final int MSGID_CONFIGURE_WINDOWS_SERVICE_TOO_FEW_ARGS = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 824; /** * The message ID for the message for the name of the Windows service. * This does not take any argument. */ public static final int MSGID_WINDOWS_SERVICE_NAME = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 825; /** * The message ID for the message for the description of the Windows service. * This does take the server path installation as argument. */ public static final int MSGID_WINDOWS_SERVICE_DESCRIPTION = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 826; /** * The message ID for the message to inform that the Windows service was * successfully enabled. This does not take any argument. */ public static final int MSGID_WINDOWS_SERVICE_SUCCESSULLY_ENABLED = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 827; /** * The message ID for the message to inform that the Windows service was * already enabled. This does not take any argument. */ public static final int MSGID_WINDOWS_SERVICE_ALREADY_ENABLED = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 828; /** * The message ID for the message to inform that the Windows service name was * already in use. This does not take any argument. */ public static final int MSGID_WINDOWS_SERVICE_NAME_ALREADY_IN_USE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 829; /** * The message ID for the message to inform that the Windows service could not * be enabled. This does not take any argument. */ public static final int MSGID_WINDOWS_SERVICE_ENABLE_ERROR = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 830; /** * The message ID for the message to inform that the Windows service was * successfully disabled. This does not take any argument. */ public static final int MSGID_WINDOWS_SERVICE_SUCCESSULLY_DISABLED = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 831; /** * The message ID for the message to inform that the Windows service was * already disabled. This does not take any argument. */ public static final int MSGID_WINDOWS_SERVICE_ALREADY_DISABLED = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 832; /** * The message ID for the message to inform that the Windows service name was * marked for deletion. This does not take any argument. */ public static final int MSGID_WINDOWS_SERVICE_MARKED_FOR_DELETION = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_WARNING | 833; /** * The message ID for the message to inform that the Windows service could not * be disabled. This does not take any argument. */ public static final int MSGID_WINDOWS_SERVICE_DISABLE_ERROR = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 834; /** * The message ID for the message to inform that the Windows service is * enabled. This does take the name of the service as argument. */ public static final int MSGID_WINDOWS_SERVICE_ENABLED = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 835; /** * The message ID for the message to inform that the Windows service is * disabled. This does not take any argument. */ public static final int MSGID_WINDOWS_SERVICE_DISABLED = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 836; /** * The message ID for the message to inform that the Windows service state * could not be retrieved. This does not take any argument. */ public static final int MSGID_WINDOWS_SERVICE_STATE_ERROR = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 837; /** * The message ID for the message that will be used as the description for the * windowsNetStop command-line argument. This does not take any arguments. */ public static final int MSGID_STOPDS_DESCRIPTION_WINDOWS_NET_STOP = CATEGORY_MASK_CORE | SEVERITY_MASK_INFORMATIONAL | 838; /** * The message ID for the message that will be used as the description for the * outputFile argument. It does not take any arguments. */ public static final int MSGID_WAIT4DEL_DESCRIPTION_OUTPUT_FILE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 839; /** * The message ID for the message that will be used if an error occurs while * trying to open the output file for reading. This takes two arguments, * which are the path to the log file and a message explaining the problem * that occurred. */ public static final int MSGID_WAIT4DEL_CANNOT_OPEN_OUTPUT_FILE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_WARNING | 840; /** * The message ID for the message that will be used to tell that we are * enabling OpenDS as a Windows service. */ public static final int MSGID_INSTALLDS_ENABLING_WINDOWS_SERVICE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 841; /** * The message ID for the message that will be used to ask the user whether to * enable OpenDS as a Windows service or not. This does not take any * argument. */ public static final int MSGID_INSTALLDS_PROMPT_ENABLE_SERVICE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 842; /** * The message ID for the message for the description of the No Windows * service. This does not take any argument. */ public static final int MSGID_INSTALLDS_DESCRIPTION_NO_WINDOWS_SERVICE = CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 843; /** @@ -8922,7 +9148,12 @@ "Attempt to automatically restart the server once it has " + "stopped"); registerMessage(MSGID_STOPDS_CHECK_STOPPABILITY, "Used to determine whether the server is stopped or not."); "Used to determine whether the server can be stopped "+ "or not and the mode to be used to stop it."); registerMessage(MSGID_STOPDS_DESCRIPTION_WINDOWS_NET_STOP, "Used by the window service code to inform that stop-ds "+ "is being called from the window services after a call "+ "to net stop"); registerMessage(MSGID_STOPDS_DESCRIPTION_STOP_TIME, "Time to begin the shutdown in YYYYMMDDhhmmss format " + "(local time)"); @@ -9288,6 +9519,8 @@ registerMessage(MSGID_INSTALLDS_DESCRIPTION_ROOTPWFILE, "Specifies the path to a file containing the password " + "for the initial root user for the Directory Server."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_NO_WINDOWS_SERVICE, "Do not enable OpenDS to run as a Windows Service."); registerMessage(MSGID_INSTALLDS_DESCRIPTION_HELP, "Displays usage information for this program."); registerMessage(MSGID_INSTALLDS_NO_CONFIG_FILE, @@ -9330,6 +9563,8 @@ registerMessage(MSGID_INSTALLDS_PROMPT_JMXPORT, "On which port would you like the Directory Server to " + "accept connections from JMX clients?"); registerMessage(MSGID_INSTALLDS_PROMPT_ENABLE_SERVICE, "Enable OpenDS to run as a Windows Service?"); registerMessage(MSGID_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT, "ERROR: Unable to bind to port %d. This port may " + "already be in use, or you may not have permission to " + @@ -9418,6 +9653,8 @@ registerMessage(MSGID_INSTALLDS_CANNOT_CREATE_TEMPLATE_FILE, "ERROR: Cannot create the template file for generating " + "sample data: %s."); registerMessage(MSGID_INSTALLDS_ENABLING_WINDOWS_SERVICE, "Enabling OpenDS as a Windows service...."); registerMessage(MSGID_MAKELDIF_TAG_INVALID_ARGUMENT_COUNT, @@ -9844,6 +10081,9 @@ registerMessage(MSGID_WAIT4DEL_DESCRIPTION_LOG_FILE, "Specifies the path to a file containing log output to " + "monitor."); registerMessage(MSGID_WAIT4DEL_DESCRIPTION_OUTPUT_FILE, "Specifies the path to a file to which the command will " + "write the output."); registerMessage(MSGID_WAIT4DEL_DESCRIPTION_TIMEOUT, "The maximum length of time in seconds to wait for the " + "target file to be deleted before exiting."); @@ -9857,6 +10097,9 @@ "arguments: %s."); registerMessage(MSGID_WAIT4DEL_CANNOT_OPEN_LOG_FILE, "WARNING: Unable to open log file %s for reading: %s."); registerMessage(MSGID_WAIT4DEL_CANNOT_OPEN_OUTPUT_FILE, "WARNING: Unable to open output file %s for writing: "+ "%s."); registerMessage(MSGID_LDAPCOMPARE_NO_DNS, @@ -10081,6 +10324,97 @@ "Please enter \"yes\" or \"no\": "); registerMessage(MSGID_PROMPTTM_USER_REJECTED, "The server certificate has been rejected by the user."); registerMessage(MSGID_WINDOWS_SERVICE_NOT_FOUND, "Could not find the service name for OpenDS."); registerMessage(MSGID_WINDOWS_SERVICE_START_ERROR, "An unexpected error occurred starting OpenDS as a "+ "windows service"); registerMessage(MSGID_WINDOWS_SERVICE_STOP_ERROR, "An unexpected error occurred stopping the OpenDS "+ "windows service"); registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_TOOL_DESCRIPTION, "This utility may be used to configure OpenDS as a "+ "Windows service."); registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_SHOWUSAGE, "Display this usage information."); registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_ENABLE, "Enables OpenDS as a Windows service."); registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_DISABLE, "Disables OpenDS as a Windows service and stops the "+ "server"); registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_STATE, "Provides information about the state of OpenDS as a "+ "Windows service."); registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_CANNOT_INITIALIZE_ARGS, "An unexpected error occurred while attempting to " + "initialize the command-line arguments: %s."); registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_ERROR_PARSING_ARGS, "An error occurred while parsing the command-line " + "arguments: %s."); registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_TOO_MANY_ARGS, "You can only provide one of the following arguments:"+ EOL+"enableService, disableService or serviceState."); registerMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_TOO_FEW_ARGS, "You must provide at least one of the following arguments:"+ EOL+"enableService, disableService or serviceState."); registerMessage(MSGID_WINDOWS_SERVICE_NAME, "OpenDS"); registerMessage(MSGID_WINDOWS_SERVICE_DESCRIPTION, "Open source Next Generation Directory Server. "+ "Installation path: %s"); registerMessage(MSGID_WINDOWS_SERVICE_SUCCESSULLY_ENABLED, "OpenDS was successfully enabled as a Windows service."); registerMessage(MSGID_WINDOWS_SERVICE_ALREADY_ENABLED, "OpenDS was already enabled as a Windows service."); registerMessage(MSGID_WINDOWS_SERVICE_NAME_ALREADY_IN_USE, "OpenDS could not enabled as a Windows service. The "+ "service name is already in use."); registerMessage(MSGID_WINDOWS_SERVICE_ENABLE_ERROR, "An unexpected error occurred trying to enable OpenDS as "+ "a Windows service."); registerMessage(MSGID_WINDOWS_SERVICE_SUCCESSULLY_DISABLED, "OpenDS was successfully disabled as a Windows service."); registerMessage(MSGID_WINDOWS_SERVICE_ALREADY_DISABLED, "OpenDS was already disabled as a Windows service."); registerMessage(MSGID_WINDOWS_SERVICE_MARKED_FOR_DELETION, "OpenDS has been marked for deletion as a Windows "+ "Service."); registerMessage(MSGID_WINDOWS_SERVICE_DISABLE_ERROR, "An unexpected error occurred trying to disable OpenDS as "+ "a Windows service."); registerMessage(MSGID_WINDOWS_SERVICE_ENABLED, "OpenDS is enabled as a Windows service. The service "+ "name for OpenDS is: %s"); registerMessage(MSGID_WINDOWS_SERVICE_DISABLED, "OpenDS is disabled as a Windows service."); registerMessage(MSGID_WINDOWS_SERVICE_STATE_ERROR, "An unexpected error occurred trying to retrieve the "+ "state of OpenDS as a Windows service."); } } opendj-sdk/opends/src/server/org/opends/server/tools/ConfigureWindowsService.java
New file @@ -0,0 +1,612 @@ /* * 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 * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * 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. */ package org.opends.server.tools; import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import org.opends.server.core.DirectoryServer; import org.opends.server.types.NullOutputStream; import org.opends.server.util.args.ArgumentException; import org.opends.server.util.args.ArgumentParser; import org.opends.server.util.args.BooleanArgument; import static org.opends.server.messages.MessageHandler.getMessage; import static org.opends.server.messages.ToolMessages.*; import static org.opends.server.util.ServerConstants.MAX_LINE_WIDTH; import static org.opends.server.util.StaticUtils.wrapText; /** * This class is used to configure the Windows service for this instance on * this machine. * This tool allows to enable and disable OpenDS to run as a Windows service * and allows to know if OpenDS is running as a Windows service or not. */ public class ConfigureWindowsService { /** * The fully-qualified name of this class. */ private static final String CLASS_NAME = "org.opends.server.tools.ConfigureWindowsService"; private static int ERROR = 1; /** * Return codes for the method enableService. */ /** * The service was successfully enabled. */ public static final int SERVICE_ENABLE_SUCCESS = 0; /** * The service was already enabled. */ public static final int SERVICE_ALREADY_ENABLED = 1; /** * The service name was already in use. */ public static final int SERVICE_NAME_ALREADY_IN_USE = 2; /** * An error occurred enabling the service. */ public static final int SERVICE_ENABLE_ERROR = 3; /** * Return codes for the method disableService. */ /** * The service was successfully disabled. */ public static final int SERVICE_DISABLE_SUCCESS = 0; /** * The service was already disabled. */ public static final int SERVICE_ALREADY_DISABLED = 1; /** * The service is marked for deletion. */ public static final int SERVICE_MARKED_FOR_DELETION = 2; /** * An error occurred disabling the service. */ public static final int SERVICE_DISABLE_ERROR = 3; /** * Return codes for the method serviceState. */ /** * The service is enabled. */ public static final int SERVICE_STATE_ENABLED = 0; /** * The service is disabled. */ public static final int SERVICE_STATE_DISABLED = 1; /** * An error occurred checking the service state. */ public static final int SERVICE_STATE_ERROR = 2; /** * Configures the Windows service for this instance on this machine. * This tool allows to enable and disable OpenDS to run as a Windows service * and allows to know if OpenDS is running as a Windows service or not. * * @param args The command-line arguments provided to this program. */ public static void main(String[] args) { int result = configureWindowsService(args, System.out, System.err); System.exit(result); } /** * Configures the Windows service for this instance on this machine. * This tool allows to enable and disable OpenDS to run as a Windows service * and allows to know if OpenDS is running as a Windows service or not. * * @param args The command-line arguments provided to this program. * @param outStream the stream used to write the standard output. * @param errStream the stream used to write the error output. * @return the integer code describing if the operation could be completed or * not. */ public static int configureWindowsService(String[] args, OutputStream outStream, OutputStream errStream) { int returnValue = 0; PrintStream out; if (outStream == null) { out = NullOutputStream.printStream(); } else { out = new PrintStream(outStream); } PrintStream err; if (errStream == null) { err = NullOutputStream.printStream(); } else { err = new PrintStream(errStream); } // Define all the arguments that may be used with this program. String toolDescription = getMessage(MSGID_CONFIGURE_WINDOWS_SERVICE_TOOL_DESCRIPTION); ArgumentParser argParser = new ArgumentParser(CLASS_NAME, toolDescription, false); BooleanArgument enableService = null; BooleanArgument disableService = null; BooleanArgument serviceState = null; BooleanArgument showUsage = null; try { enableService = new BooleanArgument("enableservice", 'e', "enableService", MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_ENABLE); argParser.addArgument(enableService); disableService = new BooleanArgument("disableservice", 'd', "disableService", MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_DISABLE); argParser.addArgument(disableService); serviceState = new BooleanArgument("servicestate", 's', "serviceState", MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_STATE); argParser.addArgument(serviceState); showUsage = new BooleanArgument("showusage", 'H', "help", MSGID_CONFIGURE_WINDOWS_SERVICE_DESCRIPTION_SHOWUSAGE); argParser.addArgument(showUsage); argParser.setUsageArgument(showUsage, out); } catch (ArgumentException ae) { int msgID = MSGID_CONFIGURE_WINDOWS_SERVICE_CANNOT_INITIALIZE_ARGS; String message = getMessage(msgID, ae.getMessage()); err.println(wrapText(message, MAX_LINE_WIDTH)); returnValue = ERROR; } // Parse the command-line arguments provided to this program. if (returnValue == 0) { try { argParser.parseArguments(args); } catch (ArgumentException ae) { int msgID = MSGID_CONFIGURE_WINDOWS_SERVICE_ERROR_PARSING_ARGS; String message = getMessage(msgID, ae.getMessage()); err.println(wrapText(message, MAX_LINE_WIDTH)); err.println(argParser.getUsage()); returnValue = ERROR; } } // If we should just display usage information, then it is already done if ((returnValue == 0) && !argParser.usageDisplayed()) { /* Check that the user only asked for one argument */ int nArgs = 0; if (enableService.isPresent()) { nArgs++; } if (disableService.isPresent()) { nArgs++; } if (serviceState.isPresent()) { nArgs++; } if (nArgs > 1) { int msgID = MSGID_CONFIGURE_WINDOWS_SERVICE_TOO_MANY_ARGS; String message = getMessage(msgID, (Object[])null); err.println(wrapText(message, MAX_LINE_WIDTH)); err.println(argParser.getUsage()); returnValue = ERROR; } if (nArgs == 0) { int msgID = MSGID_CONFIGURE_WINDOWS_SERVICE_TOO_FEW_ARGS; String message = getMessage(msgID, (Object[])null); err.println(wrapText(message, MAX_LINE_WIDTH)); err.println(argParser.getUsage()); returnValue = ERROR; } } if ((returnValue == 0) && !argParser.usageDisplayed()) { if (enableService.isPresent()) { returnValue = enableService(out, err); } else if (disableService.isPresent()) { returnValue = disableService(out, err); } else { returnValue = serviceState(out, err); } } return returnValue; } /** * Returns the service name associated with OpenDS or null if no service name * could be found. * @return the service name associated with OpenDS or null if no service name * could be found. */ static String getServiceName() { String serviceName = null; String serverRoot = getServerRoot(); String[] cmd = { getBinaryFullPath(), "state", serverRoot }; try { Process p = Runtime.getRuntime().exec(cmd); BufferedReader stdout = new BufferedReader( new InputStreamReader(p.getInputStream())); boolean processDone = false; String s; while (!processDone) { try { p.exitValue(); processDone = true; } catch (Throwable t) { } while ((s = stdout.readLine()) != null) { serviceName = s; if (serviceName.trim().length() == 0) { serviceName = null; } } } } catch (Throwable t) { serviceName = null; } return serviceName; } /** * Enables OpenDS to run as a windows service. * @param out the stream used to write the standard output. * @param err the stream used to write the error output. * @return <CODE>SERVICE_ENABLE_SUCCESS</CODE>, * <CODE>SERVICE_ENABLE_ERROR</CODE>, * <CODE>SERVICE_NAME_ALREADY_IN_USE</CODE> or * <CODE>SERVICE_ALREADY_ENABLED</CODE> depending on whether the service could * be enabled or not. */ public static int enableService(PrintStream out, PrintStream err) { int returnValue; String msg; String serverRoot = getServerRoot(); String[] cmd = { getBinaryFullPath(), "create", serverRoot, getMessage(MSGID_WINDOWS_SERVICE_NAME, (Object[]) null), getMessage(MSGID_WINDOWS_SERVICE_DESCRIPTION, serverRoot) }; try { int resultCode = Runtime.getRuntime().exec(cmd).waitFor(); switch (resultCode) { case 0: returnValue = SERVICE_ENABLE_SUCCESS; msg = getMessage(MSGID_WINDOWS_SERVICE_SUCCESSULLY_ENABLED, (Object[])null); out.println(wrapText(msg, MAX_LINE_WIDTH)); break; case 1: returnValue = SERVICE_ALREADY_ENABLED; msg = getMessage(MSGID_WINDOWS_SERVICE_ALREADY_ENABLED, (Object[])null); out.println(wrapText(msg, MAX_LINE_WIDTH)); break; case 2: returnValue = SERVICE_NAME_ALREADY_IN_USE; msg = getMessage(MSGID_WINDOWS_SERVICE_NAME_ALREADY_IN_USE, (Object[])null); err.println(wrapText(msg, MAX_LINE_WIDTH)); break; case 3: returnValue = SERVICE_ENABLE_ERROR; msg = getMessage(MSGID_WINDOWS_SERVICE_ENABLE_ERROR, (Object[])null); err.println(wrapText(msg, MAX_LINE_WIDTH)); break; default: returnValue = SERVICE_ENABLE_ERROR; msg = getMessage(MSGID_WINDOWS_SERVICE_ENABLE_ERROR, (Object[])null); err.println(wrapText(msg, MAX_LINE_WIDTH)); } } catch (Throwable t) { returnValue = SERVICE_ENABLE_ERROR; msg = getMessage(MSGID_WINDOWS_SERVICE_ENABLE_ERROR, (Object[])null); err.println(wrapText(msg, MAX_LINE_WIDTH)); } return returnValue; } /** * Disables OpenDS to run as a windows service. * @param out the stream used to write the standard output. * @param err the stream used to write the error output. * @return <CODE>SERVICE_DISABLE_SUCCESS</CODE>, * <CODE>SERVICE_DISABLE_ERROR</CODE>, * <CODE>SERVICE_MARKED_FOR_DELETION</CODE> or * <CODE>SERVICE_ALREADY_DISABLED</CODE> depending on whether the service * could be disabled or not. */ public static int disableService(PrintStream out, PrintStream err) { int returnValue; String msg; String serverRoot = getServerRoot(); String[] cmd = { getBinaryFullPath(), "remove", serverRoot }; try { int resultCode = Runtime.getRuntime().exec(cmd).waitFor(); switch (resultCode) { case 0: returnValue = SERVICE_DISABLE_SUCCESS; msg = getMessage(MSGID_WINDOWS_SERVICE_SUCCESSULLY_DISABLED, (Object[])null); out.println(msg); break; case 1: returnValue = SERVICE_ALREADY_DISABLED; msg = getMessage(MSGID_WINDOWS_SERVICE_ALREADY_DISABLED, (Object[])null); out.println(msg); break; case 2: returnValue = SERVICE_MARKED_FOR_DELETION; msg = getMessage(MSGID_WINDOWS_SERVICE_MARKED_FOR_DELETION, (Object[])null); out.println(msg); break; case 3: returnValue = SERVICE_DISABLE_ERROR; msg = getMessage(MSGID_WINDOWS_SERVICE_DISABLE_ERROR, (Object[])null); err.println(msg); break; default: returnValue = SERVICE_DISABLE_ERROR; msg = getMessage(MSGID_WINDOWS_SERVICE_DISABLE_ERROR, (Object[])null); err.println(msg); } } catch (Throwable t) { returnValue = SERVICE_DISABLE_ERROR; msg = getMessage(MSGID_WINDOWS_SERVICE_DISABLE_ERROR, (Object[])null); err.println(msg); } return returnValue; } /** * Checks if OpenDS is enabled as a windows service and if it is * write the serviceName in the output stream (if it is not null). * @param out the stream used to write the standard output. * @param err the stream used to write the error output. * @return <CODE>SERVICE_STATE_ENABLED</CODE>, * <CODE>SERVICE_STATE_DISABLED</CODE> or <CODE>SERVICE_STATE_ERROR</CODE> * depending on the state of the service. */ public static int serviceState(PrintStream out, PrintStream err) { int returnValue; String msg; String serviceName = null; String serverRoot = getServerRoot(); String[] cmd = { getBinaryFullPath(), "state", serverRoot }; try { int resultCode = -1; ProcessBuilder pb = new ProcessBuilder(cmd); Process process = pb.start(); BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream())); boolean processDone = false; String s; while (!processDone) { try { resultCode = process.exitValue(); processDone = true; } catch (Throwable t) { } while ((s = stdout.readLine()) != null) { if (s.trim().length() != 0) { serviceName = s; } } } switch (resultCode) { case 0: returnValue = SERVICE_STATE_ENABLED; if (out != null) { msg = getMessage(MSGID_WINDOWS_SERVICE_ENABLED, serviceName); out.println(msg); } break; case 1: returnValue = SERVICE_STATE_DISABLED; if (out != null) { msg = getMessage(MSGID_WINDOWS_SERVICE_DISABLED, (Object[])null); out.println(msg); } break; case 2: returnValue = SERVICE_STATE_ERROR; if (out != null) { msg = getMessage(MSGID_WINDOWS_SERVICE_STATE_ERROR, (Object[])null); out.println(msg); } break; default: returnValue = SERVICE_STATE_ERROR; if (err != null) { msg = getMessage(MSGID_WINDOWS_SERVICE_STATE_ERROR, (Object[])null); err.println(msg); } } } catch (Throwable t) { returnValue = SERVICE_STATE_ERROR; if (err != null) { msg = getMessage(MSGID_WINDOWS_SERVICE_STATE_ERROR, (Object[])null); err.println(wrapText(msg, MAX_LINE_WIDTH)); } } return returnValue; } /** * Returns the Directory Server installation path in a user friendly * representation. * @return the Directory Server installation path in a user friendly * representation. */ private static String getServerRoot() { String serverRoot = DirectoryServer.getServerRoot(); File f = new File(serverRoot); try { /* * Do a best effort to avoid having a relative representation (for * instance to avoid having ../../../). */ File canonical = f.getCanonicalFile(); f = canonical; } catch (IOException ioe) { /* This is a best effort to get the best possible representation of the * file: reporting the error is not necessary. */ } serverRoot = f.toString(); if (serverRoot.endsWith(File.separator)) { serverRoot = serverRoot.substring(0, serverRoot.length() - 1); } return serverRoot; } /** * Returns the full path of the executable used by this class to perform * operations related to the service. * @return the full path of the executable used by this class to perform * operations related to the service. */ private static String getBinaryFullPath() { return getServerRoot()+"\\lib\\opends_service.exe"; } } opendj-sdk/opends/src/server/org/opends/server/tools/InstallDS.java
@@ -177,6 +177,7 @@ BooleanArgument showUsage; BooleanArgument silentInstall; BooleanArgument skipPortCheck; BooleanArgument noWindowsService; FileBasedArgument rootPWFile; IntegerArgument ldapPort; IntegerArgument jmxPort; @@ -278,6 +279,14 @@ null, null, MSGID_INSTALLDS_DESCRIPTION_ROOTPWFILE); argParser.addArgument(rootPWFile); noWindowsService = new BooleanArgument("nowindowsservice", 'n', "noWindowsService", MSGID_INSTALLDS_DESCRIPTION_NO_WINDOWS_SERVICE); if (SetupUtils.isWindows()) { argParser.addArgument(noWindowsService); } showUsage = new BooleanArgument("help", 'H', "help", MSGID_INSTALLDS_DESCRIPTION_HELP); argParser.addArgument(showUsage); @@ -790,6 +799,24 @@ } } boolean enableService = false; // If we are in Windows ask if the server must run as a windows service. if (SetupUtils.isWindows()) { if (silentInstall.isPresent()) { enableService = !noWindowsService.isPresent(); } else if (noWindowsService.isPresent()) { enableService = false; } else { String message = getMessage(MSGID_INSTALLDS_PROMPT_ENABLE_SERVICE); enableService = promptForBoolean(message, Boolean.TRUE); } } // At this point, we should be able to invoke the ConfigureDS utility to // apply the requested configuration. @@ -976,6 +1003,24 @@ SetupUtils.writeSetJavaHome(serverRoot); } catch (Exception e) {} if (enableService) { String message = getMessage(MSGID_INSTALLDS_ENABLING_WINDOWS_SERVICE); System.out.println(wrapText(message, MAX_LINE_WIDTH)); int code = ConfigureWindowsService.enableService(System.out, System.err); switch (code) { case ConfigureWindowsService.SERVICE_ENABLE_SUCCESS: break; case ConfigureWindowsService.SERVICE_ALREADY_ENABLED: break; default: // It did not work. return code; } } // If we've gotten here, then everything seems to have gone smoothly. if (! silentInstall.isPresent()) opendj-sdk/opends/src/server/org/opends/server/tools/StartWindowsService.java
New file @@ -0,0 +1,142 @@ /* * 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 * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * 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. */ package org.opends.server.tools; import java.io.OutputStream; import java.io.PrintStream; import org.opends.server.types.NullOutputStream; import static org.opends.server.messages.MessageHandler.getMessage; import static org.opends.server.messages.ToolMessages.*; /** * This class is used to start the Windows service associated with this * instance on this machine. * This tool allows to start OpenDS and to make it run as a Windows service. */ public class StartWindowsService { /** * The service was successfully started. */ private static int SERVICE_START_SUCCESSFUL = 0; /** * The service could not be found. */ private static int SERVICE_NOT_FOUND = 1; /** * The service could not be started. */ private static int SERVICE_START_ERROR = 2; /** * Invokes the net start on the service corresponding to this server. * * @param args The command-line arguments provided to this program. */ public static void main(String[] args) { int result = startWindowsService(System.out, System.err); System.exit(result); } /** * Invokes the net start on the service corresponding to this server, it * writes information and error messages in the provided streams. * @return <CODE>SERVICE_START_SUCCESSFUL</CODE>, * <CODE>SERVICE_NOT_FOUND</CODE>, <CODE>SERVICE_ALREADY_STARTED</CODE> or * <CODE>SERVICE_START_ERROR</CODE> depending on whether the service could be * stopped or not. * @param outStream The stream to write standard output messages. * @param errStream The stream to write error messages. */ public static int startWindowsService(OutputStream outStream, OutputStream errStream) { int returnValue; PrintStream out; if (outStream == null) { out = NullOutputStream.printStream(); } else { out = new PrintStream(outStream); } PrintStream err; if (errStream == null) { err = NullOutputStream.printStream(); } else { err = new PrintStream(errStream); } String serviceName = ConfigureWindowsService.getServiceName(); if (serviceName == null) { int msgID = MSGID_WINDOWS_SERVICE_NOT_FOUND; String message = getMessage(msgID, (Object[])null); err.println(message); returnValue = SERVICE_NOT_FOUND; } else { String[] cmd = { "net", "start", serviceName }; /* Check if is a running service */ try { if (Runtime.getRuntime().exec(cmd).waitFor() == 0) { returnValue = SERVICE_START_SUCCESSFUL; } else { returnValue = SERVICE_START_ERROR; } } catch (Throwable t) { int msgID = MSGID_WINDOWS_SERVICE_START_ERROR; String message = getMessage(msgID, (Object[])null); out.println(message); returnValue = SERVICE_START_ERROR; } } return returnValue; } } opendj-sdk/opends/src/server/org/opends/server/tools/StopDS.java
@@ -40,6 +40,7 @@ import java.util.concurrent.atomic.AtomicInteger; import org.opends.server.controls.ProxiedAuthV2Control; import org.opends.server.core.DirectoryServer; import org.opends.server.core.LockFileManager; import org.opends.server.protocols.asn1.ASN1Element; import org.opends.server.protocols.asn1.ASN1Exception; @@ -58,6 +59,7 @@ import org.opends.server.tasks.ShutdownTask; import org.opends.server.types.Control; import org.opends.server.types.NullOutputStream; import org.opends.server.util.args.Argument; import org.opends.server.util.args.ArgumentException; import org.opends.server.util.args.ArgumentParser; import org.opends.server.util.args.BooleanArgument; @@ -84,7 +86,40 @@ */ private static final String CLASS_NAME = "org.opends.server.tools.StopDS"; /** * Return codes used when the hidden option --checkStoppability is used. * NOTE: when checkStoppability is specified is recommended not to allocate * a lot of memory for the JVM (Using -Xms and -Xmx options) as there might * be calls to Runtime.exec. */ /** * The server is already stopped. */ private static int SERVER_ALREADY_STOPPED = 98; /** * The server must be started. */ private static int START_SERVER = 99; /** * The server must be stopped using a system call. */ private static int STOP_USING_SYSTEM_CALL = 100; /** * The server must be restarted using system calls. */ private static int RESTART_USING_SYSTEM_CALL = 101; /** * The server must be stopped using protocol. */ private static int STOP_USING_PROTOCOL = 102; /** * The server must be stopped as a window service. */ private static int STOP_AS_WINDOW_SERVICE = 103; /** * The server must be restarted as a window service. */ private static int RESTART_AS_WINDOW_SERVICE = 104; /** * Invokes the <CODE>stopDS</CODE> method, passing it the provided command @@ -165,6 +200,7 @@ ArgumentParser argParser = new ArgumentParser(CLASS_NAME, toolDescription, false); BooleanArgument checkStoppability; BooleanArgument windowsNetStop; BooleanArgument restart; BooleanArgument showUsage; BooleanArgument trustAll; @@ -245,6 +281,11 @@ checkStoppability.setHidden(true); argParser.addArgument(checkStoppability); windowsNetStop = new BooleanArgument("windowsnetstop", null, "windowsNetStop", MSGID_STOPDS_DESCRIPTION_WINDOWS_NET_STOP); windowsNetStop.setHidden(true); argParser.addArgument(windowsNetStop); restart = new BooleanArgument("restart", 'R', "restart", MSGID_STOPDS_DESCRIPTION_RESTART); argParser.addArgument(restart); @@ -340,44 +381,8 @@ if (checkStoppability.isPresent()) { // This option should only be used if we want to check if the local // server is running or not. If the server is running result code is 98. // If the server is stopped the return code is 99. String lockFile = LockFileManager.getServerLockFileName(); try { StringBuilder failureReason = new StringBuilder(); if (LockFileManager.acquireExclusiveLock(lockFile, failureReason)) { // The server is not running: write a message informing of that // in the standard out (this is not an error message). int msgID = MSGID_STOPDS_SERVER_ALREADY_STOPPED; String message = getMessage(msgID, null, null); System.out.println(message); LockFileManager.releaseLock(lockFile, failureReason); System.exit(99); } else { // Display a message informing that we are going to the server. int msgID = MSGID_STOPDS_GOING_TO_STOP; String message = getMessage(msgID, null, null); System.out.println(message); // The server is running. System.exit(98); } } catch (Exception e) { // Display a message informing that we are going to the server. int msgID = MSGID_STOPDS_GOING_TO_STOP; String message = getMessage(msgID, null, null); System.out.println(message); // Assume that if we cannot acquire the lock file the server is // running. System.exit(98); } } System.exit(checkStoppability(argParser)); } // If both a bind password and bind password file were provided, then return // an error. @@ -750,5 +755,141 @@ return addResponse.getResultCode(); } /** * Returns the error code that we return when we are checking the stoppability * of the server. This basically tells the invoker what must be done based * on the different parameters passed. * @param argParser the ArgumentParser with the arguments already parsed. * @return the error code that we return when we are checking the stoppability * of the server. */ private static int checkStoppability(ArgumentParser argParser) { int returnValue; boolean isServerRunning; BooleanArgument restart = (BooleanArgument)argParser.getArgumentForLongID("restart"); boolean restartPresent = restart.isPresent(); BooleanArgument windowsNetStop = (BooleanArgument)argParser.getArgumentForLongID("windowsnetstop"); boolean windowsNetStopPresent = windowsNetStop.isPresent(); // Check if this is a stop through protocol. LinkedList<Argument> list = argParser.getArgumentList(); boolean stopThroughProtocol = false; for (Argument arg: list) { if (!"restart".equals(arg.getName()) && !"showusage".equals(arg.getName()) && !"checkstoppability".equals(arg.getName()) && !"windowsnetstop".equals(arg.getName())) { stopThroughProtocol |= arg.isPresent(); } } if (stopThroughProtocol) { // Assume that this is done on a remote server and do no more checks. returnValue = STOP_USING_PROTOCOL; } else { String lockFile = LockFileManager.getServerLockFileName(); try { StringBuilder failureReason = new StringBuilder(); if (LockFileManager.acquireExclusiveLock(lockFile, failureReason)) { // The server is not running: write a message informing of that // in the standard out (this is not an error message). int msgID = MSGID_STOPDS_SERVER_ALREADY_STOPPED; String message = getMessage(msgID, null, null); System.out.println(message); LockFileManager.releaseLock(lockFile, failureReason); isServerRunning = false; } else { isServerRunning = true; } } catch (Exception e) { // Assume that if we cannot acquire the lock file the server is // running. isServerRunning = true; } if (!isServerRunning) { if (restartPresent) { returnValue = START_SERVER; } else { returnValue = SERVER_ALREADY_STOPPED; } } else { boolean configuredAsService = DirectoryServer.isRunningAsWindowsService(); if (configuredAsService) { if (windowsNetStopPresent) { // stop-ds.bat is being called through net stop, so return // STOP_USING_SYSTEM_CALL or RESTART_USING_SYSTEM_CALL so that the // batch file actually stops the server. if (restartPresent) { returnValue = RESTART_USING_SYSTEM_CALL; } else { returnValue = STOP_USING_SYSTEM_CALL; } } else { if (restartPresent) { returnValue = RESTART_AS_WINDOW_SERVICE; } else { returnValue = STOP_AS_WINDOW_SERVICE; } // Display a message informing that we are going to the server. int msgID = MSGID_STOPDS_GOING_TO_STOP; String message = getMessage(msgID, null, null); System.out.println(message); } } else { // Display a message informing that we are going to the server. int msgID = MSGID_STOPDS_GOING_TO_STOP; String message = getMessage(msgID, null, null); System.out.println(message); if (restartPresent) { returnValue = RESTART_USING_SYSTEM_CALL; } else { returnValue = STOP_USING_SYSTEM_CALL; } } } } return returnValue; } } opendj-sdk/opends/src/server/org/opends/server/tools/StopWindowsService.java
New file @@ -0,0 +1,147 @@ /* * 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 * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * 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. */ package org.opends.server.tools; import java.io.OutputStream; import java.io.PrintStream; import org.opends.server.types.NullOutputStream; import static org.opends.server.messages.MessageHandler.getMessage; import static org.opends.server.messages.ToolMessages.*; /** * This class is used to stop the Windows service associated with this * instance on this machine. * This tool allows to stop OpenDS as a Windows service. */ public class StopWindowsService { /** * The service was successfully stopped. */ public static int SERVICE_STOP_SUCCESSFUL = 0; /** * The service could not be found. */ public static int SERVICE_NOT_FOUND = 1; /** * The service was already stopped. */ public static int SERVICE_ALREADY_STOPPED = 2; /** * The service could not be stopped. */ public static int SERVICE_STOP_ERROR = 3; /** * Invokes the net stop on the service corresponding to this server. * * @param args The command-line arguments provided to this program. */ public static void main(String[] args) { int result = stopWindowsService(System.out, System.err); System.exit(result); } /** * Invokes the net stop on the service corresponding to this server, it writes * information and error messages in the provided streams. * @return <CODE>SERVICE_STOP_SUCCESSFUL</CODE>, * <CODE>SERVICE_NOT_FOUND</CODE>, <CODE>SERVICE_ALREADY_STOPPED</CODE> or * <CODE>SERVICE_STOP_ERROR</CODE> depending on whether the service could be * stopped or not. * @param outStream The stream to write standard output messages. * @param errStream The stream to write error messages. */ public static int stopWindowsService(OutputStream outStream, OutputStream errStream) { int returnValue; PrintStream out; if (outStream == null) { out = NullOutputStream.printStream(); } else { out = new PrintStream(outStream); } PrintStream err; if (errStream == null) { err = NullOutputStream.printStream(); } else { err = new PrintStream(errStream); } String serviceName = ConfigureWindowsService.getServiceName(); if (serviceName == null) { int msgID = MSGID_WINDOWS_SERVICE_NOT_FOUND; String message = getMessage(msgID, (Object[])null); err.println(message); returnValue = SERVICE_NOT_FOUND; } else { String[] cmd = { "net", "stop", serviceName }; /* Check if is a running service */ try { if (Runtime.getRuntime().exec(cmd).waitFor() == 0) { returnValue = SERVICE_STOP_SUCCESSFUL; } else { returnValue = SERVICE_STOP_ERROR; } } catch (Throwable t) { int msgID = MSGID_WINDOWS_SERVICE_STOP_ERROR; String message = getMessage(msgID, (Object[])null); out.println(message); returnValue = SERVICE_STOP_ERROR; } } return returnValue; } } opendj-sdk/opends/src/server/org/opends/server/tools/WaitForFileDelete.java
@@ -124,6 +124,7 @@ IntegerArgument timeout = null; StringArgument logFilePath = null; StringArgument targetFilePath = null; StringArgument outputFilePath = null; String toolDescription = getMessage(MSGID_WAIT4DEL_TOOL_DESCRIPTION); ArgumentParser argParser = new ArgumentParser(CLASS_NAME, toolDescription, @@ -144,6 +145,13 @@ argParser.addArgument(logFilePath); outputFilePath = new StringArgument("outputfile", 'o', "outputFile", false, false, true, "{path}", null, null, MSGID_WAIT4DEL_DESCRIPTION_OUTPUT_FILE); argParser.addArgument(outputFilePath); timeout = new IntegerArgument("timeout", 't', "timeout", true, false, true, "{seconds}", 60, null, true, 0, false, 0, MSGID_WAIT4DEL_DESCRIPTION_TIMEOUT); @@ -222,6 +230,35 @@ } // If an output file was specified and we could open the log file, open it // and append data to it. RandomAccessFile outputFile = null; long outputFileOffset = 0L; if (logFile != null) { if (outputFilePath.isPresent()) { try { File f = new File(outputFilePath.getValue()); if (f.exists()) { outputFile = new RandomAccessFile(f, "rw"); outputFileOffset = outputFile.length(); outputFile.seek(outputFileOffset); } } catch (Exception e) { int msgID = MSGID_WAIT4DEL_CANNOT_OPEN_OUTPUT_FILE; String message = getMessage(msgID, outputFilePath.getValue(), String.valueOf(e)); System.err.println(wrapText(message, MAX_LINE_WIDTH)); outputFile = null; } } } // Figure out when to stop waiting. long stopWaitingTime; try @@ -257,8 +294,18 @@ int bytesRead = logFile.read(logBuffer); if (bytesRead > 0) { System.out.write(logBuffer, 0, bytesRead); System.out.flush(); if (outputFile == null) { System.out.write(logBuffer, 0, bytesRead); System.out.flush(); } else { // Write on the file. // TODO outputFile.write(logBuffer, 0, bytesRead); } logFileOffset += bytesRead; } } @@ -283,6 +330,14 @@ } } if (outputFile != null) { try { outputFile.close(); } catch (Throwable t) {} } if (targetFile.exists()) {