Hi, We've encountered a problem with the way jk_nt_service.c creates nt services.
Specifically, the call to CreateService uses the name passed in for the service as both the service name and the service display name. This is a problem because there are restrictions on the service name that do not apply to the display name. The MS documentation states that neither forward nor back slashes are allowed but in practice I have found that other characters cause problems as well. For example, if you create a service via jk_nt_service -i "My Service" wrapper.properties the service creates just fine but it fails to start. Since the MS source is not readily available we can't check on what the REAL rules are for the internal service name. To be safe, a solution I have used in the past is to treat the name passed in via the command line as the display name, and then remove all non-alphanumeric characters to generate the internal service name. This is cheap, but might cause trouble if you are unlucky enough to have multiple service display names mapping to a single internal name as in "My Service 1.1" and "My Service 11". An alternative that fixes this is to convert non alphanumerics to their hex representation. I've attached a patch using the first approach since I've used in in the past without any problems. I'll be happy to rework it to hex encode non alphanumerics if there is interest. -David
--- jk_nt_service.c.orig Sun Oct 21 13:25:54 2001 +++ jk_nt_service.c Wed Dec 19 17:59:38 2001 @@ -113,16 +113,22 @@ static void WINAPI service_ctrl(DWORD dwCtrlCode); static void WINAPI service_main(DWORD dwArgc, char **lpszArgv); + +static char *sanitize_service_name(char *displayName); static void install_service(char *name, + char *dname, char *user, char *password, char *deps, BOOL bAutomatic, char *rel_prp_file); -static void remove_service(char *name); +static void remove_service(char *name, + char *dname); static void start_service(char *name, + char *dname, char *machine); static void stop_service(char *name, + char *dname, char *machine); static char *GetLastErrorText(char *lpszBuf, DWORD dwSize); static void AddToMessageLog(char *lpszMsg); @@ -132,6 +138,7 @@ static void start_jk_service(char *name); static void stop_jk_service(void); static int set_registry_values(char *name, + char *dname, char *prp_file); static int create_registry_key(const char *tag, HKEY *key); @@ -182,6 +189,7 @@ int count; int iAction = acNoAction; char *pServiceName = NULL; + char *pServiceDisplayName = NULL; char *pUserName = NULL; char *pPassword = NULL; char *pMachine = NULL; @@ -219,16 +227,16 @@ cmd++; if(0 == stricmp("i", cmd)) { iAction = acInstall; - pServiceName = argv[i+1]; + pServiceDisplayName = argv[i+1]; } else if(0 == stricmp("r", cmd)) { iAction = acRemove; - pServiceName = argv[i+1]; + pServiceDisplayName = argv[i+1]; } else if(0 == stricmp("s", cmd)) { iAction = acStartTC; - pServiceName = argv[i+1]; + pServiceDisplayName = argv[i+1]; } else if(0 == stricmp("t", cmd)) { iAction = acStopTC; - pServiceName = argv[i+1]; + pServiceDisplayName = argv[i+1]; } else if(0 == stricmp("u", cmd)) { pUserName = argv[i+1]; } else if(0 == stricmp("p", cmd)) { @@ -243,18 +251,19 @@ } } } + pServiceName = sanitize_service_name(pServiceDisplayName); switch (iAction) { case acInstall: - install_service(pServiceName, pUserName, pPassword, strDependancy, bAutomatic, argv[i-1]); + install_service(pServiceName, pServiceDisplayName, pUserName, +pPassword, strDependancy, bAutomatic, argv[i-1]); return; case acRemove: - remove_service(pServiceName); + remove_service(pServiceName, pServiceDisplayName); return; case acStartTC: - start_service(pServiceName, pMachine); + start_service(pServiceName, pServiceDisplayName, pMachine); return; case acStopTC: - stop_service(pServiceName, pMachine); + stop_service(pServiceName, pServiceDisplayName, pMachine); return; } } else if(2 == argc) { @@ -274,6 +283,9 @@ usage_message(argv[0]); exit(-1); } __finally { + if (pServiceDisplayName) { + free(pServiceDisplayName); + } WSACleanup(); } } @@ -374,7 +386,31 @@ return fResult; } +/* + Remove non alphanumerics for use as internal service id. + MS docs stipulate not to use forward or back slashes but + spaces also cause trouble. Specifically, the service fails + to start. It seems safest to remove all special chars. + + returned pointer should be freed by the caller. +*/ +char *sanitize_service_name(char *displayName) { + char *clean = strdup(displayName); + char *ptr = clean; + + while(*displayName) { + if (isalnum(*displayName)) { + *ptr++ = *displayName; + } + displayName++; + } + *ptr = '\0'; + + return clean; +} + void install_service(char *name, + char *dname, char *user, char *password, char *deps, @@ -415,9 +451,10 @@ NULL, // database (NULL == default) SC_MANAGER_ALL_ACCESS); // access required if(schSCManager) { + schService = CreateService(schSCManager, // SCManager database - name, // name of service - name, // name to display + name, // name of service + dname, // name to display SERVICE_ALL_ACCESS, // desired access SERVICE_WIN32_OWN_PROCESS, // service type bAutomatic ? SERVICE_AUTO_START : SERVICE_DEMAND_START, // start type @@ -430,9 +467,9 @@ password); // password if(schService) { - printf("The service named %s was created. Now adding registry entries\n", name); + printf("The service named %s was created. Now adding registry entries\n", +dname); - if(set_registry_values(name, szPropPath)) { + if(set_registry_values(name, dname, szPropPath)) { CloseServiceHandle(schService); } else { printf("CreateService failed setting the private registry - %s\n", GetLastErrorText(szErr, sizeof(szErr))); @@ -447,9 +484,10 @@ } else { printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr, sizeof(szErr))); } + } -void remove_service(char *name) +void remove_service(char *name, char *dname) { SC_HANDLE schService; SC_HANDLE schSCManager; @@ -464,7 +502,7 @@ if(schService) { // try to stop the service if(ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus )) { - printf("Stopping %s.", name); + printf("Stopping %s.", dname); Sleep(1000); while(QueryServiceStatus(schService, &ssStatus )) { @@ -477,15 +515,15 @@ } if(ssStatus.dwCurrentState == SERVICE_STOPPED) { - printf("\n%s stopped.\n", name); + printf("\n%s stopped.\n", dname); } else { - printf("\n%s failed to stop.\n", name); + printf("\n%s failed to stop.\n", dname); } } // now remove the service if(DeleteService(schService)) { - printf("%s removed.\n", name); + printf("%s removed.\n", dname); } else { printf("DeleteService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr))); } @@ -501,7 +539,7 @@ } } -void start_service(char *name, char *machine) +void start_service(char *name, char *dname, char *machine) { SC_HANDLE schService; SC_HANDLE schSCManager; @@ -516,7 +554,7 @@ if(schService) { // try to start the service if(StartService(schService, 0, NULL)) { - printf("Starting %s.", name); + printf("Starting %s.", dname); Sleep(1000); while(QueryServiceStatus(schService, &ssStatus )) { @@ -529,9 +567,9 @@ } if(ssStatus.dwCurrentState == SERVICE_RUNNING) { - printf("\n%s started.\n", name); + printf("\n%s started.\n", dname); } else { - printf("\n%s failed to start.\n", name); + printf("\n%s failed to start.\n", dname); } } else @@ -548,7 +586,7 @@ } } -void stop_service(char *name, char *machine) +void stop_service(char *name, char *dname, char *machine) { SC_HANDLE schService; SC_HANDLE schSCManager; @@ -563,7 +601,7 @@ if(schService) { // try to stop the service if(ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus )) { - printf("Stopping %s.", name); + printf("Stopping %s.", dname); Sleep(1000); while(QueryServiceStatus(schService, &ssStatus )) { @@ -576,9 +614,9 @@ } if(ssStatus.dwCurrentState == SERVICE_STOPPED) { - printf("\n%s stopped.\n", name); + printf("\n%s stopped.\n", dname); } else { - printf("\n%s failed to stop.\n", name); + printf("\n%s failed to stop.\n", dname); } } else @@ -596,6 +634,7 @@ } static int set_registry_values(char *name, + char *dname, char *prp_file) { char tag[1024]; @@ -649,8 +688,8 @@ if(rc) { printf("Registry values were added\n"); printf("If you have already updated wrapper.properties you may start the %s service by executing \"jk_nt_service -s %s\" from the command prompt\n", - name, - name); + dname, + dname); } } RegCloseKey(hk);
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>