VirtualBox

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

Last change on this file since 74942 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use