VirtualBox

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

Last change on this file since 46649 was 46649, checked in by vboxsync, 11 years ago

Forward ported r85941 and required build fixes (Main: Implemented new event queue to separate system's native event queue and our own. Also, XPCOM is not needed for handling our own events. On Windows this also fixes the system's queue quota limitation).

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