X-Git-Url: http://git.iain.cx/?a=blobdiff_plain;f=service.cpp;h=d402ab32f751e77e8e4fb25ecbe9da204350ce0a;hb=73dbba7a2e6150dea8f58dd2c25ab914a0636308;hp=eec22619c4983dec6877d15a2b0de8feffb95bd7;hpb=b6cfe6e22a89192c1bdcf234f17a72fd9993d570;p=nssm.git diff --git a/service.cpp b/service.cpp index eec2261..d402ab3 100644 --- a/service.cpp +++ b/service.cpp @@ -65,6 +65,123 @@ QUERY_SERVICE_CONFIG *query_service_config(const TCHAR *service_name, SC_HANDLE return qsc; } +int set_service_description(const TCHAR *service_name, SC_HANDLE service_handle, TCHAR *buffer) { + SERVICE_DESCRIPTION description; + ZeroMemory(&description, sizeof(description)); + /* + lpDescription must be NULL if we aren't changing, the new description + or "". + */ + if (buffer && buffer[0]) description.lpDescription = buffer; + else description.lpDescription = _T(""); + + if (ChangeServiceConfig2(service_handle, SERVICE_CONFIG_DESCRIPTION, &description)) return 0; + + log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SERVICE_CONFIG_DESCRIPTION_FAILED, service_name, error_string(GetLastError()), 0); + return 1; +} + +int get_service_description(const TCHAR *service_name, SC_HANDLE service_handle, unsigned long len, TCHAR *buffer) { + if (! buffer) return 1; + + unsigned long bufsize; + QueryServiceConfig2(service_handle, SERVICE_CONFIG_DESCRIPTION, 0, 0, &bufsize); + unsigned long error = GetLastError(); + if (error == ERROR_INSUFFICIENT_BUFFER) { + SERVICE_DESCRIPTION *description = (SERVICE_DESCRIPTION *) HeapAlloc(GetProcessHeap(), 0, bufsize); + if (! description) { + print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("SERVICE_CONFIG_DESCRIPTION"), _T("get_service_description()")); + return 2; + } + + if (QueryServiceConfig2(service_handle, SERVICE_CONFIG_DESCRIPTION, (unsigned char *) description, bufsize, &bufsize)) { + if (description->lpDescription) _sntprintf_s(buffer, len, _TRUNCATE, _T("%s"), description->lpDescription); + else ZeroMemory(buffer, len * sizeof(TCHAR)); + HeapFree(GetProcessHeap(), 0, description); + return 0; + } + else { + HeapFree(GetProcessHeap(), 0, description); + print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service_name, _T("SERVICE_CONFIG_DESCRIPTION"), error_string(error)); + return 3; + } + } + else { + print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service_name, _T("SERVICE_CONFIG_DESCRIPTION"), error_string(error)); + return 4; + } + + return 0; +} + +int get_service_startup(const TCHAR *service_name, SC_HANDLE service_handle, const QUERY_SERVICE_CONFIG *qsc, unsigned long *startup) { + if (! qsc) return 1; + + switch (qsc->dwStartType) { + case SERVICE_DEMAND_START: *startup = NSSM_STARTUP_MANUAL; break; + case SERVICE_DISABLED: *startup = NSSM_STARTUP_DISABLED; break; + default: *startup = NSSM_STARTUP_AUTOMATIC; + } + + if (*startup != NSSM_STARTUP_AUTOMATIC) return 0; + + /* Check for delayed start. */ + unsigned long bufsize; + unsigned long error; + QueryServiceConfig2(service_handle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, 0, 0, &bufsize); + error = GetLastError(); + if (error == ERROR_INSUFFICIENT_BUFFER) { + SERVICE_DELAYED_AUTO_START_INFO *info = (SERVICE_DELAYED_AUTO_START_INFO *) HeapAlloc(GetProcessHeap(), 0, bufsize); + if (! info) { + print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("SERVICE_DELAYED_AUTO_START_INFO"), _T("get_service_startup()")); + return 2; + } + + if (QueryServiceConfig2(service_handle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, (unsigned char *) info, bufsize, &bufsize)) { + if (info->fDelayedAutostart) *startup = NSSM_STARTUP_DELAYED; + HeapFree(GetProcessHeap(), 0, info); + return 0; + } + else { + error = GetLastError(); + if (error != ERROR_INVALID_LEVEL) { + print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service_name, _T("SERVICE_CONFIG_DELAYED_AUTO_START_INFO"), error_string(error)); + return 3; + } + } + } + else if (error != ERROR_INVALID_LEVEL) { + print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service_name, _T("SERVICE_DELAYED_AUTO_START_INFO"), error_string(error)); + return 3; + } + + return 0; +} + +int get_service_username(const TCHAR *service_name, const QUERY_SERVICE_CONFIG *qsc, TCHAR **username, size_t *usernamelen) { + if (! username) return 1; + if (! usernamelen) return 1; + + *username = 0; + *usernamelen = 0; + + if (! qsc) return 1; + + if (str_equiv(qsc->lpServiceStartName, NSSM_LOCALSYSTEM_ACCOUNT)) return 0; + + size_t len = _tcslen(qsc->lpServiceStartName); + *username = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(TCHAR)); + if (! *username) { + print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("username"), _T("get_service_username()")); + return 2; + } + + memmove(*username, qsc->lpServiceStartName, (len + 1) * sizeof(TCHAR)); + *usernamelen = len; + + return 0; +} + static int grant_logon_as_service(const TCHAR *username) { if (str_equiv(username, NSSM_LOCALSYSTEM_ACCOUNT)) return 0; @@ -324,7 +441,6 @@ int pre_edit_service(int argc, TCHAR **argv) { /* Get system details. */ unsigned long bufsize; - unsigned long error; QUERY_SERVICE_CONFIG *qsc = query_service_config(service->name, service->handle); if (! qsc) { CloseHandle(service->handle); @@ -341,26 +457,20 @@ int pre_edit_service(int argc, TCHAR **argv) { return 3; } - switch (qsc->dwStartType) { - case SERVICE_DEMAND_START: service->startup = NSSM_STARTUP_MANUAL; break; - case SERVICE_DISABLED: service->startup = NSSM_STARTUP_DISABLED; break; - default: service->startup = NSSM_STARTUP_AUTOMATIC; - } - if (! str_equiv(qsc->lpServiceStartName, NSSM_LOCALSYSTEM_ACCOUNT)) { - size_t len = _tcslen(qsc->lpServiceStartName); - service->username = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(TCHAR)); - if (service->username) { - memmove(service->username, qsc->lpServiceStartName, (len + 1) * sizeof(TCHAR)); - service->usernamelen = (unsigned long) len; - } - else { - HeapFree(GetProcessHeap(), 0, qsc); - CloseHandle(service->handle); - CloseServiceHandle(services); - print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("username"), _T("pre_edit_service()")); - return 4; - } + if (get_service_startup(service->name, service->handle, qsc, &service->startup)) { + HeapFree(GetProcessHeap(), 0, qsc); + CloseHandle(service->handle); + CloseServiceHandle(services); + return 4; } + + if (get_service_username(service->name, qsc, &service->username, &service->usernamelen)) { + HeapFree(GetProcessHeap(), 0, qsc); + CloseHandle(service->handle); + CloseServiceHandle(services); + return 5; + } + _sntprintf_s(service->displayname, _countof(service->displayname), _TRUNCATE, _T("%s"), qsc->lpDisplayName); /* Get the canonical service name. We open it case insensitively. */ @@ -372,66 +482,9 @@ int pre_edit_service(int argc, TCHAR **argv) { HeapFree(GetProcessHeap(), 0, qsc); /* Get extended system details. */ - if (service->startup == NSSM_STARTUP_AUTOMATIC) { - QueryServiceConfig2(service->handle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, 0, 0, &bufsize); - error = GetLastError(); - if (error == ERROR_INSUFFICIENT_BUFFER) { - SERVICE_DELAYED_AUTO_START_INFO *info = (SERVICE_DELAYED_AUTO_START_INFO *) HeapAlloc(GetProcessHeap(), 0, bufsize); - if (! info) { - CloseHandle(service->handle); - CloseServiceHandle(services); - print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("SERVICE_DELAYED_AUTO_START_INFO"), _T("pre_edit_service()")); - return 5; - } - - if (QueryServiceConfig2(service->handle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, (unsigned char *) info, bufsize, &bufsize)) { - if (info->fDelayedAutostart) service->startup = NSSM_STARTUP_DELAYED; - } - else { - error = GetLastError(); - if (error != ERROR_INVALID_LEVEL) { - CloseHandle(service->handle); - CloseServiceHandle(services); - print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service->name, _T("SERVICE_CONFIG_DELAYED_AUTO_START_INFO"), error_string(error)); - return 5; - } - } - } - else if (error != ERROR_INVALID_LEVEL) { - CloseHandle(service->handle); - CloseServiceHandle(services); - print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service->name, _T("SERVICE_DELAYED_AUTO_START_INFO"), error_string(error)); - return 5; - } - } - - QueryServiceConfig2(service->handle, SERVICE_CONFIG_DESCRIPTION, 0, 0, &bufsize); - error = GetLastError(); - if (error == ERROR_INSUFFICIENT_BUFFER) { - SERVICE_DESCRIPTION *description = (SERVICE_DESCRIPTION *) HeapAlloc(GetProcessHeap(), 0, bufsize); - if (! description) { - CloseHandle(service->handle); - CloseServiceHandle(services); - print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("SERVICE_CONFIG_DESCRIPTION"), _T("pre_edit_service()")); - return 6; - } - - if (QueryServiceConfig2(service->handle, SERVICE_CONFIG_DESCRIPTION, (unsigned char *) description, bufsize, &bufsize)) { - if (description->lpDescription) _sntprintf_s(service->description, _countof(service->description), _TRUNCATE, _T("%s"), description->lpDescription); - HeapFree(GetProcessHeap(), 0, description); - } - else { - HeapFree(GetProcessHeap(), 0, description); - CloseHandle(service->handle); - CloseServiceHandle(services); - print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service->name, _T("SERVICE_CONFIG_DELAYED_AUTO_START_INFO"), error_string(error)); - return 6; - } - } - else { + if (get_service_description(service->name, service->handle, _countof(service->description), service->description)) { CloseHandle(service->handle); CloseServiceHandle(services); - print_message(stderr, NSSM_MESSAGE_QUERYSERVICECONFIG2_FAILED, service->name, _T("SERVICE_CONFIG_DELAYED_AUTO_START_INFO"), error_string(error)); return 6; } @@ -552,13 +605,7 @@ int edit_service(nssm_service_t *service, bool editing) { } if (service->description[0] || editing) { - SERVICE_DESCRIPTION description; - ZeroMemory(&description, sizeof(description)); - if (service->description[0]) description.lpDescription = service->description; - else description.lpDescription = 0; - if (! ChangeServiceConfig2(service->handle, SERVICE_CONFIG_DESCRIPTION, &description)) { - log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SERVICE_CONFIG_DESCRIPTION_FAILED, service->name, error_string(GetLastError()), 0); - } + set_service_description(service->name, service->handle, service->description); } SERVICE_DELAYED_AUTO_START_INFO delayed;