X-Git-Url: http://git.iain.cx/?a=blobdiff_plain;f=service.cpp;h=849f79093573d4ffa383c8eb9acf9e75f058fed7;hb=94d25a5dcfad872c97e71b646429fc87dc66acc2;hp=8561616387bcb24b2e099475d4a1718cbb06668c;hpb=3c9d8f85d38b4c97b83e2baca63211a4008b5e0d;p=nssm.git diff --git a/service.cpp b/service.cpp index 8561616..849f790 100644 --- a/service.cpp +++ b/service.cpp @@ -906,7 +906,11 @@ int pre_edit_service(int argc, TCHAR **argv) { mandatory = 3; mode = MODE_RESETTING; } - else if (str_equiv(verb, _T("dump"))) mode = MODE_DUMPING; + else if (str_equiv(verb, _T("dump"))) { + mandatory = 1; + remainder = 2; + mode = MODE_DUMPING; + } if (argc < mandatory) return usage(1); const TCHAR *parameter = 0; @@ -1056,17 +1060,27 @@ int pre_edit_service(int argc, TCHAR **argv) { int ret; if (mode == MODE_DUMPING) { + TCHAR *service_name = service->name; + if (argc > remainder) service_name = argv[remainder]; if (service->native) key = 0; else { key = open_registry(service->name, KEY_READ); if (! key) return 4; } + TCHAR quoted_service_name[SERVICE_NAME_LENGTH * 2]; + TCHAR quoted_exe[EXE_LENGTH * 2]; + TCHAR quoted_nssm[EXE_LENGTH * 2]; + if (quote(service_name, quoted_service_name, _countof(quoted_service_name))) return 5; + if (quote(service->exe, quoted_exe, _countof(quoted_exe))) return 6; + if (quote(nssm_exe(), quoted_nssm, _countof(quoted_nssm))) return 6; + _tprintf(_T("%s install %s %s\n"), quoted_nssm, quoted_service_name, quoted_exe); + ret = 0; for (i = 0; settings[i].name; i++) { setting = &settings[i]; if (! setting->native && service->native) continue; - if (dump_setting(service->name, key, service->handle, setting)) ret++; + if (dump_setting(service_name, key, service->handle, setting)) ret++; } if (! service->native) RegCloseKey(key); @@ -2253,3 +2267,77 @@ int list_nssm_services() { HeapFree(GetProcessHeap(), 0, status); return 0; } + +int service_process_tree(int argc, TCHAR **argv) { + int errors = 0; + if (argc < 1) return usage(1); + + SC_HANDLE services = open_service_manager(SC_MANAGER_CONNECT); + if (! services) { + print_message(stderr, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED); + return 1; + } + + /* + We need SeDebugPrivilege to read the process tree. + We ignore failure here so that an error will be printed later when we + try to open a process handle. + */ + HANDLE token = get_debug_token(); + + TCHAR canonical_name[SERVICE_NAME_LENGTH]; + SERVICE_STATUS_PROCESS service_status; + nssm_service_t *service; + kill_t k; + + int i; + for (i = 0; i < argc; i++) { + TCHAR *service_name = argv[i]; + SC_HANDLE service_handle = open_service(services, service_name, SERVICE_QUERY_STATUS, canonical_name, _countof(canonical_name)); + if (! service_handle) { + errors++; + continue; + } + + unsigned long size; + int ret = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (LPBYTE) &service_status, sizeof(service_status), &size); + long error = GetLastError(); + CloseServiceHandle(service_handle); + if (! ret) { + _ftprintf(stderr, _T("%s: %s\n"), canonical_name, error_string(error)); + errors++; + continue; + } + + ZeroMemory(&k, sizeof(k)); + k.pid = service_status.dwProcessId; + if (! k.pid) continue; + + k.process_handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, k.pid); + if (! k.process_handle) { + _ftprintf(stderr, _T("%s: %lu: %s\n"), canonical_name, k.pid, error_string(GetLastError())); + continue; + } + + if (get_process_creation_time(k.process_handle, &k.creation_time)) continue; + /* Dummy exit time so we can check processes' parents. */ + GetSystemTimeAsFileTime(&k.exit_time); + + service = alloc_nssm_service(); + if (! service) { + errors++; + continue; + } + + _sntprintf_s(service->name, _countof(service->name), _TRUNCATE, _T("%s"), canonical_name); + k.name = service->name; + walk_process_tree(service, print_process, &k, k.pid); + + cleanup_nssm_service(service); + } + + CloseServiceHandle(services); + if (token != INVALID_HANDLE_VALUE) CloseHandle(token); + + return errors; +}