mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

jvergara
15.52.2007 4c484ff6ea57ce79c5072a830e6536ac41c820c3
Fix for issue 528 (Windows Service Definition for Automatic Startup).

The following changes are targeted to be able to run OpenDS as a windows
service.

The idea is to be able to run OpenDS to run as a service and to be able
also to disable this feature.

The setup has been updated to run OpenDS as a service in windows (which
is the standard behavior in this platform). The uninstall has also been
updated to remove all references to OpenDS in the Registry and in the
list of services once OpenDS has been uninstalled.

A new executable (opends_service.exe) has been added to be able to
perform all the tasks that require native code
(registering/unregistering the service, sending events to the event log,
etc.). Most of the code required by this executable is in the file
service.c. The README file has been updated and a Makefile file
provided to generate all the executables.

A new command line has been added: windowsservice.bat. The usage of
this command line is the following one:

This utility may be used to configure OpenDS as a Windows service.
Usage: windowsservice {options}
where {options} include:
-e or --enableService
Enables OpenDS as a Windows service.
-d or --disableService
Disables OpenDS as a Windows service and stops the server
-s or --serviceState
Provides information about the state of OpenDS as a Windows service.
-H or --help
Display this usage information.

The class associated with this command line (ConfigureWindowsService)
uses opends_service.exe. ConfigureWindowsService is basically a wrapper
that allows to have the messages displayed to the user in the Java code
(and so to minimize what is done by the native code).


Some changes have been made in the start-ds(.bat) and stop-ds(.bat)
scripts by extending what the --checkStartability (in DirectoryServer
class) and --checkStoppability (in StopDS class) do. I think that it is
a good idea to have all the parsing of the arguments into the java code
(specially considering the limitations of the .bat files). So I have
moved most of the parsing to the java code so that the is the java code
that provides a return code to the scripts to tell them what to do
(start the server in detach mode, stop the server using a system call,
stop the server using protocol, etc.).

In the particular case of how start-ds.bat and stop-ds.bat have been
updated to manage the case where the server must be started using the
system call 'net start <service_name>' and 'net stop <service_name>'.
--checkstoppability and --checkstartability tell whether the server must
be stopped/started directly with a system call (or stopped using LDAP
protocol) or using the Windows Service system. If it is the latter the
bat files use two new auxiliary classes (StopWindowsService and
StartWindowsService). These classes figure out the service name
associated with the OpenDS instance and call net stop (or net start)
using that service name.

When net start/net stop are called start-ds.bat (or stop-ds.bat) are
called. The Windows Services have been configured to call start-ds.bat
and stop-ds.bat with some particular options (--windowsNetStart and
--windowsNetStop) to identify the case where we must start/stop the
server directly (and so not having an infinite recursive loop of calls
to net start/net stop).

In order to have the same user experience when the server is configured
to run as a service and when is not the tool class WaitForDelete has
also been updated to write its output to a file. This has been done
because piping from the standard output to a file in the context of a
Windows Service call does not seem to work properly. So now
WaitForDelete has a new option --outputFile.

setup --cli on windows has a new option '-n' or '-noWindowsService' to allow not to enable the windows service. When run in interactive mode and this options is not specified the user will systematically be asked whether to enable the windows service or not.

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