VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart-win.cpp@ 58103

Last change on this file since 58103 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.7 KB
Line 
1/* $Id: VBoxAutostart-win.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * VirtualBox Autostart Service - Windows Specific Code.
4 */
5
6/*
7 * Copyright (C) 2012-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <Windows.h>
23
24#include <VBox/com/com.h>
25#include <VBox/com/string.h>
26#include <VBox/com/Guid.h>
27#include <VBox/com/array.h>
28#include <VBox/com/ErrorInfo.h>
29#include <VBox/com/errorprint.h>
30
31#include <VBox/com/NativeEventQueue.h>
32#include <VBox/com/listeners.h>
33#include <VBox/com/VirtualBox.h>
34
35#include <VBox/log.h>
36#include <VBox/version.h>
37#include <iprt/string.h>
38#include <iprt/mem.h>
39#include <iprt/initterm.h>
40#include <iprt/stream.h>
41#include <iprt/getopt.h>
42#include <iprt/semaphore.h>
43#include <iprt/thread.h>
44
45#include "VBoxAutostart.h"
46
47
48/*********************************************************************************************************************************
49* Defined Constants And Macros *
50*********************************************************************************************************************************/
51/** The service name. */
52#define AUTOSTART_SERVICE_NAME "VBoxAutostartSvc"
53/** The service display name. */
54#define AUTOSTART_SERVICE_DISPLAY_NAME "VirtualBox Autostart Service"
55
56ComPtr<IVirtualBoxClient> g_pVirtualBoxClient = NULL;
57bool g_fVerbose = false;
58ComPtr<IVirtualBox> g_pVirtualBox = NULL;
59ComPtr<ISession> g_pSession = NULL;
60
61
62/*********************************************************************************************************************************
63* Global Variables *
64*********************************************************************************************************************************/
65/** The service control handler handle. */
66static SERVICE_STATUS_HANDLE g_hSupSvcWinCtrlHandler = NULL;
67/** The service status. */
68static uint32_t volatile g_u32SupSvcWinStatus = SERVICE_STOPPED;
69/** The semaphore the main service thread is waiting on in autostartSvcWinServiceMain. */
70static RTSEMEVENTMULTI g_hSupSvcWinEvent = NIL_RTSEMEVENTMULTI;
71
72
73/*********************************************************************************************************************************
74* Internal Functions *
75*********************************************************************************************************************************/
76static SC_HANDLE autostartSvcWinOpenSCManager(const char *pszAction, DWORD dwAccess);
77
78/**
79 * Print out progress on the console.
80 *
81 * This runs the main event queue every now and then to prevent piling up
82 * unhandled things (which doesn't cause real problems, just makes things
83 * react a little slower than in the ideal case).
84 */
85DECLHIDDEN(HRESULT) showProgress(ComPtr<IProgress> progress)
86{
87 using namespace com;
88
89 BOOL fCompleted = FALSE;
90 ULONG ulCurrentPercent = 0;
91 ULONG ulLastPercent = 0;
92
93 ULONG ulLastOperationPercent = (ULONG)-1;
94
95 ULONG ulLastOperation = (ULONG)-1;
96 Bstr bstrOperationDescription;
97
98 NativeEventQueue::getMainEventQueue()->processEventQueue(0);
99
100 ULONG cOperations = 1;
101 HRESULT hrc = progress->COMGETTER(OperationCount)(&cOperations);
102 if (FAILED(hrc))
103 return hrc;
104
105 /* setup signal handling if cancelable */
106 bool fCanceledAlready = false;
107 BOOL fCancelable;
108 hrc = progress->COMGETTER(Cancelable)(&fCancelable);
109 if (FAILED(hrc))
110 fCancelable = FALSE;
111
112 hrc = progress->COMGETTER(Completed(&fCompleted));
113 while (SUCCEEDED(hrc))
114 {
115 progress->COMGETTER(Percent(&ulCurrentPercent));
116
117 if (fCompleted)
118 break;
119
120 /* process async cancelation */
121 if (!fCanceledAlready)
122 {
123 hrc = progress->Cancel();
124 if (SUCCEEDED(hrc))
125 fCanceledAlready = true;
126 }
127
128 /* make sure the loop is not too tight */
129 progress->WaitForCompletion(100);
130
131 NativeEventQueue::getMainEventQueue()->processEventQueue(0);
132 hrc = progress->COMGETTER(Completed(&fCompleted));
133 }
134
135 /* complete the line. */
136 LONG iRc = E_FAIL;
137 hrc = progress->COMGETTER(ResultCode)(&iRc);
138 if (SUCCEEDED(hrc))
139 {
140 hrc = iRc;
141 }
142
143 return hrc;
144}
145
146DECLHIDDEN(void) autostartSvcOsLogStr(const char *pszMsg, AUTOSTARTLOGTYPE enmLogType)
147{
148 HANDLE hEventLog = RegisterEventSourceA(NULL /* local computer */, "VBoxAutostartSvc");
149 AssertReturnVoid(hEventLog != NULL);
150 WORD wType = 0;
151 const char *apsz[2];
152 apsz[0] = "VBoxAutostartSvc";
153 apsz[1] = pszMsg;
154
155 switch (enmLogType)
156 {
157 case AUTOSTARTLOGTYPE_INFO:
158 wType = 0;
159 break;
160 case AUTOSTARTLOGTYPE_ERROR:
161 wType = EVENTLOG_ERROR_TYPE;
162 break;
163 case AUTOSTARTLOGTYPE_WARNING:
164 wType = EVENTLOG_WARNING_TYPE;
165 break;
166 case AUTOSTARTLOGTYPE_VERBOSE:
167 if (!g_fVerbose)
168 return;
169 wType = EVENTLOG_INFORMATION_TYPE;
170 break;
171 default:
172 AssertMsgFailed(("Invalid log type %d\n", enmLogType));
173 }
174
175 BOOL fRc = ReportEventA(hEventLog, /* hEventLog */
176 wType, /* wType */
177 0, /* wCategory */
178 0 /** @todo mc */, /* dwEventID */
179 NULL, /* lpUserSid */
180 RT_ELEMENTS(apsz), /* wNumStrings */
181 0, /* dwDataSize */
182 apsz, /* lpStrings */
183 NULL); /* lpRawData */
184 AssertMsg(fRc, ("%d\n", GetLastError()));
185 DeregisterEventSource(hEventLog);
186}
187
188/**
189 * Opens the service control manager.
190 *
191 * When this fails, an error message will be displayed.
192 *
193 * @returns Valid handle on success.
194 * NULL on failure, will display an error message.
195 *
196 * @param pszAction The action which is requesting access to SCM.
197 * @param dwAccess The desired access.
198 */
199static SC_HANDLE autostartSvcWinOpenSCManager(const char *pszAction, DWORD dwAccess)
200{
201 SC_HANDLE hSCM = OpenSCManager(NULL /* lpMachineName*/, NULL /* lpDatabaseName */, dwAccess);
202 if (hSCM == NULL)
203 {
204 DWORD err = GetLastError();
205 switch (err)
206 {
207 case ERROR_ACCESS_DENIED:
208 autostartSvcDisplayError("%s - OpenSCManager failure: access denied\n", pszAction);
209 break;
210 default:
211 autostartSvcDisplayError("%s - OpenSCManager failure: %d\n", pszAction, err);
212 break;
213 }
214 }
215 return hSCM;
216}
217
218
219/**
220 * Opens the service.
221 *
222 * Last error is preserved on failure and set to 0 on success.
223 *
224 * @returns Valid service handle on success.
225 * NULL on failure, will display an error message unless it's ignored.
226 *
227 * @param pszAction The action which is requesting access to the service.
228 * @param dwSCMAccess The service control manager access.
229 * @param dwSVCAccess The desired service access.
230 * @param cIgnoredErrors The number of ignored errors.
231 * @param ... Errors codes that should not cause a message to be displayed.
232 */
233static SC_HANDLE autostartSvcWinOpenService(const char *pszAction, DWORD dwSCMAccess, DWORD dwSVCAccess,
234 unsigned cIgnoredErrors, ...)
235{
236 SC_HANDLE hSCM = autostartSvcWinOpenSCManager(pszAction, dwSCMAccess);
237 if (!hSCM)
238 return NULL;
239
240 SC_HANDLE hSvc = OpenServiceA(hSCM, AUTOSTART_SERVICE_NAME, dwSVCAccess);
241 if (hSvc)
242 {
243 CloseServiceHandle(hSCM);
244 SetLastError(0);
245 }
246 else
247 {
248 DWORD err = GetLastError();
249 bool fIgnored = false;
250 va_list va;
251 va_start(va, cIgnoredErrors);
252 while (!fIgnored && cIgnoredErrors-- > 0)
253 fIgnored = va_arg(va, long) == err;
254 va_end(va);
255 if (!fIgnored)
256 {
257 switch (err)
258 {
259 case ERROR_ACCESS_DENIED:
260 autostartSvcDisplayError("%s - OpenService failure: access denied\n", pszAction);
261 break;
262 case ERROR_SERVICE_DOES_NOT_EXIST:
263 autostartSvcDisplayError("%s - OpenService failure: The service does not exist. Reinstall it.\n", pszAction);
264 break;
265 default:
266 autostartSvcDisplayError("%s - OpenService failure: %d\n", pszAction, err);
267 break;
268 }
269 }
270
271 CloseServiceHandle(hSCM);
272 SetLastError(err);
273 }
274 return hSvc;
275}
276
277static RTEXITCODE autostartSvcWinInterrogate(int argc, char **argv)
278{
279 RTPrintf("VBoxAutostartSvc: The \"interrogate\" action is not implemented.\n");
280 return RTEXITCODE_FAILURE;
281}
282
283
284static RTEXITCODE autostartSvcWinStop(int argc, char **argv)
285{
286 RTPrintf("VBoxAutostartSvc: The \"stop\" action is not implemented.\n");
287 return RTEXITCODE_FAILURE;
288}
289
290
291static RTEXITCODE autostartSvcWinContinue(int argc, char **argv)
292{
293 RTPrintf("VBoxAutostartSvc: The \"continue\" action is not implemented.\n");
294 return RTEXITCODE_FAILURE;
295}
296
297
298static RTEXITCODE autostartSvcWinPause(int argc, char **argv)
299{
300 RTPrintf("VBoxAutostartSvc: The \"pause\" action is not implemented.\n");
301 return RTEXITCODE_FAILURE;
302}
303
304
305static RTEXITCODE autostartSvcWinStart(int argc, char **argv)
306{
307 RTPrintf("VBoxAutostartSvc: The \"start\" action is not implemented.\n");
308 return RTEXITCODE_SUCCESS;
309}
310
311
312static RTEXITCODE autostartSvcWinQueryDescription(int argc, char **argv)
313{
314 RTPrintf("VBoxAutostartSvc: The \"qdescription\" action is not implemented.\n");
315 return RTEXITCODE_FAILURE;
316}
317
318
319static RTEXITCODE autostartSvcWinQueryConfig(int argc, char **argv)
320{
321 RTPrintf("VBoxAutostartSvc: The \"qconfig\" action is not implemented.\n");
322 return RTEXITCODE_FAILURE;
323}
324
325
326static RTEXITCODE autostartSvcWinDisable(int argc, char **argv)
327{
328 RTPrintf("VBoxAutostartSvc: The \"disable\" action is not implemented.\n");
329 return RTEXITCODE_FAILURE;
330}
331
332static RTEXITCODE autostartSvcWinEnable(int argc, char **argv)
333{
334 RTPrintf("VBoxAutostartSvc: The \"enable\" action is not implemented.\n");
335 return RTEXITCODE_FAILURE;
336}
337
338
339/**
340 * Handle the 'delete' action.
341 *
342 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE.
343 * @param argc The action argument count.
344 * @param argv The action argument vector.
345 */
346static int autostartSvcWinDelete(int argc, char **argv)
347{
348 /*
349 * Parse the arguments.
350 */
351 bool fVerbose = false;
352 static const RTGETOPTDEF s_aOptions[] =
353 {
354 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
355 };
356 int ch;
357 unsigned iArg = 0;
358 RTGETOPTUNION Value;
359 RTGETOPTSTATE GetState;
360 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
361 while ((ch = RTGetOpt(&GetState, &Value)))
362 {
363 switch (ch)
364 {
365 case 'v':
366 fVerbose = true;
367 break;
368 case VINF_GETOPT_NOT_OPTION:
369 return autostartSvcDisplayTooManyArgsError("delete", argc, argv, iArg);
370 default:
371 return autostartSvcDisplayGetOptError("delete", ch, argc, argv, iArg, &Value);
372 }
373
374 iArg++;
375 }
376
377 /*
378 * Create the service.
379 */
380 int rc = RTEXITCODE_FAILURE;
381 SC_HANDLE hSvc = autostartSvcWinOpenService("delete", SERVICE_CHANGE_CONFIG, DELETE,
382 1, ERROR_SERVICE_DOES_NOT_EXIST);
383 if (hSvc)
384 {
385 if (DeleteService(hSvc))
386 {
387 RTPrintf("Successfully deleted the %s service.\n", AUTOSTART_SERVICE_NAME);
388 rc = RTEXITCODE_SUCCESS;
389 }
390 else
391 autostartSvcDisplayError("delete - DeleteService failed, err=%d.\n", GetLastError());
392 CloseServiceHandle(hSvc);
393 }
394 else if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
395 {
396
397 if (fVerbose)
398 RTPrintf("The service %s was not installed, nothing to be done.", AUTOSTART_SERVICE_NAME);
399 else
400 RTPrintf("Successfully deleted the %s service.\n", AUTOSTART_SERVICE_NAME);
401 rc = RTEXITCODE_SUCCESS;
402 }
403 return rc;
404}
405
406
407/**
408 * Handle the 'create' action.
409 *
410 * @returns 0 or 1.
411 * @param argc The action argument count.
412 * @param argv The action argument vector.
413 */
414static RTEXITCODE autostartSvcWinCreate(int argc, char **argv)
415{
416 /*
417 * Parse the arguments.
418 */
419 bool fVerbose = false;
420 const char *pszUser = NULL;
421 const char *pszPwd = NULL;
422 static const RTGETOPTDEF s_aOptions[] =
423 {
424 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
425 { "--user", 'u', RTGETOPT_REQ_STRING },
426 { "--password", 'p', RTGETOPT_REQ_STRING }
427 };
428 int iArg = 0;
429 int ch;
430 RTGETOPTUNION Value;
431 RTGETOPTSTATE GetState;
432 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
433 while ((ch = RTGetOpt(&GetState, &Value)))
434 {
435 switch (ch)
436 {
437 case 'v':
438 fVerbose = true;
439 break;
440 case 'u':
441 pszUser = Value.psz;
442 break;
443 case 'p':
444 pszPwd = Value.psz;
445 break;
446 default:
447 return autostartSvcDisplayGetOptError("create", ch, argc, argv, iArg, &Value);
448 }
449 iArg++;
450 }
451 if (iArg != argc)
452 return autostartSvcDisplayTooManyArgsError("create", argc, argv, iArg);
453
454 /*
455 * Create the service.
456 */
457 RTEXITCODE rc = RTEXITCODE_FAILURE;
458 SC_HANDLE hSCM = autostartSvcWinOpenSCManager("create", SC_MANAGER_CREATE_SERVICE); /*SC_MANAGER_ALL_ACCESS*/
459 if (hSCM)
460 {
461 char szExecPath[MAX_PATH];
462 if (GetModuleFileNameA(NULL /* the executable */, szExecPath, sizeof(szExecPath)))
463 {
464 if (fVerbose)
465 RTPrintf("Creating the %s service, binary \"%s\"...\n",
466 AUTOSTART_SERVICE_NAME, szExecPath); /* yea, the binary name isn't UTF-8, but wtf. */
467
468 SC_HANDLE hSvc = CreateServiceA(hSCM, /* hSCManager */
469 AUTOSTART_SERVICE_NAME, /* lpServiceName */
470 AUTOSTART_SERVICE_DISPLAY_NAME, /* lpDisplayName */
471 SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG, /* dwDesiredAccess */
472 SERVICE_WIN32_OWN_PROCESS, /* dwServiceType ( | SERVICE_INTERACTIVE_PROCESS? ) */
473 SERVICE_AUTO_START, /* dwStartType */
474 SERVICE_ERROR_NORMAL, /* dwErrorControl */
475 szExecPath, /* lpBinaryPathName */
476 NULL, /* lpLoadOrderGroup */
477 NULL, /* lpdwTagId */
478 NULL, /* lpDependencies */
479 pszUser, /* lpServiceStartName (NULL => LocalSystem) */
480 pszPwd); /* lpPassword */
481 if (hSvc)
482 {
483 RTPrintf("Successfully created the %s service.\n", AUTOSTART_SERVICE_NAME);
484 /** @todo Set the service description or it'll look weird in the vista service manager.
485 * Anything else that should be configured? Start access or something? */
486 rc = RTEXITCODE_SUCCESS;
487 CloseServiceHandle(hSvc);
488 }
489 else
490 {
491 DWORD err = GetLastError();
492 switch (err)
493 {
494 case ERROR_SERVICE_EXISTS:
495 autostartSvcDisplayError("create - The service already exists.\n");
496 break;
497 default:
498 autostartSvcDisplayError("create - CreateService failed, err=%d.\n", GetLastError());
499 break;
500 }
501 }
502 CloseServiceHandle(hSvc);
503 }
504 else
505 autostartSvcDisplayError("create - Failed to obtain the executable path: %d\n", GetLastError());
506 }
507 return rc;
508}
509
510
511/**
512 * Sets the service status, just a SetServiceStatus Wrapper.
513 *
514 * @returns See SetServiceStatus.
515 * @param dwStatus The current status.
516 * @param iWaitHint The wait hint, if < 0 then supply a default.
517 * @param dwExitCode The service exit code.
518 */
519static bool autostartSvcWinSetServiceStatus(DWORD dwStatus, int iWaitHint, DWORD dwExitCode)
520{
521 SERVICE_STATUS SvcStatus;
522 SvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
523 SvcStatus.dwWin32ExitCode = dwExitCode;
524 SvcStatus.dwServiceSpecificExitCode = 0;
525 SvcStatus.dwWaitHint = iWaitHint >= 0 ? iWaitHint : 3000;
526 SvcStatus.dwCurrentState = dwStatus;
527 LogFlow(("autostartSvcWinSetServiceStatus: %d -> %d\n", g_u32SupSvcWinStatus, dwStatus));
528 g_u32SupSvcWinStatus = dwStatus;
529 switch (dwStatus)
530 {
531 case SERVICE_START_PENDING:
532 SvcStatus.dwControlsAccepted = 0;
533 break;
534 default:
535 SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
536 break;
537 }
538
539 static DWORD dwCheckPoint = 0;
540 switch (dwStatus)
541 {
542 case SERVICE_RUNNING:
543 case SERVICE_STOPPED:
544 SvcStatus.dwCheckPoint = 0;
545 default:
546 SvcStatus.dwCheckPoint = ++dwCheckPoint;
547 break;
548 }
549 return SetServiceStatus(g_hSupSvcWinCtrlHandler, &SvcStatus) != FALSE;
550}
551
552
553/**
554 * Service control handler (extended).
555 *
556 * @returns Windows status (see HandlerEx).
557 * @retval NO_ERROR if handled.
558 * @retval ERROR_CALL_NOT_IMPLEMENTED if not handled.
559 *
560 * @param dwControl The control code.
561 * @param dwEventType Event type. (specific to the control?)
562 * @param pvEventData Event data, specific to the event.
563 * @param pvContext The context pointer registered with the handler.
564 * Currently not used.
565 */
566static DWORD WINAPI autostartSvcWinServiceCtrlHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID pvEventData, LPVOID pvContext)
567{
568 LogFlow(("autostartSvcWinServiceCtrlHandlerEx: dwControl=%#x dwEventType=%#x pvEventData=%p\n",
569 dwControl, dwEventType, pvEventData));
570
571 switch (dwControl)
572 {
573 /*
574 * Interrogate the service about it's current status.
575 * MSDN says that this should just return NO_ERROR and does
576 * not need to set the status again.
577 */
578 case SERVICE_CONTROL_INTERROGATE:
579 return NO_ERROR;
580
581 /*
582 * Request to stop the service.
583 */
584 case SERVICE_CONTROL_STOP:
585 {
586 /*
587 * Check if the real services can be stopped and then tell them to stop.
588 */
589 autostartSvcWinSetServiceStatus(SERVICE_STOP_PENDING, 3000, NO_ERROR);
590 /*
591 * Notify the main thread that we're done, it will wait for the
592 * VMs to stop, and set the windows service status to SERVICE_STOPPED
593 * and return.
594 */
595 int rc = RTSemEventMultiSignal(g_hSupSvcWinEvent);
596 if (RT_FAILURE(rc))
597 autostartSvcLogError("SERVICE_CONTROL_STOP: RTSemEventMultiSignal failed, %Rrc\n", rc);
598
599 return NO_ERROR;
600 }
601
602 case SERVICE_CONTROL_PAUSE:
603 case SERVICE_CONTROL_CONTINUE:
604 case SERVICE_CONTROL_SHUTDOWN:
605 case SERVICE_CONTROL_PARAMCHANGE:
606 case SERVICE_CONTROL_NETBINDADD:
607 case SERVICE_CONTROL_NETBINDREMOVE:
608 case SERVICE_CONTROL_NETBINDENABLE:
609 case SERVICE_CONTROL_NETBINDDISABLE:
610 case SERVICE_CONTROL_DEVICEEVENT:
611 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
612 case SERVICE_CONTROL_POWEREVENT:
613 case SERVICE_CONTROL_SESSIONCHANGE:
614#ifdef SERVICE_CONTROL_PRESHUTDOWN /* vista */
615 case SERVICE_CONTROL_PRESHUTDOWN:
616#endif
617 default:
618 return ERROR_CALL_NOT_IMPLEMENTED;
619 }
620
621 NOREF(dwEventType);
622 NOREF(pvEventData);
623 NOREF(pvContext);
624 return NO_ERROR;
625}
626
627static int autostartWorker(RTTHREAD ThreadSelf, void *pvUser)
628{
629 int rc = autostartSetup();
630
631 /** @todo: Implement config options. */
632 rc = autostartStartMain(NULL);
633 if (RT_FAILURE(rc))
634 autostartSvcLogError("Starting VMs failed, rc=%Rrc", rc);
635
636 return rc;
637}
638
639/**
640 * Windows Service Main.
641 *
642 * This is invoked when the service is started and should not return until
643 * the service has been stopped.
644 *
645 * @param cArgs Argument count.
646 * @param papszArgs Argument vector.
647 */
648static VOID WINAPI autostartSvcWinServiceMain(DWORD cArgs, LPTSTR *papszArgs)
649{
650 LogFlowFuncEnter();
651
652 /*
653 * Register the control handler function for the service and report to SCM.
654 */
655 Assert(g_u32SupSvcWinStatus == SERVICE_STOPPED);
656 g_hSupSvcWinCtrlHandler = RegisterServiceCtrlHandlerExA(AUTOSTART_SERVICE_NAME, autostartSvcWinServiceCtrlHandlerEx, NULL);
657 if (g_hSupSvcWinCtrlHandler)
658 {
659 DWORD err = ERROR_GEN_FAILURE;
660 if (autostartSvcWinSetServiceStatus(SERVICE_START_PENDING, 3000, NO_ERROR))
661 {
662 if (cArgs == 1)
663 {
664 /*
665 * Create the event semaphore we'll be waiting on and
666 * then instantiate the actual services.
667 */
668 int rc = RTSemEventMultiCreate(&g_hSupSvcWinEvent);
669 if (RT_SUCCESS(rc))
670 {
671 /*
672 * Update the status and enter the work loop.
673 */
674 if (autostartSvcWinSetServiceStatus(SERVICE_RUNNING, 0, 0))
675 {
676 LogFlow(("autostartSvcWinServiceMain: calling RTSemEventMultiWait\n"));
677 RTTHREAD hWorker;
678 RTThreadCreate(&hWorker, autostartWorker, NULL, 0, RTTHREADTYPE_DEFAULT, 0, "WorkerThread");
679
680 LogFlow(("autostartSvcWinServiceMain: woke up\n"));
681 err = NO_ERROR;
682 rc = RTSemEventMultiWait(g_hSupSvcWinEvent, RT_INDEFINITE_WAIT);
683 if (RT_SUCCESS(rc))
684 {
685 LogFlow(("autostartSvcWinServiceMain: woke up\n"));
686 /** @todo: Autostop part. */
687 err = NO_ERROR;
688 }
689 else
690 autostartSvcLogError("RTSemEventWait failed, rc=%Rrc", rc);
691
692 autostartShutdown();
693 }
694 else
695 {
696 err = GetLastError();
697 autostartSvcLogError("SetServiceStatus failed, err=%d", err);
698 }
699
700 RTSemEventMultiDestroy(g_hSupSvcWinEvent);
701 g_hSupSvcWinEvent = NIL_RTSEMEVENTMULTI;
702 }
703 else
704 autostartSvcLogError("RTSemEventMultiCreate failed, rc=%Rrc", rc);
705 }
706 else
707 autostartSvcLogTooManyArgsError("main", cArgs, NULL, 0);
708 }
709 else
710 {
711 err = GetLastError();
712 autostartSvcLogError("SetServiceStatus failed, err=%d", err);
713 }
714 autostartSvcWinSetServiceStatus(SERVICE_STOPPED, 0, err);
715 }
716 else
717 autostartSvcLogError("RegisterServiceCtrlHandlerEx failed, err=%d", GetLastError());
718
719 LogFlowFuncLeave();
720}
721
722
723/**
724 * Handle the 'create' action.
725 *
726 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE.
727 * @param argc The action argument count.
728 * @param argv The action argument vector.
729 */
730static int autostartSvcWinRunIt(int argc, char **argv)
731{
732 LogFlowFuncEnter();
733
734 /*
735 * Initialize release logging.
736 */
737 /** @todo release logging of the system-wide service. */
738
739 /*
740 * Parse the arguments.
741 */
742 static const RTGETOPTDEF s_aOptions[] =
743 {
744 { "--dummy", 'd', RTGETOPT_REQ_NOTHING }
745 };
746 int iArg = 0;
747 int ch;
748 RTGETOPTUNION Value;
749 RTGETOPTSTATE GetState;
750 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
751 while ((ch = RTGetOpt(&GetState, &Value)))
752 switch (ch)
753 {
754 default: return autostartSvcDisplayGetOptError("runit", ch, argc, argv, iArg, &Value);
755 }
756 if (iArg != argc)
757 return autostartSvcDisplayTooManyArgsError("runit", argc, argv, iArg);
758
759 /*
760 * Register the service with the service control manager
761 * and start dispatching requests from it (all done by the API).
762 */
763 static SERVICE_TABLE_ENTRY const s_aServiceStartTable[] =
764 {
765 { _T(AUTOSTART_SERVICE_NAME), autostartSvcWinServiceMain },
766 { NULL, NULL}
767 };
768 if (StartServiceCtrlDispatcher(&s_aServiceStartTable[0]))
769 {
770 LogFlowFuncLeave();
771 return RTEXITCODE_SUCCESS; /* told to quit, so quit. */
772 }
773
774 DWORD err = GetLastError();
775 switch (err)
776 {
777 case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
778 autostartSvcWinServiceMain(0, NULL);//autostartSvcDisplayError("Cannot run a service from the command line. Use the 'start' action to start it the right way.\n");
779 break;
780 default:
781 autostartSvcLogError("StartServiceCtrlDispatcher failed, err=%d", err);
782 break;
783 }
784 return RTEXITCODE_FAILURE;
785}
786
787
788/**
789 * Show the version info.
790 *
791 * @returns RTEXITCODE_SUCCESS.
792 */
793static RTEXITCODE autostartSvcWinShowVersion(int argc, char **argv)
794{
795 /*
796 * Parse the arguments.
797 */
798 bool fBrief = false;
799 static const RTGETOPTDEF s_aOptions[] =
800 {
801 { "--brief", 'b', RTGETOPT_REQ_NOTHING }
802 };
803 int iArg = 0;
804 int ch;
805 RTGETOPTUNION Value;
806 RTGETOPTSTATE GetState;
807 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
808 while ((ch = RTGetOpt(&GetState, &Value)))
809 switch (ch)
810 {
811 case 'b': fBrief = true; break;
812 default: return autostartSvcDisplayGetOptError("version", ch, argc, argv, iArg, &Value);
813
814 }
815 if (iArg != argc)
816 return autostartSvcDisplayTooManyArgsError("version", argc, argv, iArg);
817
818 /*
819 * Do the printing.
820 */
821 if (fBrief)
822 RTPrintf("%s\n", VBOX_VERSION_STRING);
823 else
824 RTPrintf("VirtualBox Autostart Service Version %s\n"
825 "(C) 2012 Oracle Corporation\n"
826 "All rights reserved.\n",
827 VBOX_VERSION_STRING);
828 return RTEXITCODE_SUCCESS;
829}
830
831
832/**
833 * Show the usage help screen.
834 *
835 * @returns RTEXITCODE_SUCCESS.
836 */
837static RTEXITCODE autostartSvcWinShowHelp(void)
838{
839 RTPrintf("VirtualBox Autostart Service Version %s\n"
840 "(C) 2012 Oracle Corporation\n"
841 "All rights reserved.\n"
842 "\n",
843 VBOX_VERSION_STRING);
844 RTPrintf("Usage:\n"
845 "\n"
846 "VBoxAutostartSvc\n"
847 " Runs the service.\n"
848 "VBoxAutostartSvc <version|-v|--version> [-brief]\n"
849 " Displays the version.\n"
850 "VBoxAutostartSvc <help|-?|-h|--help> [...]\n"
851 " Displays this help screen.\n"
852 "\n"
853 "VBoxAutostartSvc <install|/RegServer|/i>\n"
854 " Installs the service.\n"
855 "VBoxAutostartSvc <uninstall|delete|/UnregServer|/u>\n"
856 " Uninstalls the service.\n"
857 );
858 return RTEXITCODE_SUCCESS;
859}
860
861
862/**
863 * VBoxAutostart main(), Windows edition.
864 *
865 *
866 * @returns 0 on success.
867 *
868 * @param argc Number of arguments in argv.
869 * @param argv Argument vector.
870 */
871int main(int argc, char **argv)
872{
873 /*
874 * Initialize the IPRT first of all.
875 */
876 int rc = RTR3InitExe(argc, &argv, 0);
877 if (RT_FAILURE(rc))
878 {
879 autostartSvcLogError("RTR3InitExe failed with rc=%Rrc", rc);
880 return RTEXITCODE_FAILURE;
881 }
882
883 RTThreadSleep(10 * 1000);
884
885 /*
886 * Parse the initial arguments to determine the desired action.
887 */
888 enum
889 {
890 kAutoSvcAction_RunIt,
891
892 kAutoSvcAction_Create,
893 kAutoSvcAction_Delete,
894
895 kAutoSvcAction_Enable,
896 kAutoSvcAction_Disable,
897 kAutoSvcAction_QueryConfig,
898 kAutoSvcAction_QueryDescription,
899
900 kAutoSvcAction_Start,
901 kAutoSvcAction_Pause,
902 kAutoSvcAction_Continue,
903 kAutoSvcAction_Stop,
904 kAutoSvcAction_Interrogate,
905
906 kAutoSvcAction_End
907 } enmAction = kAutoSvcAction_RunIt;
908 int iArg = 1;
909 if (argc > 1)
910 {
911 if ( !stricmp(argv[iArg], "/RegServer")
912 || !stricmp(argv[iArg], "install")
913 || !stricmp(argv[iArg], "/i"))
914 enmAction = kAutoSvcAction_Create;
915 else if ( !stricmp(argv[iArg], "/UnregServer")
916 || !stricmp(argv[iArg], "/u")
917 || !stricmp(argv[iArg], "uninstall")
918 || !stricmp(argv[iArg], "delete"))
919 enmAction = kAutoSvcAction_Delete;
920
921 else if (!stricmp(argv[iArg], "enable"))
922 enmAction = kAutoSvcAction_Enable;
923 else if (!stricmp(argv[iArg], "disable"))
924 enmAction = kAutoSvcAction_Disable;
925 else if (!stricmp(argv[iArg], "qconfig"))
926 enmAction = kAutoSvcAction_QueryConfig;
927 else if (!stricmp(argv[iArg], "qdescription"))
928 enmAction = kAutoSvcAction_QueryDescription;
929
930 else if ( !stricmp(argv[iArg], "start")
931 || !stricmp(argv[iArg], "/t"))
932 enmAction = kAutoSvcAction_Start;
933 else if (!stricmp(argv[iArg], "pause"))
934 enmAction = kAutoSvcAction_Start;
935 else if (!stricmp(argv[iArg], "continue"))
936 enmAction = kAutoSvcAction_Continue;
937 else if (!stricmp(argv[iArg], "stop"))
938 enmAction = kAutoSvcAction_Stop;
939 else if (!stricmp(argv[iArg], "interrogate"))
940 enmAction = kAutoSvcAction_Interrogate;
941 else if ( !stricmp(argv[iArg], "help")
942 || !stricmp(argv[iArg], "?")
943 || !stricmp(argv[iArg], "/?")
944 || !stricmp(argv[iArg], "-?")
945 || !stricmp(argv[iArg], "/h")
946 || !stricmp(argv[iArg], "-h")
947 || !stricmp(argv[iArg], "/help")
948 || !stricmp(argv[iArg], "-help")
949 || !stricmp(argv[iArg], "--help"))
950 return autostartSvcWinShowHelp();
951 else if ( !stricmp(argv[iArg], "version")
952 || !stricmp(argv[iArg], "/v")
953 || !stricmp(argv[iArg], "-v")
954 || !stricmp(argv[iArg], "/version")
955 || !stricmp(argv[iArg], "-version")
956 || !stricmp(argv[iArg], "--version"))
957 return autostartSvcWinShowVersion(argc - iArg - 1, argv + iArg + 1);
958 else
959 iArg--;
960 iArg++;
961 }
962
963 /*
964 * Dispatch it.
965 */
966 switch (enmAction)
967 {
968 case kAutoSvcAction_RunIt:
969 return autostartSvcWinRunIt(argc - iArg, argv + iArg);
970
971 case kAutoSvcAction_Create:
972 return autostartSvcWinCreate(argc - iArg, argv + iArg);
973 case kAutoSvcAction_Delete:
974 return autostartSvcWinDelete(argc - iArg, argv + iArg);
975
976 case kAutoSvcAction_Enable:
977 return autostartSvcWinEnable(argc - iArg, argv + iArg);
978 case kAutoSvcAction_Disable:
979 return autostartSvcWinDisable(argc - iArg, argv + iArg);
980 case kAutoSvcAction_QueryConfig:
981 return autostartSvcWinQueryConfig(argc - iArg, argv + iArg);
982 case kAutoSvcAction_QueryDescription:
983 return autostartSvcWinQueryDescription(argc - iArg, argv + iArg);
984
985 case kAutoSvcAction_Start:
986 return autostartSvcWinStart(argc - iArg, argv + iArg);
987 case kAutoSvcAction_Pause:
988 return autostartSvcWinPause(argc - iArg, argv + iArg);
989 case kAutoSvcAction_Continue:
990 return autostartSvcWinContinue(argc - iArg, argv + iArg);
991 case kAutoSvcAction_Stop:
992 return autostartSvcWinStop(argc - iArg, argv + iArg);
993 case kAutoSvcAction_Interrogate:
994 return autostartSvcWinInterrogate(argc - iArg, argv + iArg);
995
996 default:
997 AssertMsgFailed(("enmAction=%d\n", enmAction));
998 return RTEXITCODE_FAILURE;
999 }
1000}
1001
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette