| | |
| | | HANDLE _terminationEvent = NULL; |
| | | char *_instanceDir = NULL; |
| | | HANDLE _eventLog = NULL; |
| | | char * _logFile = NULL; |
| | | BOOL DEBUG = FALSE; |
| | | |
| | | |
| | |
| | | } // 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. |
| | | // Debug utility. |
| | | // If the _eventLog is NULL and the DEBUG variable is TRUE write the message |
| | | // in a log file. |
| | | // --------------------------------------------------- |
| | | void debug(char* msg) |
| | | { |
| | | if (DEBUG == TRUE) |
| | | { |
| | | /* |
| | | if (_eventLog != NULL) |
| | | { |
| | | const char* args[1]; |
| | |
| | | NULL // no war data |
| | | ); |
| | | } |
| | | */ |
| | | |
| | | // Log to the file |
| | | FILE *fp; |
| | | if (_logFile == NULL) |
| | | { |
| | | char path [MAX_PATH]; |
| | | if (_instanceDir != NULL) |
| | | { |
| | | int length = strlen(_instanceDir); |
| | | if ((length > 0) && (_instanceDir[length - 1] == '\\')) |
| | | { |
| | | sprintf(path, "%slogs\\windows-service.out", _instanceDir); |
| | | _logFile = strdup(path); |
| | | } |
| | | else |
| | | { |
| | | sprintf(path, "%s\\logs\\windows-service.out", _instanceDir); |
| | | _logFile = strdup(path); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | char execName [MAX_PATH]; |
| | | char instanceDir [MAX_PATH]; |
| | | int length; |
| | | GetModuleFileName ( |
| | | NULL, |
| | | execName, |
| | | MAX_PATH |
| | | ); |
| | | length = strlen(execName) - strlen("lib\\opends_service.exe"); |
| | | if (length > 0) |
| | | { |
| | | strncpy(instanceDir, execName, length); |
| | | instanceDir[length] = '\0'; |
| | | sprintf(path, "%slogs\\windows-service.out", instanceDir); |
| | | _logFile = strdup(path); |
| | | } |
| | | } |
| | | } |
| | | if ((_logFile != NULL) && ((fp = fopen(_logFile, "a")) != NULL)) |
| | | { |
| | | fprintf(fp, "%s\n", msg); |
| | | fclose(fp); |
| | | } |
| | | else |
| | | { |
| | | fprintf(stdout, "%s\n", msg); |
| | | fprintf(stdout, "Could not create log file.\n"); |
| | | } |
| | | } |
| | | } |
| | |
| | | if(_locking(fd, LK_NBLCK, 1) != -1) |
| | | { |
| | | *running = FALSE; |
| | | _locking(fd, LK_UNLCK, 1); |
| | | } |
| | | else |
| | | { |
| | |
| | | } |
| | | else |
| | | { |
| | | debug("Could not open lock file."); |
| | | *running = FALSE; |
| | | returnValue = SERVICE_RETURN_ERROR; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | debug("Lock file path is too long."); |
| | | *running = FALSE; |
| | | returnValue = SERVICE_RETURN_ERROR; |
| | | } |
| | |
| | | // init out params |
| | | char* relativePath = "\\bat\\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) |
| | | if (spawn(command, FALSE) != -1) |
| | | { |
| | | // Try to see if server is really running |
| | | int nTries = 10; |
| | | BOOL running = FALSE; |
| | | |
| | | debug("doStartApplication: the spawn of the process worked."); |
| | | debug("Command:"); |
| | | debug(command); |
| | | // Wait to be able to launch the java process in order it to free the lock |
| | | // on the file. |
| | | Sleep(3000); |
| | |
| | | { |
| | | Sleep(2000); |
| | | } |
| | | nTries--; |
| | | } |
| | | if (running) |
| | | { |
| | | returnValue = SERVICE_RETURN_OK; |
| | | debug("doStartApplication: server running."); |
| | | } |
| | | else |
| | | { |
| | | returnValue = SERVICE_RETURN_ERROR; |
| | | debug("doStartApplication: server not running."); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | |
| | | returnValue = SERVICE_RETURN_ERROR; |
| | | debug("doStartApplication: spawn failed. Sent command:"); |
| | | debug(command); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | returnValue = SERVICE_RETURN_ERROR; |
| | | debug("doStartApplication: the command path name is too long."); |
| | | } |
| | | return returnValue; |
| | | } // doStartApplication |
| | |
| | | sprintf(command, "\"%s%s\" --windowsNetStop", _instanceDir, relativePath); |
| | | |
| | | // launch the command |
| | | if (spawn(command, FALSE) != 0) |
| | | if (spawn(command, FALSE) != -1) |
| | | { |
| | | // Try to see if server is really stopped |
| | | int nTries = 10; |
| | | BOOL running = TRUE; |
| | | |
| | | debug("doStopApplication: the spawn of the process worked."); |
| | | |
| | | // Wait to be able to launch the java process in order it to free the lock |
| | | // on the file. |
| | | Sleep(3000); |
| | |
| | | if (!running) |
| | | { |
| | | returnValue = SERVICE_RETURN_OK; |
| | | debug("doStopApplication: server stopped."); |
| | | } |
| | | else |
| | | { |
| | | returnValue = SERVICE_RETURN_ERROR; |
| | | debug("doStopApplication: server NOT stopped."); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | returnValue = SERVICE_RETURN_ERROR; |
| | | debug("doStopApplication: spawn failed. Sent command:"); |
| | | debug(command); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | returnValue = SERVICE_RETURN_ERROR; |
| | | debug("doStopApplication: the command path name is too long."); |
| | | } |
| | | return returnValue; |
| | | } // doStopApplication |
| | |
| | | // 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. |
| | | // at least COMMAND_SIZE bytes in serviceBinPath. |
| | | // The function returns SERVICE_RETURN_OK if we could create the binary |
| | | // path name and SERVICE_RETURN_ERROR otherwise. |
| | | // --------------------------------------------------------------- |
| | |
| | | { |
| | | // failed to get the path of the executable file |
| | | returnValue = SERVICE_RETURN_ERROR; |
| | | debug("Could not get the path of the executable file.\n"); |
| | | } |
| | | else |
| | | { |
| | |
| | | { |
| | | // buffer was too small, executable name is probably not valid |
| | | returnValue = SERVICE_RETURN_ERROR; |
| | | debug("The name of the module file is too long."); |
| | | } |
| | | else |
| | | { |
| | | if (strlen(fileName) + strlen(" start ") + strlen(_instanceDir) |
| | | < MAX_PATH) |
| | | < COMMAND_SIZE) |
| | | { |
| | | sprintf(serviceBinPath, "%s start \"%s\"", fileName, |
| | | _instanceDir); |
| | |
| | | { |
| | | // buffer was too small, executable name is probably not valid |
| | | returnValue = SERVICE_RETURN_ERROR; |
| | | fprintf(stdout, |
| | | "The name of the resulting windows service command is too long.\n"); |
| | | } |
| | | } |
| | | } |
| | |
| | | // 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 |
| | | // The functions returns SERVICE_RETURN_OK if we could get a service name |
| | | // and SERVICE_RETURN_ERROR otherwise. |
| | | // The serviceName buffer must be allocated OUTSIDE the function and its |
| | | // minimum size must be of 256 (the maximum string length of a Service Name). |
| | |
| | | sprintf(serviceName, curService.serviceName); |
| | | returnValue = SERVICE_RETURN_OK; |
| | | } |
| | | else |
| | | { |
| | | debug("The service name found is too long:"); |
| | | debug(curService.serviceName); |
| | | } |
| | | break; |
| | | } |
| | | } |
| | |
| | | void serviceMain(int argc, char* argv[]) |
| | | { |
| | | // returned status |
| | | char cmdToRun[MAX_PATH]; |
| | | char cmdToRun[COMMAND_SIZE]; |
| | | 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; |
| | | |
| | | debug("serviceMain called."); |
| | | |
| | | code = createServiceBinPath(cmdToRun); |
| | | |
| | | if (code == SERVICE_RETURN_OK) |
| | | { |
| | | code = getServiceName(cmdToRun, serviceName); |
| | | if (code != SERVICE_RETURN_OK) |
| | | { |
| | | debug("serviceMain: could not get service name."); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | debug("serviceMain: failed to create service bin path."); |
| | | } |
| | | |
| | | if (code == SERVICE_RETURN_OK) |
| | |
| | | { |
| | | _serviceStatusHandle = &serviceStatusHandle; |
| | | } |
| | | else |
| | | { |
| | | debug("serviceMain: failed to register service handler."); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | ServiceReturnCode code; |
| | | DWORD checkpoint; |
| | | BOOL running; |
| | | debug("serviceHandler called."); |
| | | switch (controlCode) |
| | | { |
| | | case SERVICE_CONTROL_SHUTDOWN: |
| | | // If system is shuting down then stop the service |
| | | // -> no break here |
| | | debug("serviceHandler: Shutdown."); |
| | | case SERVICE_CONTROL_STOP: |
| | | { |
| | | // update service status to STOP_PENDING |
| | | debug("Stop called"); |
| | | debug("serviceHandler: Stop."); |
| | | _serviceCurStatus = SERVICE_STOP_PENDING; |
| | | checkpoint = CHECKPOINT_FIRST_VALUE; |
| | | updateServiceStatus ( |
| | |
| | | // Request to pause the service |
| | | // ---------------------------- |
| | | case SERVICE_CONTROL_PAUSE: |
| | | // not supported |
| | | break; |
| | | // not supported |
| | | debug("serviceHandler: pause."); |
| | | break; |
| | | |
| | | // Request to resume the service |
| | | // ----------------------------- |
| | | case SERVICE_CONTROL_CONTINUE: |
| | | // not supported |
| | | break; |
| | | // not supported |
| | | debug("serviceHandler: continue."); |
| | | 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 |
| | | ); |
| | | debug("serviceHandler: interrogate."); |
| | | code = isServerRunning(&running); |
| | | if (code != SERVICE_RETURN_OK) |
| | | { |
| | | debug("serviceHandler: error interrogating."); |
| | | } |
| | | else if (running) |
| | | { |
| | | _serviceCurStatus = SERVICE_RUNNING; |
| | | debug("serviceHandler: service running."); |
| | | } |
| | | else |
| | | { |
| | | _serviceCurStatus = SERVICE_STOPPED; |
| | | debug("serviceHandler: service stopped."); |
| | | } |
| | | updateServiceStatus ( |
| | | _serviceCurStatus, |
| | | NO_ERROR, |
| | | 0, |
| | | CHECKPOINT_NO_ONGOING_OPERATION, |
| | | TIMEOUT_NONE, |
| | | _serviceStatusHandle |
| | | ); |
| | | break; |
| | | |
| | | // Other codes are ignored |
| | |
| | | // |
| | | // 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 |
| | | // It is up to the caller of the function to allocate at least COMMAND_SIZE bytes |
| | | // in binPathName. |
| | | // The function returns SERVICE_RETURN_OK if we could create the binary |
| | | // path name and SERVICE_RETURN_ERROR otherwise. |
| | |
| | | char* binPathName) |
| | | { |
| | | ServiceReturnCode returnValue; |
| | | // pathtname to return |
| | | char* binPathname = NULL; |
| | | |
| | | // handle to the service |
| | | SC_HANDLE myService = NULL; |
| | |
| | | } |
| | | else |
| | | { |
| | | char msg[200]; |
| | | sprintf(msg, |
| | | "getBinaryPath: error calling QueryServiceConfig. Code [%d]", |
| | | errCode); |
| | | // error |
| | | debug(msg); |
| | | break; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (strlen(serviceConfig->lpBinaryPathName) < MAX_PATH) |
| | | if (strlen(serviceConfig->lpBinaryPathName) < COMMAND_SIZE) |
| | | { |
| | | sprintf(binPathName, serviceConfig->lpBinaryPathName); |
| | | returnValue = SERVICE_RETURN_OK; |
| | | } |
| | | else |
| | | { |
| | | debug( |
| | | "getBinaryPath: the length of the binary path name is too big."); |
| | | debug("serviceName:"); |
| | | debug(serviceName); |
| | | debug("binary path:"); |
| | | debug(serviceConfig->lpBinaryPathName); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | else |
| | | { |
| | | debug("getServiceList: error More Data."); |
| | | // buffer is not big enough: try again with a proper size |
| | | dataSize += neededSize; |
| | | lpServiceData = (ENUM_SERVICE_STATUS*)calloc( |
| | |
| | | DWORD lastError = GetLastError(); |
| | | if (lastError != ERROR_MORE_DATA) |
| | | { |
| | | char msg[200]; |
| | | returnValue = SERVICE_RETURN_ERROR; |
| | | sprintf(msg, "getServiceList: second try generic error. Code [%d]", |
| | | lastError); |
| | | } |
| | | else |
| | | { |
| | |
| | | } |
| | | else |
| | | { |
| | | debug("getServiceList: error opening scm."); |
| | | returnValue = SERVICE_RETURN_ERROR; |
| | | } |
| | | |
| | |
| | | *nbServices = aux; |
| | | if (aux > 0) |
| | | { |
| | | char binPath[MAX_PATH]; |
| | | char binPath[COMMAND_SIZE]; |
| | | l = (ServiceDescriptor*)calloc(sizeof(ServiceDescriptor), aux); |
| | | for (i = 0; i < aux; i++) |
| | | { |
| | |
| | | { |
| | | l[i].cmdToRun = strdup(binPath); |
| | | } |
| | | else |
| | | { |
| | | debug("Error getting binary path name of service:"); |
| | | debug(l[i].serviceName); |
| | | } |
| | | curService++; |
| | | } |
| | | *serviceList = l; |
| | |
| | | BOOL success; |
| | | SERVICE_DESCRIPTION serviceDescription; |
| | | serviceDescription.lpDescription = description; |
| | | |
| | | success = ChangeServiceConfig2( |
| | | myService, |
| | | SERVICE_CONFIG_DESCRIPTION, |
| | |
| | | int createService(char* displayName, char* description) |
| | | { |
| | | int returnCode = 0; |
| | | char cmdToRun[MAX_PATH]; |
| | | char cmdToRun[COMMAND_SIZE]; |
| | | ServiceReturnCode code; |
| | | |
| | | debug("Creating service."); |
| | | code = createServiceBinPath(cmdToRun); |
| | | |
| | | if (code == SERVICE_RETURN_OK) |
| | |
| | | // OpenDS is registered as a service. |
| | | code = SERVICE_ALREADY_EXISTS; |
| | | createRegistryKey(serviceName); |
| | | debug("createService: service already exists for this instance."); |
| | | } |
| | | else |
| | | { |
| | |
| | | { |
| | | createRegistryKey(serviceName); |
| | | } |
| | | else |
| | | { |
| | | debug("Could not get a service name for command to run"); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | else |
| | | { |
| | | debug("createService could not create bin path."); |
| | | } |
| | | switch (code) |
| | | { |
| | | case SERVICE_RETURN_OK: |
| | | returnCode = 0; |
| | | debug("Service successfully created."); |
| | | break; |
| | | case SERVICE_ALREADY_EXISTS: |
| | | returnCode = 1; |
| | | debug("Service already exists."); |
| | | break; |
| | | case DUPLICATED_SERVICE_NAME: |
| | | returnCode = 2; |
| | | debug("Duplicated service name."); |
| | | break; |
| | | default: |
| | | returnCode = 3; |
| | | debug("Unexpected error creating service."); |
| | | } |
| | | |
| | | return returnCode; |
| | |
| | | int serviceState() |
| | | { |
| | | int returnCode = 0; |
| | | char cmdToRun[MAX_PATH]; |
| | | char cmdToRun[COMMAND_SIZE]; |
| | | char serviceName[MAX_SERVICE_NAME]; |
| | | ServiceReturnCode code; |
| | | |
| | | debug("Getting service state."); |
| | | code = createServiceBinPath(cmdToRun); |
| | | |
| | | if (code == SERVICE_RETURN_OK) |
| | |
| | | // OpenDS is registered as a service. |
| | | fprintf(stdout, serviceName); |
| | | returnCode = 0; |
| | | debug("Service is enabled."); |
| | | } |
| | | else |
| | | { |
| | | returnCode = 1; |
| | | debug("Service is disabled."); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | returnCode = 2; |
| | | debug("An error occurred getting the service status."); |
| | | } |
| | | |
| | | return returnCode; |
| | |
| | | { |
| | | int returnCode = 0; |
| | | ServiceReturnCode code = serviceNameInUse(serviceName); |
| | | |
| | | |
| | | debug("Removing service."); |
| | | |
| | | if (code != SERVICE_IN_USE) |
| | | { |
| | | returnCode = 1; |
| | | debug("Service does not exist."); |
| | | } |
| | | else |
| | | { |
| | |
| | | case SERVICE_RETURN_OK: |
| | | removeRegistryKey(serviceName); |
| | | returnCode = 0; |
| | | debug("Service successfully removed."); |
| | | break; |
| | | case SERVICE_MARKED_FOR_DELETION: |
| | | removeRegistryKey(serviceName); |
| | | returnCode = 2; |
| | | debug("Service marked for deletion."); |
| | | break; |
| | | default: |
| | | returnCode = 3; |
| | | debug("Unexpected error removing service."); |
| | | } |
| | | } |
| | | |
| | | |
| | | return returnCode; |
| | | } // removeServiceWithServiceName |
| | | |
| | |
| | | int removeService() |
| | | { |
| | | int returnCode = 0; |
| | | char cmdToRun[MAX_PATH]; |
| | | char cmdToRun[COMMAND_SIZE]; |
| | | char serviceName[MAX_SERVICE_NAME]; |
| | | ServiceReturnCode code; |
| | | |
| | |
| | | { |
| | | int returnCode; |
| | | char serviceName[MAX_SERVICE_NAME]; |
| | | char cmdToRun[MAX_PATH]; |
| | | char cmdToRun[COMMAND_SIZE]; |
| | | ServiceReturnCode code; |
| | | |
| | | code = createServiceBinPath(cmdToRun); |
| | |
| | | { |
| | | char* subcommand; |
| | | int returnCode = 0; |
| | | |
| | | if (argc <= 1) |
| | | { |
| | | fprintf(stderr, |
| | | fprintf(stdout, |
| | | "Subcommand required: create, state, remove, start or cleanup.\n"); |
| | | returnCode = -1; |
| | | } |
| | |
| | | { |
| | | if (argc <= 4) |
| | | { |
| | | fprintf(stderr, |
| | | fprintf(stdout, |
| | | "Subcommand create requires instance dir, service name and description.\n"); |
| | | returnCode = -1; |
| | | } |
| | |
| | | { |
| | | if (argc <= 2) |
| | | { |
| | | fprintf(stderr, |
| | | fprintf(stdout, |
| | | "Subcommand state requires instance dir.\n"); |
| | | returnCode = -1; |
| | | } |
| | |
| | | { |
| | | if (argc <= 2) |
| | | { |
| | | fprintf(stderr, |
| | | fprintf(stdout, |
| | | "Subcommand remove requires instance dir.\n"); |
| | | returnCode = -1; |
| | | } |
| | |
| | | { |
| | | if (argc <= 2) |
| | | { |
| | | fprintf(stderr, |
| | | fprintf(stdout, |
| | | "Subcommand start requires instance dir.\n"); |
| | | returnCode = -1; |
| | | } |
| | | else |
| | | { |
| | | _instanceDir = strdup(argv[2]); |
| | | updateDebugFlag(argv, argc, 3); |
| | | DEBUG = TRUE; |
| | | returnCode = startService(); |
| | | free(_instanceDir); |
| | | } |
| | |
| | | { |
| | | if (argc <= 2) |
| | | { |
| | | fprintf(stderr, |
| | | fprintf(stdout, |
| | | "Subcommand isrunning requires instance dir.\n"); |
| | | returnCode = -1; |
| | | } |
| | |
| | | { |
| | | if (argc <= 2) |
| | | { |
| | | fprintf(stderr, |
| | | fprintf(stdout, |
| | | "Subcommand cleanup requires service name.\n"); |
| | | returnCode = -1; |
| | | } |
| | |
| | | |
| | | else |
| | | { |
| | | fprintf(stderr, "Unknown subcommand: [%s]\n", subcommand); |
| | | fprintf(stdout, "Unknown subcommand: [%s]\n", subcommand); |
| | | returnCode = -1; |
| | | } |
| | | } |