~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/programs/services/services.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  1 /*
  2  * Services - controls services keeps track of their state
  3  *
  4  * Copyright 2007 Google (Mikolaj Zalewski)
  5  *
  6  * This library is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU Lesser General Public
  8  * License as published by the Free Software Foundation; either
  9  * version 2.1 of the License, or (at your option) any later version.
 10  *
 11  * This library is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14  * Lesser General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU Lesser General Public
 17  * License along with this library; if not, write to the Free Software
 18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 19  */
 20 
 21 #define WIN32_LEAN_AND_MEAN
 22 
 23 #include <stdarg.h>
 24 #include <windows.h>
 25 #include <winsvc.h>
 26 #include <rpc.h>
 27 
 28 #include "wine/unicode.h"
 29 #include "wine/debug.h"
 30 #include "svcctl.h"
 31 
 32 #include "services.h"
 33 
 34 #define MAX_SERVICE_NAME 260
 35 
 36 WINE_DEFAULT_DEBUG_CHANNEL(service);
 37 
 38 HANDLE g_hStartedEvent;
 39 struct scmdatabase *active_database;
 40 
 41 static const WCHAR SZ_LOCAL_SYSTEM[] = {'L','o','c','a','l','S','y','s','t','e','m',0};
 42 
 43 /* Registry constants */
 44 static const WCHAR SZ_SERVICES_KEY[] = { 'S','y','s','t','e','m','\\',
 45       'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
 46       'S','e','r','v','i','c','e','s',0 };
 47 
 48 /* Service key values names */
 49 static const WCHAR SZ_DISPLAY_NAME[]      = {'D','i','s','p','l','a','y','N','a','m','e',0 };
 50 static const WCHAR SZ_TYPE[]              = {'T','y','p','e',0 };
 51 static const WCHAR SZ_START[]             = {'S','t','a','r','t',0 };
 52 static const WCHAR SZ_ERROR[]             = {'E','r','r','o','r','C','o','n','t','r','o','l',0 };
 53 static const WCHAR SZ_IMAGE_PATH[]        = {'I','m','a','g','e','P','a','t','h',0};
 54 static const WCHAR SZ_GROUP[]             = {'G','r','o','u','p',0};
 55 static const WCHAR SZ_DEPEND_ON_SERVICE[] = {'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
 56 static const WCHAR SZ_DEPEND_ON_GROUP[]   = {'D','e','p','e','n','d','O','n','G','r','o','u','p',0};
 57 static const WCHAR SZ_OBJECT_NAME[]       = {'O','b','j','e','c','t','N','a','m','e',0};
 58 static const WCHAR SZ_TAG[]               = {'T','a','g',0};
 59 static const WCHAR SZ_DESCRIPTION[]       = {'D','e','s','c','r','i','p','t','i','o','n',0};
 60 
 61 
 62 DWORD service_create(LPCWSTR name, struct service_entry **entry)
 63 {
 64     *entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(**entry));
 65     if (!*entry)
 66         return ERROR_NOT_ENOUGH_SERVER_MEMORY;
 67     (*entry)->name = strdupW(name);
 68     if (!(*entry)->name)
 69     {
 70         HeapFree(GetProcessHeap(), 0, *entry);
 71         return ERROR_NOT_ENOUGH_SERVER_MEMORY;
 72     }
 73     (*entry)->control_pipe = INVALID_HANDLE_VALUE;
 74     (*entry)->status.dwCurrentState = SERVICE_STOPPED;
 75     (*entry)->status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
 76     /* all other fields are zero */
 77     return ERROR_SUCCESS;
 78 }
 79 
 80 void free_service_entry(struct service_entry *entry)
 81 {
 82     HeapFree(GetProcessHeap(), 0, entry->name);
 83     HeapFree(GetProcessHeap(), 0, entry->config.lpBinaryPathName);
 84     HeapFree(GetProcessHeap(), 0, entry->config.lpDependencies);
 85     HeapFree(GetProcessHeap(), 0, entry->config.lpLoadOrderGroup);
 86     HeapFree(GetProcessHeap(), 0, entry->config.lpServiceStartName);
 87     HeapFree(GetProcessHeap(), 0, entry->config.lpDisplayName);
 88     HeapFree(GetProcessHeap(), 0, entry->description);
 89     HeapFree(GetProcessHeap(), 0, entry->dependOnServices);
 90     HeapFree(GetProcessHeap(), 0, entry->dependOnGroups);
 91     CloseHandle(entry->control_mutex);
 92     CloseHandle(entry->control_pipe);
 93     CloseHandle(entry->status_changed_event);
 94     HeapFree(GetProcessHeap(), 0, entry);
 95 }
 96 
 97 static DWORD load_service_config(HKEY hKey, struct service_entry *entry)
 98 {
 99     DWORD err;
100     WCHAR *wptr;
101 
102     if ((err = load_reg_string(hKey, SZ_IMAGE_PATH,   TRUE, &entry->config.lpBinaryPathName)) != 0)
103         return err;
104     if ((err = load_reg_string(hKey, SZ_GROUP,        0,    &entry->config.lpLoadOrderGroup)) != 0)
105         return err;
106     if ((err = load_reg_string(hKey, SZ_OBJECT_NAME,  TRUE, &entry->config.lpServiceStartName)) != 0)
107         return err;
108     if ((err = load_reg_string(hKey, SZ_DISPLAY_NAME, 0,    &entry->config.lpDisplayName)) != 0)
109         return err;
110     if ((err = load_reg_string(hKey, SZ_DESCRIPTION,  0,    &entry->description)) != 0)
111         return err;
112     if ((err = load_reg_multisz(hKey, SZ_DEPEND_ON_SERVICE, TRUE, &entry->dependOnServices)) != 0)
113         return err;
114     if ((err = load_reg_multisz(hKey, SZ_DEPEND_ON_GROUP, FALSE, &entry->dependOnGroups)) != 0)
115         return err;
116 
117     if ((err = load_reg_dword(hKey, SZ_TYPE,  &entry->config.dwServiceType)) != 0)
118         return err;
119     if ((err = load_reg_dword(hKey, SZ_START, &entry->config.dwStartType)) != 0)
120         return err;
121     if ((err = load_reg_dword(hKey, SZ_ERROR, &entry->config.dwErrorControl)) != 0)
122         return err;
123     if ((err = load_reg_dword(hKey, SZ_TAG,   &entry->config.dwTagId)) != 0)
124         return err;
125 
126     WINE_TRACE("Image path           = %s\n", wine_dbgstr_w(entry->config.lpBinaryPathName) );
127     WINE_TRACE("Group                = %s\n", wine_dbgstr_w(entry->config.lpLoadOrderGroup) );
128     WINE_TRACE("Service account name = %s\n", wine_dbgstr_w(entry->config.lpServiceStartName) );
129     WINE_TRACE("Display name         = %s\n", wine_dbgstr_w(entry->config.lpDisplayName) );
130     WINE_TRACE("Service dependencies : %s\n", entry->dependOnServices[0] ? "" : "(none)");
131     for (wptr = entry->dependOnServices; *wptr; wptr += strlenW(wptr) + 1)
132         WINE_TRACE("    * %s\n", wine_dbgstr_w(wptr));
133     WINE_TRACE("Group dependencies   : %s\n", entry->dependOnGroups[0] ? "" : "(none)");
134     for (wptr = entry->dependOnGroups; *wptr; wptr += strlenW(wptr) + 1)
135         WINE_TRACE("    * %s\n", wine_dbgstr_w(wptr));
136 
137     return ERROR_SUCCESS;
138 }
139 
140 static DWORD reg_set_string_value(HKEY hKey, LPCWSTR value_name, LPCWSTR string)
141 {
142     if (!string)
143     {
144         DWORD err;
145         err = RegDeleteValueW(hKey, value_name);
146         if (err != ERROR_FILE_NOT_FOUND)
147             return err;
148 
149         return ERROR_SUCCESS;
150     }
151 
152     return RegSetValueExW(hKey, value_name, 0, REG_SZ, (LPBYTE)string, sizeof(WCHAR)*(strlenW(string) + 1));
153 }
154 
155 DWORD save_service_config(struct service_entry *entry)
156 {
157     DWORD err;
158     HKEY hKey = NULL;
159 
160     err = RegCreateKeyW(entry->db->root_key, entry->name, &hKey);
161     if (err != ERROR_SUCCESS)
162         goto cleanup;
163 
164     if ((err = reg_set_string_value(hKey, SZ_DISPLAY_NAME, entry->config.lpDisplayName)) != 0)
165         goto cleanup;
166     if ((err = reg_set_string_value(hKey, SZ_IMAGE_PATH, entry->config.lpBinaryPathName)) != 0)
167         goto cleanup;
168     if ((err = reg_set_string_value(hKey, SZ_GROUP, entry->config.lpLoadOrderGroup)) != 0)
169         goto cleanup;
170     if ((err = reg_set_string_value(hKey, SZ_OBJECT_NAME, entry->config.lpServiceStartName)) != 0)
171         goto cleanup;
172     if ((err = reg_set_string_value(hKey, SZ_DESCRIPTION, entry->description)) != 0)
173         goto cleanup;
174     if ((err = RegSetValueExW(hKey, SZ_START, 0, REG_DWORD, (LPBYTE)&entry->config.dwStartType, sizeof(DWORD))) != 0)
175         goto cleanup;
176     if ((err = RegSetValueExW(hKey, SZ_ERROR, 0, REG_DWORD, (LPBYTE)&entry->config.dwErrorControl, sizeof(DWORD))) != 0)
177         goto cleanup;
178 
179     if ((err = RegSetValueExW(hKey, SZ_TYPE, 0, REG_DWORD, (LPBYTE)&entry->config.dwServiceType, sizeof(DWORD))) != 0)
180         goto cleanup;
181 
182     if (entry->config.dwTagId)
183         err = RegSetValueExW(hKey, SZ_TAG, 0, REG_DWORD, (LPBYTE)&entry->config.dwTagId, sizeof(DWORD));
184     else
185         err = RegDeleteValueW(hKey, SZ_TAG);
186 
187     if (err != 0 && err != ERROR_FILE_NOT_FOUND)
188         goto cleanup;
189 
190     err = ERROR_SUCCESS;
191 cleanup:
192     RegCloseKey(hKey);
193     return err;
194 }
195 
196 DWORD scmdatabase_add_service(struct scmdatabase *db, struct service_entry *service)
197 {
198     int err;
199     service->db = db;
200     if ((err = save_service_config(service)) != ERROR_SUCCESS)
201     {
202         WINE_ERR("Couldn't store service configuration: error %u\n", err);
203         return ERROR_GEN_FAILURE;
204     }
205 
206     list_add_tail(&db->services, &service->entry);
207     return ERROR_SUCCESS;
208 }
209 
210 DWORD scmdatabase_remove_service(struct scmdatabase *db, struct service_entry *service)
211 {
212     int err;
213 
214     err = RegDeleteTreeW(db->root_key, service->name);
215 
216     if (err != 0)
217         return err;
218 
219     list_remove(&service->entry);
220     service->entry.next = service->entry.prev = NULL;
221     return ERROR_SUCCESS;
222 }
223 
224 static void scmdatabase_autostart_services(struct scmdatabase *db)
225 {
226     struct service_entry **services_list;
227     unsigned int i = 0;
228     unsigned int size = 32;
229     struct service_entry *service;
230 
231     services_list = HeapAlloc(GetProcessHeap(), 0, size * sizeof(services_list[0]));
232     if (!services_list)
233         return;
234 
235     scmdatabase_lock_shared(db);
236 
237     LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry)
238     {
239         if (service->config.dwStartType == SERVICE_BOOT_START ||
240             service->config.dwStartType == SERVICE_SYSTEM_START ||
241             service->config.dwStartType == SERVICE_AUTO_START)
242         {
243             if (i+1 >= size)
244             {
245                 size *= 2;
246                 services_list = HeapReAlloc(GetProcessHeap(), 0, services_list, size * sizeof(services_list[0]));
247                 if (!services_list)
248                     break;
249             }
250             services_list[i] = service;
251             service->ref_count++;
252             i++;
253         }
254     }
255 
256     scmdatabase_unlock(db);
257 
258     size = i;
259     for (i = 0; i < size; i++)
260     {
261         DWORD err;
262         const WCHAR *argv[2];
263         service = services_list[i];
264         argv[0] = service->name;
265         argv[1] = NULL;
266         err = service_start(service, 1, argv);
267         /* FIXME: do something if the service failed to start */
268         release_service(service);
269     }
270 
271     HeapFree(GetProcessHeap(), 0, services_list);
272 }
273 
274 BOOL validate_service_name(LPCWSTR name)
275 {
276     return (name && name[0] && !strchrW(name, '/') && !strchrW(name, '\\'));
277 }
278 
279 BOOL validate_service_config(struct service_entry *entry)
280 {
281     if (entry->config.dwServiceType & SERVICE_WIN32 && (entry->config.lpBinaryPathName == NULL || !entry->config.lpBinaryPathName[0]))
282     {
283         WINE_ERR("Service %s is Win32 but has no image path set\n", wine_dbgstr_w(entry->name));
284         return FALSE;
285     }
286 
287     switch (entry->config.dwServiceType)
288     {
289     case SERVICE_KERNEL_DRIVER:
290     case SERVICE_FILE_SYSTEM_DRIVER:
291     case SERVICE_WIN32_OWN_PROCESS:
292     case SERVICE_WIN32_SHARE_PROCESS:
293         /* No problem */
294         break;
295     case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
296     case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
297         /* These can be only run as LocalSystem */
298         if (entry->config.lpServiceStartName && strcmpiW(entry->config.lpServiceStartName, SZ_LOCAL_SYSTEM) != 0)
299         {
300             WINE_ERR("Service %s is interactive but has a start name\n", wine_dbgstr_w(entry->name));
301             return FALSE;
302         }
303         break;
304     default:
305         WINE_ERR("Service %s has an unknown service type\n", wine_dbgstr_w(entry->name));
306         return FALSE;
307     }
308 
309     /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
310     if (entry->config.dwStartType > SERVICE_DISABLED)
311     {
312         WINE_ERR("Service %s has an unknown start type\n", wine_dbgstr_w(entry->name));
313         return FALSE;
314     }
315 
316     /* SERVICE_BOOT_START and SERVICE_SYSTEM_START are only allowed for driver services */
317     if (((entry->config.dwStartType == SERVICE_BOOT_START) || (entry->config.dwStartType == SERVICE_SYSTEM_START)) &&
318         ((entry->config.dwServiceType & SERVICE_WIN32_OWN_PROCESS) || (entry->config.dwServiceType & SERVICE_WIN32_SHARE_PROCESS)))
319     {
320         WINE_ERR("Service %s - SERVICE_BOOT_START and SERVICE_SYSTEM_START are only allowed for driver services\n", wine_dbgstr_w(entry->name));
321         return FALSE;
322     }
323 
324     if (entry->config.lpServiceStartName == NULL)
325         entry->config.lpServiceStartName = strdupW(SZ_LOCAL_SYSTEM);
326 
327     return TRUE;
328 }
329 
330 
331 struct service_entry *scmdatabase_find_service(struct scmdatabase *db, LPCWSTR name)
332 {
333     struct service_entry *service;
334 
335     LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry)
336     {
337         if (strcmpiW(name, service->name) == 0)
338             return service;
339     }
340 
341     return NULL;
342 }
343 
344 struct service_entry *scmdatabase_find_service_by_displayname(struct scmdatabase *db, LPCWSTR name)
345 {
346     struct service_entry *service;
347 
348     LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry)
349     {
350         if (strcmpiW(name, service->config.lpDisplayName) == 0)
351             return service;
352     }
353 
354     return NULL;
355 }
356 
357 void release_service(struct service_entry *service)
358 {
359     if (InterlockedDecrement(&service->ref_count) == 0 && is_marked_for_delete(service))
360         free_service_entry(service);
361 }
362 
363 static DWORD scmdatabase_create(struct scmdatabase **db)
364 {
365     DWORD err;
366 
367     *db = HeapAlloc(GetProcessHeap(), 0, sizeof(**db));
368     if (!*db)
369         return ERROR_NOT_ENOUGH_SERVER_MEMORY;
370 
371     (*db)->service_start_lock = FALSE;
372     list_init(&(*db)->services);
373 
374     InitializeCriticalSection(&(*db)->cs);
375 
376     err = RegCreateKeyExW(HKEY_LOCAL_MACHINE, SZ_SERVICES_KEY, 0, NULL,
377                           REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
378                           &(*db)->root_key, NULL);
379     if (err != ERROR_SUCCESS)
380         HeapFree(GetProcessHeap(), 0, *db);
381 
382     return err;
383 }
384 
385 static void scmdatabase_destroy(struct scmdatabase *db)
386 {
387     RegCloseKey(db->root_key);
388     DeleteCriticalSection(&db->cs);
389     HeapFree(GetProcessHeap(), 0, db);
390 }
391 
392 static DWORD scmdatabase_load_services(struct scmdatabase *db)
393 {
394     DWORD err;
395     int i;
396 
397     for (i = 0; TRUE; i++)
398     {
399         WCHAR szName[MAX_SERVICE_NAME];
400         struct service_entry *entry;
401         HKEY hServiceKey;
402 
403         err = RegEnumKeyW(db->root_key, i, szName, MAX_SERVICE_NAME);
404         if (err == ERROR_NO_MORE_ITEMS)
405             break;
406 
407         if (err != 0)
408         {
409             WINE_ERR("Error %d reading key %d name - skipping\n", err, i);
410             continue;
411         }
412 
413         err = service_create(szName, &entry);
414         if (err != ERROR_SUCCESS)
415             break;
416 
417         WINE_TRACE("Loading service %s\n", wine_dbgstr_w(szName));
418         err = RegOpenKeyExW(db->root_key, szName, 0, KEY_READ | KEY_WRITE, &hServiceKey);
419         if (err == ERROR_SUCCESS)
420         {
421             err = load_service_config(hServiceKey, entry);
422             RegCloseKey(hServiceKey);
423         }
424 
425         if (err != ERROR_SUCCESS)
426         {
427             WINE_ERR("Error %d reading registry key for service %s - skipping\n", err, wine_dbgstr_w(szName));
428             free_service_entry(entry);
429             continue;
430         }
431 
432         if (entry->config.dwServiceType == 0)
433         {
434             /* Maybe an application only wrote some configuration in the service key. Continue silently */
435             WINE_TRACE("Even the service type not set for service %s - skipping\n", wine_dbgstr_w(szName));
436             free_service_entry(entry);
437             continue;
438         }
439 
440         if (!validate_service_config(entry))
441         {
442             WINE_ERR("Invalid configuration of service %s - skipping\n", wine_dbgstr_w(szName));
443             free_service_entry(entry);
444             continue;
445         }
446 
447         entry->status.dwServiceType = entry->config.dwServiceType;
448         entry->db = db;
449 
450         list_add_tail(&db->services, &entry->entry);
451     }
452     return ERROR_SUCCESS;
453 }
454 
455 DWORD scmdatabase_lock_startup(struct scmdatabase *db)
456 {
457     if (InterlockedCompareExchange(&db->service_start_lock, TRUE, FALSE))
458         return ERROR_SERVICE_DATABASE_LOCKED;
459     return ERROR_SUCCESS;
460 }
461 
462 void scmdatabase_unlock_startup(struct scmdatabase *db)
463 {
464     InterlockedCompareExchange(&db->service_start_lock, FALSE, TRUE);
465 }
466 
467 void scmdatabase_lock_shared(struct scmdatabase *db)
468 {
469     EnterCriticalSection(&db->cs);
470 }
471 
472 void scmdatabase_lock_exclusive(struct scmdatabase *db)
473 {
474     EnterCriticalSection(&db->cs);
475 }
476 
477 void scmdatabase_unlock(struct scmdatabase *db)
478 {
479     LeaveCriticalSection(&db->cs);
480 }
481 
482 void service_lock_shared(struct service_entry *service)
483 {
484     EnterCriticalSection(&service->db->cs);
485 }
486 
487 void service_lock_exclusive(struct service_entry *service)
488 {
489     EnterCriticalSection(&service->db->cs);
490 }
491 
492 void service_unlock(struct service_entry *service)
493 {
494     LeaveCriticalSection(&service->db->cs);
495 }
496 
497 /* only one service started at a time, so there is no race on the registry
498  * value here */
499 static LPWSTR service_get_pipe_name(void)
500 {
501     static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
502         'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
503     static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
504         'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
505         'C','o','n','t','r','o','l','\\',
506         'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
507     LPWSTR name;
508     DWORD len;
509     HKEY service_current_key;
510     DWORD service_current = -1;
511     LONG ret;
512     DWORD type;
513 
514     ret = RegCreateKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
515         NULL, REG_OPTION_VOLATILE, KEY_SET_VALUE | KEY_QUERY_VALUE, NULL,
516         &service_current_key, NULL);
517     if (ret != ERROR_SUCCESS)
518         return NULL;
519     len = sizeof(service_current);
520     ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
521         (BYTE *)&service_current, &len);
522     if ((ret == ERROR_SUCCESS && type == REG_DWORD) || ret == ERROR_FILE_NOT_FOUND)
523     {
524         service_current++;
525         RegSetValueExW(service_current_key, NULL, 0, REG_DWORD,
526             (BYTE *)&service_current, sizeof(service_current));
527     }
528     RegCloseKey(service_current_key);
529     if ((ret != ERROR_SUCCESS || type != REG_DWORD) && (ret != ERROR_FILE_NOT_FOUND))
530         return NULL;
531     len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
532     name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
533     if (!name)
534         return NULL;
535     snprintfW(name, len, format, service_current);
536     return name;
537 }
538 
539 static DWORD service_start_process(struct service_entry *service_entry, HANDLE *process)
540 {
541     PROCESS_INFORMATION pi;
542     STARTUPINFOW si;
543     LPWSTR path = NULL;
544     DWORD size;
545     BOOL r;
546 
547     service_lock_exclusive(service_entry);
548 
549     if (service_entry->config.dwServiceType == SERVICE_KERNEL_DRIVER)
550     {
551         static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
552         DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(service_entry->name);
553 
554         if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
555             return ERROR_NOT_ENOUGH_SERVER_MEMORY;
556         GetSystemDirectoryW( path, len );
557         lstrcatW( path, winedeviceW );
558         lstrcatW( path, service_entry->name );
559     }
560     else
561     {
562         size = ExpandEnvironmentStringsW(service_entry->config.lpBinaryPathName,NULL,0);
563         path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
564         if (!path)
565             return ERROR_NOT_ENOUGH_SERVER_MEMORY;
566         ExpandEnvironmentStringsW(service_entry->config.lpBinaryPathName,path,size);
567     }
568 
569     ZeroMemory(&si, sizeof(STARTUPINFOW));
570     si.cb = sizeof(STARTUPINFOW);
571     if (!(service_entry->config.dwServiceType & SERVICE_INTERACTIVE_PROCESS))
572     {
573         static WCHAR desktopW[] = {'_','_','w','i','n','e','s','e','r','v','i','c','e','_','w','i','n','s','t','a','t','i','o','n','\\','D','e','f','a','u','l','t',0};
574         si.lpDesktop = desktopW;
575     }
576 
577     service_entry->status.dwCurrentState = SERVICE_START_PENDING;
578     service_entry->status.dwProcessId = pi.dwProcessId;
579 
580     service_unlock(service_entry);
581 
582     r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
583     HeapFree(GetProcessHeap(),0,path);
584     if (!r)
585     {
586         service_lock_exclusive(service_entry);
587         service_entry->status.dwCurrentState = SERVICE_STOPPED;
588         service_entry->status.dwProcessId = 0;
589         service_unlock(service_entry);
590         return GetLastError();
591     }
592 
593     *process = pi.hProcess;
594     CloseHandle( pi.hThread );
595 
596     return ERROR_SUCCESS;
597 }
598 
599 static DWORD service_wait_for_startup(struct service_entry *service_entry, HANDLE process_handle)
600 {
601     WINE_TRACE("%p\n", service_entry);
602 
603     for (;;)
604     {
605         DWORD dwCurrentStatus;
606         HANDLE handles[2] = { service_entry->status_changed_event, process_handle };
607         DWORD ret;
608         ret = WaitForMultipleObjects(sizeof(handles)/sizeof(handles[0]), handles, FALSE, 20000);
609         if (ret != WAIT_OBJECT_0)
610             return ERROR_SERVICE_REQUEST_TIMEOUT;
611         service_lock_shared(service_entry);
612         dwCurrentStatus = service_entry->status.dwCurrentState;
613         service_unlock(service_entry);
614         if (dwCurrentStatus == SERVICE_RUNNING)
615         {
616             WINE_TRACE("Service started successfully\n");
617             return ERROR_SUCCESS;
618         }
619         if (dwCurrentStatus != SERVICE_START_PENDING)
620             return ERROR_SERVICE_REQUEST_TIMEOUT;
621     }
622 }
623 
624 /******************************************************************************
625  * service_send_start_message
626  */
627 static BOOL service_send_start_message(struct service_entry *service, LPCWSTR *argv, DWORD argc)
628 {
629     DWORD i, len, count, result;
630     service_start_info *ssi;
631     LPWSTR p;
632     BOOL r;
633 
634     WINE_TRACE("%s %p %d\n", wine_dbgstr_w(service->name), argv, argc);
635 
636     /* FIXME: this can block so should be done in another thread */
637     r = ConnectNamedPipe(service->control_pipe, NULL);
638     if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
639     {
640         WINE_ERR("pipe connect failed\n");
641         return FALSE;
642     }
643 
644     /* calculate how much space do we need to send the startup info */
645     len = strlenW(service->name) + 1;
646     for (i=0; i<argc; i++)
647         len += strlenW(argv[i])+1;
648     len++;
649 
650     ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, data[len]));
651     ssi->cmd = WINESERV_STARTINFO;
652     ssi->control = 0;
653     ssi->total_size = FIELD_OFFSET(service_start_info, data[len]);
654     ssi->name_size = strlenW(service->name) + 1;
655     strcpyW( ssi->data, service->name );
656 
657     /* copy service args into a single buffer*/
658     p = &ssi->data[ssi->name_size];
659     for (i=0; i<argc; i++)
660     {
661         strcpyW(p, argv[i]);
662         p += strlenW(p) + 1;
663     }
664     *p=0;
665 
666     r = WriteFile(service->control_pipe, ssi, ssi->total_size, &count, NULL);
667     if (r)
668     {
669         r = ReadFile(service->control_pipe, &result, sizeof result, &count, NULL);
670         if (r && result)
671         {
672             SetLastError(result);
673             r = FALSE;
674         }
675     }
676 
677     HeapFree(GetProcessHeap(),0,ssi);
678 
679     return r;
680 }
681 
682 DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR *service_argv)
683 {
684     DWORD err;
685     LPWSTR name;
686     HANDLE process_handle = NULL;
687 
688     err = scmdatabase_lock_startup(service->db);
689     if (err != ERROR_SUCCESS)
690         return err;
691 
692     if (service->control_pipe != INVALID_HANDLE_VALUE)
693     {
694         scmdatabase_unlock_startup(service->db);
695         return ERROR_SERVICE_ALREADY_RUNNING;
696     }
697 
698     service->control_mutex = CreateMutexW(NULL, TRUE, NULL);
699 
700     if (!service->status_changed_event)
701         service->status_changed_event = CreateEventW(NULL, FALSE, FALSE, NULL);
702 
703     name = service_get_pipe_name();
704     service->control_pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
705                   PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
706     HeapFree(GetProcessHeap(), 0, name);
707     if (service->control_pipe==INVALID_HANDLE_VALUE)
708     {
709         WINE_ERR("failed to create pipe for %s, error = %d\n",
710             wine_dbgstr_w(service->name), GetLastError());
711         scmdatabase_unlock_startup(service->db);
712         return GetLastError();
713     }
714 
715     err = service_start_process(service, &process_handle);
716 
717     if (err == ERROR_SUCCESS)
718     {
719         if (!service_send_start_message(service, service_argv, service_argc))
720             err = ERROR_SERVICE_REQUEST_TIMEOUT;
721     }
722 
723     if (err == ERROR_SUCCESS)
724         err = service_wait_for_startup(service, process_handle);
725 
726     if (process_handle)
727         CloseHandle(process_handle);
728 
729     ReleaseMutex(service->control_mutex);
730     scmdatabase_unlock_startup(service->db);
731 
732     WINE_TRACE("returning %d\n", err);
733 
734     return err;
735 }
736 
737 
738 int main(int argc, char *argv[])
739 {
740     static const WCHAR svcctl_started_event[] = SVCCTL_STARTED_EVENT;
741     DWORD err;
742     g_hStartedEvent = CreateEventW(NULL, TRUE, FALSE, svcctl_started_event);
743     err = scmdatabase_create(&active_database);
744     if (err != ERROR_SUCCESS)
745         return err;
746     if ((err = scmdatabase_load_services(active_database)) != ERROR_SUCCESS)
747         return err;
748     if ((err = RPC_Init()) == ERROR_SUCCESS)
749     {
750         scmdatabase_autostart_services(active_database);
751         RPC_MainLoop();
752     }
753     scmdatabase_destroy(active_database);
754     return err;
755 }
756 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.