Index: base/service_utils.cc |
diff --git a/base/service_utils.cc b/base/service_utils.cc |
deleted file mode 100644 |
index e190bd54d8384e78b2958be9d364299052c00e6f..0000000000000000000000000000000000000000 |
--- a/base/service_utils.cc |
+++ /dev/null |
@@ -1,360 +0,0 @@ |
-// Copyright 2007-2009 Google Inc. |
-// |
-// Licensed under the Apache License, Version 2.0 (the "License"); |
-// you may not use this file except in compliance with the License. |
-// You may obtain a copy of the License at |
-// |
-// http://www.apache.org/licenses/LICENSE-2.0 |
-// |
-// Unless required by applicable law or agreed to in writing, software |
-// distributed under the License is distributed on an "AS IS" BASIS, |
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
-// See the License for the specific language governing permissions and |
-// limitations under the License. |
-// ======================================================================== |
- |
-// |
-// Service-related utilities. |
-// |
- |
-#include "omaha/base/service_utils.h" |
- |
-#include <windows.h> |
-#include "omaha/base/constants.h" |
-#include "omaha/base/debug.h" |
-#include "omaha/base/error.h" |
-#include "omaha/base/reg_key.h" |
-#include "omaha/base/smart_handle.h" |
-#include "omaha/base/string.h" |
-#include "omaha/base/timer.h" |
-#include "omaha/base/utils.h" |
- |
-namespace omaha { |
- |
-HRESULT ScmDatabase::EnumerateServices( |
- ScmDatabase::EnumerateServicesCallback callback, |
- void* callback_context) { |
- ASSERT1(callback); |
- if (!callback) |
- return E_POINTER; |
- |
- const wchar_t* kServicesRegKeyFromRoot = |
- L"SYSTEM\\CurrentControlSet\\Services"; |
- |
- HRESULT hr = E_FAIL; |
- |
- RegKey services_key; |
- if (FAILED(hr = services_key.Open(HKEY_LOCAL_MACHINE, |
- kServicesRegKeyFromRoot, |
- KEY_ENUMERATE_SUB_KEYS))) { |
- ASSERT1(false); |
- REPORT(false, R_ERROR, (L"Couldn't open services subkey, hr=0x%x", hr), |
- 9834572); |
- return hr; |
- } |
- |
- CString service_name; |
- int key_index = 0; |
- while (SUCCEEDED(hr = services_key.GetSubkeyNameAt(key_index++, |
- &service_name))) { |
- hr = callback(callback_context, service_name); |
- if (FAILED(hr) || hr == S_FALSE) { |
- // Callback asked to terminate enumeration. |
- return hr; |
- } |
- } |
- |
- if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)) { |
- ASSERT1(false); |
- REPORT(false, R_ERROR, (L"Failed enumerating service subkeys: 0x%x", hr), |
- 1499372); |
- return hr; |
- } |
- |
- return S_OK; |
-} |
- |
-bool ScmDatabase::IsServiceStateEqual(SC_HANDLE service, DWORD state) { |
- ASSERT1(service); |
- |
- DWORD bytes_needed_ignored = 0; |
- byte buffer[8 * 1024] = { 0 }; |
- QUERY_SERVICE_CONFIG* service_config = |
- reinterpret_cast<QUERY_SERVICE_CONFIG*>(buffer); |
- if (!::QueryServiceConfig(service, service_config, sizeof(buffer), |
- &bytes_needed_ignored)) { |
- ASSERT(false, (L"Failed to query service config, perhaps handle is missing " |
- L"SERVICE_QUERY_CONFIG rights?")); |
- return false; |
- } |
- |
- return (service_config[0].dwStartType == state); |
-} |
- |
-bool ScmDatabase::IsServiceMarkedDeleted(SC_HANDLE service) { |
- ASSERT1(service); |
- |
- // Services that have been marked deleted are always in the |
- // SERVICE_DISABLED state. The converse is not true, and unfortunately |
- // there is no way to check if a service has been marked deleted except by |
- // attempting to change one of its configuration parameters, at which |
- // point you get a specific error indicating it has been marked deleted. |
- // |
- // The following call to ChangeServiceConfig does not actually change any |
- // of the service's configuration, but should hopefully return the |
- // specific error if the service has been marked deleted. |
- if (!::ChangeServiceConfig(service, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, |
- SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, |
- NULL, NULL, NULL) && |
- ::GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE) { |
- ASSERT1(IsServiceStateEqual(service, SERVICE_DISABLED)); |
- return true; |
- } else { |
- return false; |
- } |
-} |
- |
-HRESULT ServiceInstall::UninstallByPrefix(void* context, |
- const wchar_t* service_name) { |
- ASSERT1(context != NULL); |
- if (!context) |
- return E_POINTER; |
- |
- UninstallByPrefixParams* params = |
- reinterpret_cast<UninstallByPrefixParams*>(context); |
- |
- if (String_StartsWith(service_name, params->prefix, true) && |
- lstrcmpiW(service_name, params->unless_matches) != 0) { |
- // The service must be stopped before attempting to remove it from the |
- // database. Otherwise, the SCM database remains dirty and all service |
- // functions return ERROR_SERVICE_MARKED_FOR_DELETE until the system is |
- // restarted. |
- StopService(service_name); |
- |
- scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)); |
- if (!scm) { |
- HRESULT hr = HRESULTFromLastError(); |
- ASSERT1(false); |
- REPORT(false, R_ERROR, (L"Failed to open SCM: 0x%x", hr), 77223399); |
- return hr; |
- } |
- scoped_service service(::OpenService(get(scm), |
- service_name, |
- SERVICE_CHANGE_CONFIG | DELETE)); |
- if (service) { |
- // The service may not get deleted immediately; if there are handles to |
- // it open, it won't get deleted until the last one is closed. If the |
- // service is running, it won't get deleted immediately but rather will be |
- // marked for deletion (which happens on next reboot). Having to wait for |
- // a while and even until reboot doesn't matter much to us as our new |
- // service is installed under a new name and we are just cleaning up old |
- // ones. |
- if (!::DeleteService(get(service))) { |
- // We do not assert but just report so that we know if this happens |
- // abnormally often. |
- if (::GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE) { |
- REPORT(false, R_INFO, |
- (L"Failed to immediately delete service %s", service_name), |
- 5440098); |
- } else { |
- ASSERT(false, (L"Failed to delete service %s, error %d", |
- service_name, ::GetLastError())); |
- } |
- // DO NOT return an error here; we want to keep going through all the |
- // services. |
- } else { |
- SERVICE_LOG(L1, |
- (L"Deleted old service %s", service_name)); |
- } |
- } else { |
- // Per documentation of the EnumerateServicesCallback interface we can |
- // expect not to be able to open the service with one of the following two |
- // error codes, because of discrepancies between the registry and the SCM |
- // database in memory. |
- DWORD last_error = ::GetLastError(); |
- ASSERT(last_error == ERROR_SERVICE_DOES_NOT_EXIST || |
- last_error == ERROR_INVALID_NAME, |
- (L"Failed to open service %s, last error %d", service_name, |
- last_error)); |
- REPORT(last_error == ERROR_SERVICE_DOES_NOT_EXIST || |
- last_error == ERROR_INVALID_NAME, R_ERROR, |
- (L"Failed to open service %s, last error %d", service_name, |
- last_error), 5576234); |
- } |
- } |
- |
- return S_OK; |
-} |
- |
-CString ServiceInstall::GenerateServiceName(const TCHAR* service_prefix) { |
- FILETIME ft = {0}; |
- ::GetSystemTimeAsFileTime(&ft); |
- CString versioned_service_name; |
- versioned_service_name.Format(_T("%s%x%x"), |
- service_prefix, |
- ft.dwHighDateTime, |
- ft.dwLowDateTime); |
- |
- ASSERT1(!versioned_service_name.IsEmpty()); |
- return versioned_service_name; |
-} |
- |
-HRESULT ServiceInstall::UninstallServices(const TCHAR* service_prefix, |
- const TCHAR* exclude_service) { |
- SERVICE_LOG(L2, (L"ServiceInstall::UninstallServices")); |
- |
- UninstallByPrefixParams params = { |
- service_prefix, |
- exclude_service, |
- }; |
- |
- return ScmDatabase::EnumerateServices(UninstallByPrefix, ¶ms); |
-} |
- |
-bool ServiceInstall::CanInstallWithoutReboot() { |
- scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)); |
- if (!scm) { |
- ASSERT1(false); |
- REPORT(false, R_ERROR, (L"Failed to open SCM: %d", ::GetLastError()), |
- 77224449); |
- return false; // request reboot just in case |
- } |
- |
- scoped_service service(::OpenService(get(scm), |
- _T("gupdate"), |
- SERVICE_QUERY_CONFIG | |
- SERVICE_CHANGE_CONFIG)); |
- if (!service) { |
- DWORD last_error = ::GetLastError(); |
- if (last_error == ERROR_ACCESS_DENIED || |
- last_error == ERROR_INVALID_HANDLE) { |
- // unable to verify the service is fully deleted, so request reboot |
- ASSERT(false, (L"Expected access and correct handle")); |
- return false; |
- } else { |
- // service does not exist |
- return true; |
- } |
- } |
- |
- return !ScmDatabase::IsServiceMarkedDeleted(get(service)); |
-} |
- |
-HRESULT ServiceInstall::StopService(const CString& service_name) { |
- SERVICE_LOG(L1, (_T("[ServiceInstall::StopService]"))); |
- |
- scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)); |
- if (!scm) { |
- return HRESULTFromLastError(); |
- } |
- scoped_service service(::OpenService(get(scm), |
- service_name, |
- SERVICE_QUERY_STATUS | SERVICE_STOP)); |
- if (!service) { |
- return HRESULTFromLastError(); |
- } |
- |
- SERVICE_STATUS status = {0}; |
- if (::QueryServiceStatus(get(service), &status)) { |
- if (status.dwCurrentState != SERVICE_STOPPED && |
- status.dwCurrentState != SERVICE_STOP_PENDING) { |
- // Stop the service. |
- SetZero(status); |
- if (!::ControlService(get(service), SERVICE_CONTROL_STOP, &status)) { |
- return HRESULTFromLastError(); |
- } |
- } |
- } |
- |
- if (status.dwCurrentState != SERVICE_STOPPED) { |
- SERVICE_LOG(L1, (_T("[Service is stopping...]"))); |
- |
- const int kWaitForServiceToStopMs = 8000; |
- LowResTimer t(true); |
- |
- while (status.dwCurrentState != SERVICE_STOPPED && |
- t.GetMilliseconds() < kWaitForServiceToStopMs) { |
- const int kSleepTimeMs = 50; |
- ::Sleep(kSleepTimeMs); |
- SetZero(status); |
- VERIFY1(::QueryServiceStatus(get(service), &status)); |
- SERVICE_LOG(L1, (_T("[Waiting for service to stop][time elapsed: %d ms]"), |
- static_cast<int>(t.GetMilliseconds()))); |
- } |
- |
- if (status.dwCurrentState != SERVICE_STOPPED) { |
- SERVICE_LOG(LEVEL_WARNING, (_T("[Service did not stop! Not good...]"))); |
- return HRESULT_FROM_WIN32(ERROR_TIMEOUT); |
- } |
- } |
- |
- ASSERT1(status.dwCurrentState == SERVICE_STOPPED); |
- SERVICE_LOG(L1, (_T("[ServiceInstall::StopService - service stopped]"))); |
- return S_OK; |
-} |
- |
-bool ServiceInstall::IsServiceInstalled(const TCHAR* service_name) { |
- ASSERT1(service_name); |
- scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)); |
- if (!scm) { |
- return false; |
- } |
- scoped_service service(::OpenService(get(scm), |
- service_name, |
- SERVICE_QUERY_CONFIG)); |
- return valid(service); |
-} |
- |
-// TODO(Omaha): Move all functions under a common ServiceUtils namespace. |
-bool ServiceUtils::IsServiceRunning(const TCHAR* service_name) { |
- ASSERT1(service_name); |
- |
- scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)); |
- if (!scm) { |
- SERVICE_LOG(LE, (_T("[OpenSCManager fail][0x%x]"), HRESULTFromLastError())); |
- return false; |
- } |
- |
- scoped_service service(::OpenService(get(scm), |
- service_name, |
- SERVICE_QUERY_STATUS)); |
- if (!service) { |
- SERVICE_LOG(LE, (_T("[OpenService failed][%s][0x%x]"), |
- service_name, HRESULTFromLastError())); |
- return false; |
- } |
- |
- SERVICE_STATUS status = {0}; |
- if (!::QueryServiceStatus(get(service), &status)) { |
- SERVICE_LOG(LE, (_T("[QueryServiceStatus failed][%s][0x%x]"), |
- service_name, HRESULTFromLastError())); |
- return false; |
- } |
- |
- return status.dwCurrentState == SERVICE_RUNNING || |
- status.dwCurrentState == SERVICE_START_PENDING; |
-} |
- |
-bool ServiceUtils::IsServiceDisabled(const TCHAR* service_name) { |
- ASSERT1(service_name); |
- |
- scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)); |
- if (!scm) { |
- SERVICE_LOG(LE, (_T("[OpenSCManager fail][0x%x]"), HRESULTFromLastError())); |
- return false; |
- } |
- |
- scoped_service service(::OpenService(get(scm), |
- service_name, |
- SERVICE_QUERY_CONFIG)); |
- if (!service) { |
- SERVICE_LOG(LE, (_T("[OpenService failed][%s][0x%x]"), |
- service_name, HRESULTFromLastError())); |
- return false; |
- } |
- |
- return ScmDatabase::IsServiceStateEqual(get(service), SERVICE_DISABLED); |
-} |
- |
-} // namespace omaha |
- |