WINE_DEFAULT_DEBUG_CHANNEL(service);
-static CRITICAL_SECTION g_handle_table_cs;
-static CRITICAL_SECTION_DEBUG g_handle_table_cs_debug =
-{
- 0, 0, &g_handle_table_cs,
- { &g_handle_table_cs_debug.ProcessLocksList,
- &g_handle_table_cs_debug.ProcessLocksList },
- 0, 0, { (DWORD_PTR)(__FILE__ ": g_handle_table_cs") }
-};
-static CRITICAL_SECTION g_handle_table_cs = { &g_handle_table_cs_debug, -1, 0, 0, 0, 0 };
-
static const GENERIC_MAPPING g_scm_generic =
{
(STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
DWORD access;
};
-struct sc_manager /* service control manager handle */
+struct sc_manager_handle /* service control manager handle */
{
struct sc_handle hdr;
+ struct scmdatabase *db;
};
-struct sc_service /* service handle */
+struct sc_service_handle /* service handle */
{
struct sc_handle hdr;
struct service_entry *service_entry;
struct sc_lock
{
- char dummy; /* no state currently used */
+ struct scmdatabase *db;
};
/* Check if the given handle is of the required type and allows the requested access. */
return ERROR_SUCCESS;
}
-static DWORD validate_scm_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_manager **manager)
+static DWORD validate_scm_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_manager_handle **manager)
{
struct sc_handle *hdr;
DWORD err = validate_context_handle(handle, SC_HTYPE_MANAGER, needed_access, &hdr);
if (err == ERROR_SUCCESS)
- *manager = (struct sc_manager *)hdr;
+ *manager = (struct sc_manager_handle *)hdr;
return err;
}
-static DWORD validate_service_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_service **service)
+static DWORD validate_service_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_service_handle **service)
{
struct sc_handle *hdr;
DWORD err = validate_context_handle(handle, SC_HTYPE_SERVICE, needed_access, &hdr);
if (err == ERROR_SUCCESS)
- *service = (struct sc_service *)hdr;
+ *service = (struct sc_service_handle *)hdr;
return err;
}
DWORD dwAccessMask,
SC_RPC_HANDLE *handle)
{
- struct sc_manager *manager;
+ struct sc_manager_handle *manager;
WINE_TRACE("(%s, %s, %x)\n", wine_dbgstr_w(MachineName), wine_dbgstr_w(DatabaseName), dwAccessMask);
dwAccessMask |= SC_MANAGER_ALL_ACCESS;
manager->hdr.access = dwAccessMask;
RtlMapGenericMask(&manager->hdr.access, &g_scm_generic);
+ manager->db = active_database;
*handle = &manager->hdr;
return ERROR_SUCCESS;
{
case SC_HTYPE_MANAGER:
{
- struct sc_manager *manager = (struct sc_manager *)hdr;
+ struct sc_manager_handle *manager = (struct sc_manager_handle *)hdr;
HeapFree(GetProcessHeap(), 0, manager);
break;
}
case SC_HTYPE_SERVICE:
{
- struct sc_service *service = (struct sc_service *)hdr;
+ struct sc_service_handle *service = (struct sc_service_handle *)hdr;
release_service(service->service_entry);
HeapFree(GetProcessHeap(), 0, service);
break;
DWORD cchBufSize,
DWORD *cchLength)
{
- struct sc_manager *manager;
+ struct sc_manager_handle *manager;
struct service_entry *entry;
DWORD err;
if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
return err;
- lock_services();
+ scmdatabase_lock_shared(manager->db);
- entry = find_service(lpServiceName);
+ entry = scmdatabase_find_service(manager->db, lpServiceName);
if (entry != NULL)
{
- LPCWSTR name = get_display_name(entry);
+ LPCWSTR name;
+ service_lock_shared(entry);
+ name = get_display_name(entry);
*cchLength = strlenW(name);
if (*cchLength < cchBufSize)
{
}
else
err = ERROR_INSUFFICIENT_BUFFER;
+ service_unlock(entry);
}
else
{
err = ERROR_SERVICE_DOES_NOT_EXIST;
}
+ scmdatabase_unlock(manager->db);
+
if (err != ERROR_SUCCESS && cchBufSize > 0)
lpBuffer[0] = 0;
- unlock_services();
return err;
}
DWORD *cchLength)
{
struct service_entry *entry;
- struct sc_manager *manager;
+ struct sc_manager_handle *manager;
DWORD err;
WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceDisplayName), cchBufSize);
if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
return err;
- lock_services();
+ scmdatabase_lock_shared(manager->db);
- entry = find_service_by_displayname(lpServiceDisplayName);
+ entry = scmdatabase_find_service_by_displayname(manager->db, lpServiceDisplayName);
if (entry != NULL)
{
+ service_lock_shared(entry);
*cchLength = strlenW(entry->name);
if (*cchLength < cchBufSize)
{
}
else
err = ERROR_INSUFFICIENT_BUFFER;
+ service_unlock(entry);
}
else
{
err = ERROR_SERVICE_DOES_NOT_EXIST;
}
+ scmdatabase_unlock(manager->db);
+
if (err != ERROR_SUCCESS && cchBufSize > 0)
lpBuffer[0] = 0;
- unlock_services();
return err;
}
static DWORD create_handle_for_service(struct service_entry *entry, DWORD dwDesiredAccess, SC_RPC_HANDLE *phService)
{
- struct sc_service *service;
+ struct sc_service_handle *service;
if (!(service = HeapAlloc(GetProcessHeap(), 0, sizeof(*service))))
{
DWORD dwDesiredAccess,
SC_RPC_HANDLE *phService)
{
- struct sc_manager *manager;
+ struct sc_manager_handle *manager;
struct service_entry *entry;
DWORD err;
if (!validate_service_name(lpServiceName))
return ERROR_INVALID_NAME;
- lock_services();
- entry = find_service(lpServiceName);
+ scmdatabase_lock_shared(manager->db);
+ entry = scmdatabase_find_service(manager->db, lpServiceName);
if (entry != NULL)
entry->ref_count++;
- unlock_services();
+ scmdatabase_unlock(manager->db);
if (entry == NULL)
return ERROR_SERVICE_DOES_NOT_EXIST;
DWORD dwPasswordSize,
SC_RPC_HANDLE *phService)
{
- struct sc_manager *manager;
+ struct sc_manager_handle *manager;
struct service_entry *entry;
DWORD err;
if (lpDependencies)
WINE_FIXME("Dependencies not supported yet\n");
- entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*entry));
- entry->name = strdupW(lpServiceName);
+ err = service_create(lpServiceName, &entry);
+ if (err != ERROR_SUCCESS)
+ return err;
entry->config.dwServiceType = dwServiceType;
entry->config.dwStartType = dwStartType;
entry->config.dwErrorControl = dwErrorControl;
entry->config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup);
entry->config.lpServiceStartName = strdupW(lpServiceStartName);
entry->config.lpDisplayName = strdupW(lpDisplayName);
- entry->control_pipe = INVALID_HANDLE_VALUE;
if (lpdwTagId) /* TODO: in most situations a non-NULL tagid will generate a ERROR_INVALID_PARAMETER */
entry->config.dwTagId = *lpdwTagId;
return ERROR_INVALID_PARAMETER;
}
- lock_services();
+ scmdatabase_lock_exclusive(manager->db);
- if (find_service(lpServiceName))
+ if (scmdatabase_find_service(manager->db, lpServiceName))
{
- unlock_services();
+ scmdatabase_unlock(manager->db);
free_service_entry(entry);
return ERROR_SERVICE_EXISTS;
}
- if (find_service_by_displayname(get_display_name(entry)))
+ if (scmdatabase_find_service_by_displayname(manager->db, get_display_name(entry)))
{
- unlock_services();
+ scmdatabase_unlock(manager->db);
free_service_entry(entry);
return ERROR_DUPLICATE_SERVICE_NAME;
}
- err = add_service(entry);
+ err = scmdatabase_add_service(manager->db, entry);
if (err != ERROR_SUCCESS)
{
- unlock_services();
+ scmdatabase_unlock(manager->db);
free_service_entry(entry);
return err;
}
- unlock_services();
+ scmdatabase_unlock(manager->db);
return create_handle_for_service(entry, dwDesiredAccess, phService);
}
DWORD svcctl_DeleteService(
SC_RPC_HANDLE hService)
{
- struct sc_service *service;
+ struct sc_service_handle *service;
DWORD err;
if ((err = validate_service_handle(hService, DELETE, &service)) != ERROR_SUCCESS)
return err;
- lock_services();
+ scmdatabase_lock_exclusive(service->service_entry->db);
+ service_lock_exclusive(service->service_entry);
if (!is_marked_for_delete(service->service_entry))
- err = remove_service(service->service_entry);
+ err = scmdatabase_remove_service(service->service_entry->db, service->service_entry);
else
err = ERROR_SERVICE_MARKED_FOR_DELETE;
- unlock_services();
+ service_unlock(service->service_entry);
+ scmdatabase_unlock(service->service_entry->db);
return err;
}
SC_RPC_HANDLE hService,
QUERY_SERVICE_CONFIGW *config)
{
- struct sc_service *service;
+ struct sc_service_handle *service;
DWORD err;
WINE_TRACE("(%p)\n", config);
if ((err = validate_service_handle(hService, SERVICE_QUERY_CONFIG, &service)) != 0)
return err;
- lock_services();
+ service_lock_shared(service->service_entry);
config->dwServiceType = service->service_entry->config.dwServiceType;
config->dwStartType = service->service_entry->config.dwStartType;
config->dwErrorControl = service->service_entry->config.dwErrorControl;
config->lpDependencies = NULL; /* TODO */
config->lpServiceStartName = strdupW(service->service_entry->config.lpServiceStartName);
config->lpDisplayName = strdupW(service->service_entry->config.lpDisplayName);
- unlock_services();
+ service_unlock(service->service_entry);
return ERROR_SUCCESS;
}
LPCWSTR lpDisplayName)
{
struct service_entry new_entry;
- struct sc_service *service;
+ struct sc_service_handle *service;
DWORD err;
WINE_TRACE("\n");
return ERROR_INVALID_PARAMETER;
/* first check if the new configuration is correct */
- lock_services();
+ service_lock_exclusive(service->service_entry);
if (is_marked_for_delete(service->service_entry))
{
- unlock_services();
+ service_unlock(service->service_entry);
return ERROR_SERVICE_MARKED_FOR_DELETE;
}
- if (lpDisplayName != NULL && find_service_by_displayname(lpDisplayName))
+ if (lpDisplayName != NULL &&
+ scmdatabase_find_service_by_displayname(service->service_entry->db, lpDisplayName))
{
- unlock_services();
+ service_unlock(service->service_entry);
return ERROR_DUPLICATE_SERVICE_NAME;
}
if (!validate_service_config(&new_entry))
{
WINE_ERR("The configuration after the change wouldn't be valid");
- unlock_services();
+ service_unlock(service->service_entry);
return ERROR_INVALID_PARAMETER;
}
*service->service_entry = new_entry;
save_service_config(service->service_entry);
- unlock_services();
+ service_unlock(service->service_entry);
return ERROR_SUCCESS;
}
SC_RPC_HANDLE hServiceStatus,
LPSERVICE_STATUS lpServiceStatus)
{
- struct sc_service *service;
+ struct sc_service_handle *service;
DWORD err;
WINE_TRACE("(%p, %p)\n", hServiceStatus, lpServiceStatus);
if ((err = validate_service_handle(hServiceStatus, SERVICE_SET_STATUS, &service)) != 0)
return err;
- lock_services();
+ service_lock_exclusive(service->service_entry);
/* FIXME: be a bit more discriminant about what parts of the status we set
* and check that fields are valid */
service->service_entry->status.dwServiceType = lpServiceStatus->dwServiceType;
service->service_entry->status.dwServiceSpecificExitCode = lpServiceStatus->dwServiceSpecificExitCode;
service->service_entry->status.dwCheckPoint = lpServiceStatus->dwCheckPoint;
service->service_entry->status.dwWaitHint = lpServiceStatus->dwWaitHint;
- unlock_services();
+ service_unlock(service->service_entry);
if (service->service_entry->status_changed_event)
SetEvent(service->service_entry->status_changed_event);
DWORD cbBufSize,
LPDWORD pcbBytesNeeded)
{
- struct sc_service *service;
+ struct sc_service_handle *service;
DWORD err;
LPSERVICE_STATUS_PROCESS pSvcStatusData;
return ERROR_INSUFFICIENT_BUFFER;
}
- lock_services();
+ service_lock_shared(service->service_entry);
pSvcStatusData->dwServiceType = service->service_entry->status.dwServiceType;
pSvcStatusData->dwCurrentState = service->service_entry->status.dwCurrentState;
pSvcStatusData->dwProcessId = service->service_entry->status.dwProcessId;
pSvcStatusData->dwServiceFlags = service->service_entry->status.dwServiceFlags;
- unlock_services();
+ service_unlock(service->service_entry);
return ERROR_SUCCESS;
}
DWORD size;
BOOL r;
- lock_services();
+ service_lock_exclusive(service_entry);
if (service_entry->config.dwServiceType == SERVICE_KERNEL_DRIVER)
{
si.lpDesktop = desktopW;
}
- unlock_services();
+ service_entry->status.dwCurrentState = SERVICE_START_PENDING;
+ service_entry->status.dwProcessId = pi.dwProcessId;
+
+ service_unlock(service_entry);
r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
HeapFree(GetProcessHeap(),0,path);
if (!r)
+ {
+ service_lock_exclusive(service_entry);
+ service_entry->status.dwCurrentState = SERVICE_STOPPED;
+ service_entry->status.dwProcessId = 0;
+ service_unlock(service_entry);
return GetLastError();
-
- lock_services();
- service_entry->status.dwCurrentState = SERVICE_START_PENDING;
- service_entry->status.dwProcessId = pi.dwProcessId;
- unlock_services();
+ }
*process = pi.hProcess;
CloseHandle( pi.hThread );
ret = WaitForMultipleObjects(sizeof(handles)/sizeof(handles[0]), handles, FALSE, 20000);
if (ret != WAIT_OBJECT_0)
return ERROR_SERVICE_REQUEST_TIMEOUT;
- lock_services();
+ service_lock_shared(service_entry);
dwCurrentStatus = service_entry->status.dwCurrentState;
- unlock_services();
+ service_unlock(service_entry);
if (dwCurrentStatus == SERVICE_RUNNING)
{
WINE_TRACE("Service started successfully\n");
DWORD dwNumServiceArgs,
LPCWSTR *lpServiceArgVectors)
{
- struct sc_service *service;
+ struct sc_service_handle *service;
DWORD err;
LPWSTR name;
HANDLE process_handle = NULL;
if ((err = validate_service_handle(hService, SERVICE_START, &service)) != 0)
return err;
- err = lock_service_database();
+ err = scmdatabase_lock_startup(service->service_entry->db);
if (err != ERROR_SUCCESS)
return err;
if (service->service_entry->control_pipe != INVALID_HANDLE_VALUE)
{
- unlock_service_database();
+ scmdatabase_unlock_startup(service->service_entry->db);
return ERROR_SERVICE_ALREADY_RUNNING;
}
{
WINE_ERR("failed to create pipe for %s, error = %d\n",
wine_dbgstr_w(service->service_entry->name), GetLastError());
- unlock_service_database();
+ scmdatabase_unlock_startup(service->service_entry->db);
return GetLastError();
}
CloseHandle(process_handle);
ReleaseMutex(service->service_entry->control_mutex);
- unlock_service_database();
+ scmdatabase_unlock_startup(service->service_entry->db);
return err;
}
SERVICE_STATUS *lpServiceStatus)
{
DWORD access_required;
- struct sc_service *service;
+ struct sc_service_handle *service;
DWORD err;
BOOL ret;
HANDLE control_mutex;
if ((err = validate_service_handle(hService, access_required, &service)) != 0)
return err;
- lock_services();
+ service_lock_exclusive(service->service_entry);
if (lpServiceStatus)
{
if (!service_accepts_control(service->service_entry, dwControl))
{
- unlock_services();
+ service_unlock(service->service_entry);
return ERROR_INVALID_SERVICE_CONTROL;
}
switch (service->service_entry->status.dwCurrentState)
{
case SERVICE_STOPPED:
- unlock_services();
+ service_unlock(service->service_entry);
return ERROR_SERVICE_NOT_ACTIVE;
case SERVICE_START_PENDING:
if (dwControl==SERVICE_CONTROL_STOP)
break;
/* fall thru */
case SERVICE_STOP_PENDING:
- unlock_services();
+ service_unlock(service->service_entry);
return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
}
service->service_entry->control_pipe = NULL;
}
- unlock_services();
+ service_unlock(service->service_entry);
ret = WaitForSingleObject(control_mutex, 30000);
if (ret)
static void SC_RPC_LOCK_destroy(SC_RPC_LOCK hLock)
{
- unlock_service_database();
- HeapFree(GetProcessHeap(), 0, hLock);
+ struct sc_lock *lock = hLock;
+ scmdatabase_unlock_startup(lock->db);
+ HeapFree(GetProcessHeap(), 0, lock);
}
void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK hLock)
SC_RPC_HANDLE hSCManager,
SC_RPC_LOCK *phLock)
{
- struct sc_manager *manager;
+ struct sc_manager_handle *manager;
DWORD err;
WINE_TRACE("(%p, %p)\n", hSCManager, phLock);
if ((err = validate_scm_handle(hSCManager, SC_MANAGER_LOCK, &manager)) != ERROR_SUCCESS)
return err;
- err = lock_service_database();
+ err = scmdatabase_lock_startup(manager->db);
if (err != ERROR_SUCCESS)
return err;
*phLock = HeapAlloc(GetProcessHeap(), 0, sizeof(struct sc_lock));
if (!*phLock)
+ {
+ scmdatabase_unlock_startup(manager->db);
return ERROR_NOT_ENOUGH_SERVER_MEMORY;
+ }
return ERROR_SUCCESS;
}
WINE_DEFAULT_DEBUG_CHANNEL(service);
HANDLE g_hStartedEvent;
-
-static struct list g_services;
-
-static CRITICAL_SECTION services_list_cs;
-static CRITICAL_SECTION_DEBUG services_list_cs_debug =
-{
- 0, 0, &services_list_cs,
- { &services_list_cs_debug.ProcessLocksList,
- &services_list_cs_debug.ProcessLocksList },
- 0, 0, { (DWORD_PTR)(__FILE__ ": services_list_cs") }
-};
-static CRITICAL_SECTION services_list_cs = { &services_list_cs_debug, -1, 0, 0, 0, 0 };
+struct scmdatabase *active_database;
static const WCHAR SZ_LOCAL_SYSTEM[] = {'L','o','c','a','l','S','y','s','t','e','m',0};
static const WCHAR SZ_DESCRIPTION[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
+DWORD service_create(LPCWSTR name, struct service_entry **entry)
+{
+ *entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(**entry));
+ if (!*entry)
+ return ERROR_NOT_ENOUGH_SERVER_MEMORY;
+ (*entry)->name = strdupW(name);
+ if (!(*entry)->name)
+ {
+ HeapFree(GetProcessHeap(), 0, *entry);
+ return ERROR_NOT_ENOUGH_SERVER_MEMORY;
+ }
+ (*entry)->control_pipe = INVALID_HANDLE_VALUE;
+ return ERROR_SUCCESS;
+}
+
void free_service_entry(struct service_entry *entry)
{
HeapFree(GetProcessHeap(), 0, entry->name);
DWORD save_service_config(struct service_entry *entry)
{
- HKEY hServicesRootKey;
DWORD err;
HKEY hKey = NULL;
- if ((err = RegCreateKeyW(HKEY_LOCAL_MACHINE, SZ_SERVICES_KEY, &hServicesRootKey)) != 0)
- goto cleanup;
-
- err = RegCreateKeyW(hServicesRootKey, entry->name, &hKey);
- RegCloseKey(hServicesRootKey);
+ err = RegCreateKeyW(entry->db->root_key, entry->name, &hKey);
if (err != ERROR_SUCCESS)
goto cleanup;
return err;
}
-DWORD add_service(struct service_entry *service)
+DWORD scmdatabase_add_service(struct scmdatabase *db, struct service_entry *service)
{
int err;
+ service->db = db;
if ((err = save_service_config(service)) != ERROR_SUCCESS)
{
WINE_ERR("Couldn't store service configuration: error %u\n", err);
return ERROR_GEN_FAILURE;
}
- list_add_tail(&g_services, &service->entry);
+ list_add_tail(&db->services, &service->entry);
return ERROR_SUCCESS;
}
-DWORD remove_service(struct service_entry *service)
+DWORD scmdatabase_remove_service(struct scmdatabase *db, struct service_entry *service)
{
int err;
- HKEY hKey;
- if ((err = RegOpenKeyW(HKEY_LOCAL_MACHINE, SZ_SERVICES_KEY, &hKey)) != 0)
- return err;
-
- err = RegDeleteTreeW(hKey, service->name);
- RegCloseKey(hKey);
+ err = RegDeleteTreeW(db->root_key, service->name);
if (err != 0)
return err;
return TRUE;
}
-static LONG service_lock = FALSE;
-
-DWORD lock_service_database(void)
-{
- if (InterlockedCompareExchange(&service_lock, TRUE, FALSE))
- return ERROR_SERVICE_DATABASE_LOCKED;
- return ERROR_SUCCESS;
-}
-void unlock_service_database(void)
-{
- InterlockedCompareExchange(&service_lock, FALSE, TRUE);
-}
-
-void lock_services(void)
-{
- EnterCriticalSection(&services_list_cs);
-}
-
-void unlock_services(void)
-{
- LeaveCriticalSection(&services_list_cs);
-}
-
-struct service_entry *find_service(LPCWSTR name)
+struct service_entry *scmdatabase_find_service(struct scmdatabase *db, LPCWSTR name)
{
struct service_entry *service;
- LIST_FOR_EACH_ENTRY(service, &g_services, struct service_entry, entry)
+ LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry)
{
if (strcmpiW(name, service->name) == 0)
return service;
return NULL;
}
-struct service_entry *find_service_by_displayname(LPCWSTR name)
+struct service_entry *scmdatabase_find_service_by_displayname(struct scmdatabase *db, LPCWSTR name)
{
struct service_entry *service;
- LIST_FOR_EACH_ENTRY(service, &g_services, struct service_entry, entry)
+ LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry)
{
if (strcmpiW(name, service->config.lpDisplayName) == 0)
return service;
free_service_entry(service);
}
-static DWORD load_services(void)
+static DWORD scmdatabase_create(struct scmdatabase **db)
{
- HKEY hServicesRootKey;
DWORD err;
- int i;
- if ((err = RegCreateKeyExW(HKEY_LOCAL_MACHINE, SZ_SERVICES_KEY, 0, NULL,
- REG_OPTION_NON_VOLATILE, KEY_READ, NULL,
- &hServicesRootKey, NULL)) != ERROR_SUCCESS)
- {
- WINE_ERR("Couldn't open services key\n");
- return err;
- }
+ *db = HeapAlloc(GetProcessHeap(), 0, sizeof(**db));
+ if (!*db)
+ return ERROR_NOT_ENOUGH_SERVER_MEMORY;
+
+ (*db)->service_start_lock = FALSE;
+ list_init(&(*db)->services);
+
+ InitializeCriticalSection(&(*db)->cs);
+
+ err = RegCreateKeyExW(HKEY_LOCAL_MACHINE, SZ_SERVICES_KEY, 0, NULL,
+ REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
+ &(*db)->root_key, NULL);
+ if (err != ERROR_SUCCESS)
+ HeapFree(GetProcessHeap(), 0, *db);
+
+ return err;
+}
+
+static void scmdatabase_destroy(struct scmdatabase *db)
+{
+ RegCloseKey(db->root_key);
+ DeleteCriticalSection(&db->cs);
+ HeapFree(GetProcessHeap(), 0, db);
+}
+
+static DWORD scmdatabase_load_services(struct scmdatabase *db)
+{
+ DWORD err;
+ int i;
for (i = 0; TRUE; i++)
{
struct service_entry *entry;
HKEY hServiceKey;
- err = RegEnumKeyW(hServicesRootKey, i, szName, MAX_SERVICE_NAME);
+ err = RegEnumKeyW(db->root_key, i, szName, MAX_SERVICE_NAME);
if (err == ERROR_NO_MORE_ITEMS)
break;
continue;
}
- entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*entry));
- entry->name = strdupW(szName);
- entry->control_pipe = INVALID_HANDLE_VALUE;
+ err = service_create(szName, &entry);
+ if (err != ERROR_SUCCESS)
+ break;
WINE_TRACE("Loading service %s\n", wine_dbgstr_w(szName));
- err = RegOpenKeyExW(hServicesRootKey, szName, 0, KEY_READ | KEY_WRITE, &hServiceKey);
+ err = RegOpenKeyExW(db->root_key, szName, 0, KEY_READ | KEY_WRITE, &hServiceKey);
if (err == ERROR_SUCCESS)
{
err = load_service_config(hServiceKey, entry);
entry->status.dwServiceType = entry->config.dwServiceType;
entry->status.dwCurrentState = SERVICE_STOPPED;
entry->status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
+ entry->db = db;
/* all other fields are zero */
- list_add_tail(&g_services, &entry->entry);
+ list_add_tail(&db->services, &entry->entry);
}
- RegCloseKey(hServicesRootKey);
return ERROR_SUCCESS;
}
+DWORD scmdatabase_lock_startup(struct scmdatabase *db)
+{
+ if (InterlockedCompareExchange(&db->service_start_lock, TRUE, FALSE))
+ return ERROR_SERVICE_DATABASE_LOCKED;
+ return ERROR_SUCCESS;
+}
+
+void scmdatabase_unlock_startup(struct scmdatabase *db)
+{
+ InterlockedCompareExchange(&db->service_start_lock, FALSE, TRUE);
+}
+
+void scmdatabase_lock_shared(struct scmdatabase *db)
+{
+ EnterCriticalSection(&db->cs);
+}
+
+void scmdatabase_lock_exclusive(struct scmdatabase *db)
+{
+ EnterCriticalSection(&db->cs);
+}
+
+void scmdatabase_unlock(struct scmdatabase *db)
+{
+ LeaveCriticalSection(&db->cs);
+}
+
+void service_lock_shared(struct service_entry *service)
+{
+ EnterCriticalSection(&service->db->cs);
+}
+
+void service_lock_exclusive(struct service_entry *service)
+{
+ EnterCriticalSection(&service->db->cs);
+}
+
+void service_unlock(struct service_entry *service)
+{
+ LeaveCriticalSection(&service->db->cs);
+}
+
int main(int argc, char *argv[])
{
static const WCHAR svcctl_started_event[] = SVCCTL_STARTED_EVENT;
DWORD err;
g_hStartedEvent = CreateEventW(NULL, TRUE, FALSE, svcctl_started_event);
- list_init(&g_services);
- if ((err = load_services()) != ERROR_SUCCESS)
+ err = scmdatabase_create(&active_database);
+ if (err != ERROR_SUCCESS)
return err;
- return RPC_MainLoop();
+ if ((err = scmdatabase_load_services(active_database)) != ERROR_SUCCESS)
+ return err;
+ err = RPC_MainLoop();
+ scmdatabase_destroy(active_database);
+ return err;
}