From e01455d41d72a9823fbe6c33f821bdf037c955d8 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Fri, 22 Oct 2010 10:35:49 +0200 Subject: [PATCH] services: Support setting and changing service dependencies. --- programs/services/rpc.c | 104 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 96 insertions(+), 8 deletions(-) diff --git a/programs/services/rpc.c b/programs/services/rpc.c index c647cc8286..41630be769 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -84,8 +84,11 @@ struct sc_lock struct scmdatabase *db; }; -static void free_config_strings(QUERY_SERVICE_CONFIGW *old_cfg, QUERY_SERVICE_CONFIGW *new_cfg) +static void free_service_strings(struct service_entry *old, struct service_entry *new) { + QUERY_SERVICE_CONFIGW *old_cfg = &old->config; + QUERY_SERVICE_CONFIGW *new_cfg = &new->config; + if (old_cfg->lpBinaryPathName != new_cfg->lpBinaryPathName) HeapFree(GetProcessHeap(), 0, old_cfg->lpBinaryPathName); @@ -97,6 +100,12 @@ static void free_config_strings(QUERY_SERVICE_CONFIGW *old_cfg, QUERY_SERVICE_CO if (old_cfg->lpDisplayName != new_cfg->lpDisplayName) HeapFree(GetProcessHeap(), 0, old_cfg->lpDisplayName); + + if (old->dependOnServices != new->dependOnServices) + HeapFree(GetProcessHeap(), 0, old->dependOnServices); + + if (old->dependOnGroups != new->dependOnGroups) + HeapFree(GetProcessHeap(), 0, old->dependOnGroups); } /* Check if the given handle is of the required type and allows the requested access. */ @@ -335,6 +344,78 @@ DWORD svcctl_OpenServiceW( return create_handle_for_service(entry, dwDesiredAccess, phService); } +static DWORD parse_dependencies(const WCHAR *dependencies, struct service_entry *entry) +{ + WCHAR *services = NULL, *groups, *s; + DWORD len, len_services = 0, len_groups = 0; + const WCHAR *ptr = dependencies; + + if (!dependencies || !dependencies[0]) + { + entry->dependOnServices = NULL; + entry->dependOnGroups = NULL; + return ERROR_SUCCESS; + } + + while (*ptr) + { + len = strlenW(ptr) + 1; + if (ptr[0] == '+' && ptr[1]) + len_groups += len - 1; + else + len_services += len; + ptr += len; + } + if (!len_services) entry->dependOnServices = NULL; + else + { + services = HeapAlloc(GetProcessHeap(), 0, (len_services + 1) * sizeof(WCHAR)); + if (!services) + return ERROR_OUTOFMEMORY; + + s = services; + ptr = dependencies; + while (*ptr) + { + len = strlenW(ptr) + 1; + if (*ptr != '+') + { + strcpyW(s, ptr); + s += len; + } + ptr += len; + } + *s = 0; + entry->dependOnServices = services; + } + if (!len_groups) entry->dependOnGroups = NULL; + else + { + groups = HeapAlloc(GetProcessHeap(), 0, (len_groups + 1) * sizeof(WCHAR)); + if (!groups) + { + HeapFree(GetProcessHeap(), 0, services); + return ERROR_OUTOFMEMORY; + } + s = groups; + ptr = dependencies; + while (*ptr) + { + len = strlenW(ptr) + 1; + if (ptr[0] == '+' && ptr[1]) + { + strcpyW(s, ptr + 1); + s += len - 1; + } + ptr += len; + } + *s = 0; + entry->dependOnGroups = groups; + } + + return ERROR_SUCCESS; +} + DWORD svcctl_CreateServiceW( SC_RPC_HANDLE hSCManager, LPCWSTR lpServiceName, @@ -369,12 +450,15 @@ DWORD svcctl_CreateServiceW( if (lpPassword) WINE_FIXME("Don't know how to add a password\n"); /* I always get ERROR_GEN_FAILURE */ - if (lpDependencies) - WINE_FIXME("Dependencies not supported yet\n"); err = service_create(lpServiceName, &entry); if (err != ERROR_SUCCESS) return err; + + err = parse_dependencies((LPCWSTR)lpDependencies, entry); + if (err != ERROR_SUCCESS) + return err; + entry->ref_count = 1; entry->config.dwServiceType = entry->status.dwServiceType = dwServiceType; entry->config.dwStartType = dwStartType; @@ -540,9 +624,6 @@ DWORD svcctl_ChangeServiceConfigW( if (lpdwTagId != NULL) WINE_FIXME("Changing tag id not supported\n"); - if (lpDependencies != NULL) - WINE_FIXME("Changing dependencies not supported\n"); - if (lpServiceStartName != NULL) new_entry.config.lpServiceStartName = (LPWSTR)lpServiceStartName; @@ -552,6 +633,13 @@ DWORD svcctl_ChangeServiceConfigW( if (lpDisplayName != NULL) new_entry.config.lpDisplayName = (LPWSTR)lpDisplayName; + err = parse_dependencies((LPCWSTR)lpDependencies, &new_entry); + if (err != ERROR_SUCCESS) + { + service_unlock(service->service_entry); + return err; + } + if (!validate_service_config(&new_entry)) { WINE_ERR("The configuration after the change wouldn't be valid\n"); @@ -576,10 +664,10 @@ DWORD svcctl_ChangeServiceConfigW( err = save_service_config(&new_entry); if (ERROR_SUCCESS == err) { - free_config_strings(&service->service_entry->config,&new_entry.config); + free_service_strings(service->service_entry, &new_entry); *service->service_entry = new_entry; } - else free_config_strings(&new_entry.config,&service->service_entry->config); + else free_service_strings(&new_entry, service->service_entry); service_unlock(service->service_entry); return err;