From 4c484ff6ea57ce79c5072a830e6536ac41c820c3 Mon Sep 17 00:00:00 2001
From: jvergara <jvergara@localhost>
Date: Thu, 15 Mar 2007 15:52:50 +0000
Subject: [PATCH] Fix for issue 528 (Windows Service Definition for Automatic Startup).
---
opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java | 27
opendj-sdk/opends/build-tools/src/windows/Makefile | 86
opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java | 15
opendj-sdk/opends/resource/bin/stop-ds | 158
opendj-sdk/opends/build-tools/src/windows/common.c | 96
opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartDownloader.java | 4
opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java | 13
opendj-sdk/opends/src/server/org/opends/server/tools/StopDS.java | 219 +
opendj-sdk/opends/resource/bin/start-ds | 55
opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java | 256 ++
opendj-sdk/opends/src/server/org/opends/server/tools/ConfigureWindowsService.java | 612 ++++++
opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressStep.java | 4
opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java | 31
opendj-sdk/opends/build-tools/src/windows/winlauncher.h | 53
opendj-sdk/opends/build-tools/src/windows/service.h | 109 +
opendj-sdk/opends/lib/opends_service.exe | 0
opendj-sdk/opends/build-tools/src/windows/common.h | 35
opendj-sdk/opends/lib/winlauncher.exe | 0
opendj-sdk/opends/resource/bin/stop-ds.bat | 92
opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java | 4
opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallException.java | 4
opendj-sdk/opends/build-tools/src/windows/winlauncher.c | 661 ++---
opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties | 49
opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java | 223 +
opendj-sdk/opends/build-tools/src/windows/EventLogMsg.mc | 103 +
opendj-sdk/opends/build-tools/src/windows/service.c | 2167 +++++++++++++++++++++
opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java | 11
opendj-sdk/opends/build.xml | 8
opendj-sdk/opends/resource/bin/start-ds.bat | 32
opendj-sdk/opends/build-tools/src/windows/README | 86
opendj-sdk/opends/resource/bin/windowsservice.bat | 33
opendj-sdk/opends/src/server/org/opends/server/tools/StartWindowsService.java | 142 +
opendj-sdk/opends/src/server/org/opends/server/tools/WaitForFileDelete.java | 59
opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java | 13
opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressStep.java | 4
opendj-sdk/opends/src/server/org/opends/server/tools/StopWindowsService.java | 147 +
opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java | 338 +++
opendj-sdk/opends/src/server/org/opends/server/tools/InstallDS.java | 45
38 files changed, 5,328 insertions(+), 666 deletions(-)
diff --git a/opendj-sdk/opends/build-tools/src/windows/EventLogMsg.mc b/opendj-sdk/opends/build-tools/src/windows/EventLogMsg.mc
new file mode 100644
index 0000000..3f9114e
--- /dev/null
+++ b/opendj-sdk/opends/build-tools/src/windows/EventLogMsg.mc
@@ -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
+.
+
diff --git a/opendj-sdk/opends/build-tools/src/windows/Makefile b/opendj-sdk/opends/build-tools/src/windows/Makefile
new file mode 100644
index 0000000..93fd9fa
--- /dev/null
+++ b/opendj-sdk/opends/build-tools/src/windows/Makefile
@@ -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
+
diff --git a/opendj-sdk/opends/build-tools/src/windows/README b/opendj-sdk/opends/build-tools/src/windows/README
index 65c76c3..6a19ec2 100644
--- a/opendj-sdk/opends/build-tools/src/windows/README
+++ b/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.
diff --git a/opendj-sdk/opends/build-tools/src/windows/common.c b/opendj-sdk/opends/build-tools/src/windows/common.c
new file mode 100644
index 0000000..0868745
--- /dev/null
+++ b/opendj-sdk/opends/build-tools/src/windows/common.c
@@ -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
+
diff --git a/opendj-sdk/opends/build-tools/src/windows/common.h b/opendj-sdk/opends/build-tools/src/windows/common.h
new file mode 100644
index 0000000..969909d
--- /dev/null
+++ b/opendj-sdk/opends/build-tools/src/windows/common.h
@@ -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);
diff --git a/opendj-sdk/opends/build-tools/src/windows/service.c b/opendj-sdk/opends/build-tools/src/windows/service.c
new file mode 100644
index 0000000..2442c82
--- /dev/null
+++ b/opendj-sdk/opends/build-tools/src/windows/service.c
@@ -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
+
diff --git a/opendj-sdk/opends/build-tools/src/windows/service.h b/opendj-sdk/opends/build-tools/src/windows/service.h
new file mode 100644
index 0000000..cc69bee
--- /dev/null
+++ b/opendj-sdk/opends/build-tools/src/windows/service.h
@@ -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);
+
diff --git a/opendj-sdk/opends/build-tools/src/windows/winlauncher.c b/opendj-sdk/opends/build-tools/src/windows/winlauncher.c
index fd6464b..5bd057d 100644
--- a/opendj-sdk/opends/build-tools/src/windows/winlauncher.c
+++ b/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;
}
+
diff --git a/opendj-sdk/opends/build-tools/src/windows/winlauncher.h b/opendj-sdk/opends/build-tools/src/windows/winlauncher.h
index 273ced3..e577a39 100644
--- a/opendj-sdk/opends/build-tools/src/windows/winlauncher.h
+++ b/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
+
diff --git a/opendj-sdk/opends/build.xml b/opendj-sdk/opends/build.xml
index 78d6fe4..b5be56f 100644
--- a/opendj-sdk/opends/build.xml
+++ b/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>
diff --git a/opendj-sdk/opends/lib/opends_service.exe b/opendj-sdk/opends/lib/opends_service.exe
new file mode 100755
index 0000000..7a5a5b3
--- /dev/null
+++ b/opendj-sdk/opends/lib/opends_service.exe
Binary files differ
diff --git a/opendj-sdk/opends/lib/winlauncher.exe b/opendj-sdk/opends/lib/winlauncher.exe
index a92ef27..0b278e2 100755
--- a/opendj-sdk/opends/lib/winlauncher.exe
+++ b/opendj-sdk/opends/lib/winlauncher.exe
Binary files differ
diff --git a/opendj-sdk/opends/resource/bin/start-ds b/opendj-sdk/opends/resource/bin/start-ds
index 1d21ce9..d7f6e57 100755
--- a/opendj-sdk/opends/resource/bin/start-ds
+++ b/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
diff --git a/opendj-sdk/opends/resource/bin/start-ds.bat b/opendj-sdk/opends/resource/bin/start-ds.bat
index effbb06..7cd4fcd 100644
--- a/opendj-sdk/opends/resource/bin/start-ds.bat
+++ b/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
diff --git a/opendj-sdk/opends/resource/bin/stop-ds b/opendj-sdk/opends/resource/bin/stop-ds
index 9969147..8269397 100755
--- a/opendj-sdk/opends/resource/bin/stop-ds
+++ b/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 "${@}"
diff --git a/opendj-sdk/opends/resource/bin/stop-ds.bat b/opendj-sdk/opends/resource/bin/stop-ds.bat
index fc9fe8c..9145664 100644
--- a/opendj-sdk/opends/resource/bin/stop-ds.bat
+++ b/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
diff --git a/opendj-sdk/opends/resource/bin/windowsservice.bat b/opendj-sdk/opends/resource/bin/windowsservice.bat
new file mode 100644
index 0000000..14ddae7
--- /dev/null
+++ b/opendj-sdk/opends/resource/bin/windowsservice.bat
@@ -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" %*
+
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java
index cd9889f..772d9a9 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallException.java
+++ b/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
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java
index 5a283ee..165edc2 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallLauncher.java
+++ b/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);
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressStep.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressStep.java
index 05ade2c..df25583 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallProgressStep.java
+++ b/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,
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
index bef514e..c972175 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
+++ b/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())
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java
index a81f378..94da554 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java
+++ b/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);
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java
index 3e0b3f5..f0b4bf8 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/offline/OfflineInstaller.java
+++ b/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);
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartDownloader.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartDownloader.java
index 975028d..9d46da2 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartDownloader.java
+++ b/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);
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java
index 8f16bb6..4424e1c 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/installer/webstart/WebStartInstaller.java
+++ b/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);
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties
index f1d1900..4c9d7eb 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/resources/Resources.properties
+++ b/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 \
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallException.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallException.java
index ea72225..5b77db0 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallException.java
+++ b/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
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressStep.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressStep.java
index 0fc2ee7..3fcd5a1 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/UninstallProgressStep.java
+++ b/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,
diff --git a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java b/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java
index 10787f8..53ea429 100644
--- a/opendj-sdk/opends/src/quicksetup/org/opends/quicksetup/uninstaller/Uninstaller.java
+++ b/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));
+ }
+ }
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java b/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
index 7ee531b..bb0b5a8 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/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;
+ }
+
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java
index f90d343..6229ac3 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java
+++ b/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.");
}
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
index 17bb407..de101c5 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
+++ b/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.");
}
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/ConfigureWindowsService.java b/opendj-sdk/opends/src/server/org/opends/server/tools/ConfigureWindowsService.java
new file mode 100644
index 0000000..fd16026
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/ConfigureWindowsService.java
@@ -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";
+ }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/InstallDS.java b/opendj-sdk/opends/src/server/org/opends/server/tools/InstallDS.java
index 5399c19..86b1314 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/InstallDS.java
+++ b/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())
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/StartWindowsService.java b/opendj-sdk/opends/src/server/org/opends/server/tools/StartWindowsService.java
new file mode 100644
index 0000000..043f704
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/StartWindowsService.java
@@ -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;
+ }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/StopDS.java b/opendj-sdk/opends/src/server/org/opends/server/tools/StopDS.java
index 1f06a81..598cf35 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/StopDS.java
+++ b/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;
+ }
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/StopWindowsService.java b/opendj-sdk/opends/src/server/org/opends/server/tools/StopWindowsService.java
new file mode 100644
index 0000000..7ef7aca
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/StopWindowsService.java
@@ -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;
+ }
+}
+
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/WaitForFileDelete.java b/opendj-sdk/opends/src/server/org/opends/server/tools/WaitForFileDelete.java
index 111b11b..a9d9bc4 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/WaitForFileDelete.java
+++ b/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())
{
--
Gitblit v1.10.0