VirtualBox

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

Last change on this file since 45733 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.0 KB
Line 
1/* $Id: VBoxAutostart-win.cpp 44528 2013-02-04 14:27:54Z vboxsync $ */
2/** @file
3 * VirtualBox Autostart Service - Windows Specific Code.
4 */
5
6/*
7 * Copyright (C) 2012 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/EventQueue.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 EventQueue::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 EventQueue::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