VirtualBox

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

Last change on this file since 77910 was 76553, checked in by vboxsync, 5 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 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VirtualBox Autostart Service - Windows Specific Code.
4 */
5
6/*
7 * Copyright (C) 2012-2019 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/errcore.h>
39#include <iprt/initterm.h>
40#include <iprt/mem.h>
41#include <iprt/getopt.h>
42#include <iprt/semaphore.h>
43#include <iprt/stream.h>
44#include <iprt/string.h>
45#include <iprt/thread.h>
46
47#include "VBoxAutostart.h"
48
49
50/*********************************************************************************************************************************
51* Defined Constants And Macros *
52*********************************************************************************************************************************/
53/** The service name. */
54#define AUTOSTART_SERVICE_NAME "VBoxAutostartSvc"
55/** The service display name. */
56#define AUTOSTART_SERVICE_DISPLAY_NAME "VirtualBox Autostart Service"
57
58ComPtr<IVirtualBoxClient> g_pVirtualBoxClient = NULL;
59bool g_fVerbose = false;
60ComPtr<IVirtualBox> g_pVirtualBox = NULL;
61ComPtr<ISession> g_pSession = NULL;
62
63
64/*********************************************************************************************************************************
65* Global Variables *
66*********************************************************************************************************************************/
67/** The service control handler handle. */
68static SERVICE_STATUS_HANDLE g_hSupSvcWinCtrlHandler = NULL;
69/** The service status. */
70static uint32_t volatile g_u32SupSvcWinStatus = SERVICE_STOPPED;
71/** The semaphore the main service thread is waiting on in autostartSvcWinServiceMain. */
72static RTSEMEVENTMULTI g_hSupSvcWinEvent = NIL_RTSEMEVENTMULTI;
73
74
75/*********************************************************************************************************************************
76* Internal Functions *
77*********************************************************************************************************************************/
78static SC_HANDLE autostartSvcWinOpenSCManager(const char *pszAction, DWORD dwAccess);
79
80/**
81 * Print out progress on the console.
82 *
83 * This runs the main event queue every now and then to prevent piling up
84 * unhandled things (which doesn't cause real problems, just makes things
85 * react a little slower than in the ideal case).
86 */
87DECLHIDDEN(HRESULT) showProgress(ComPtr<IProgress> progress)
88{
89 using namespace com;
90
91 BOOL fCompleted = FALSE;
92 ULONG uCurrentPercent = 0;
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(&uCurrentPercent));
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, ("%u\n", GetLastError())); NOREF(fRc);
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 = (DWORD)va_arg(va, int) == 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 RT_NOREF(argc, argv);
277 RTPrintf("VBoxAutostartSvc: The \"interrogate\" action is not implemented.\n");
278 return RTEXITCODE_FAILURE;
279}
280
281
282static RTEXITCODE autostartSvcWinStop(int argc, char **argv)
283{
284 RT_NOREF(argc, argv);
285 RTPrintf("VBoxAutostartSvc: The \"stop\" action is not implemented.\n");
286 return RTEXITCODE_FAILURE;
287}
288
289
290static RTEXITCODE autostartSvcWinContinue(int argc, char **argv)
291{
292 RT_NOREF(argc, argv);
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 RT_NOREF(argc, argv);
301 RTPrintf("VBoxAutostartSvc: The \"pause\" action is not implemented.\n");
302 return RTEXITCODE_FAILURE;
303}
304
305
306static RTEXITCODE autostartSvcWinStart(int argc, char **argv)
307{
308 RT_NOREF(argc, argv);
309 RTPrintf("VBoxAutostartSvc: The \"start\" action is not implemented.\n");
310 return RTEXITCODE_SUCCESS;
311}
312
313
314static RTEXITCODE autostartSvcWinQueryDescription(int argc, char **argv)
315{
316 RT_NOREF(argc, argv);
317 RTPrintf("VBoxAutostartSvc: The \"qdescription\" action is not implemented.\n");
318 return RTEXITCODE_FAILURE;
319}
320
321
322static RTEXITCODE autostartSvcWinQueryConfig(int argc, char **argv)
323{
324 RT_NOREF(argc, argv);
325 RTPrintf("VBoxAutostartSvc: The \"qconfig\" action is not implemented.\n");
326 return RTEXITCODE_FAILURE;
327}
328
329
330static RTEXITCODE autostartSvcWinDisable(int argc, char **argv)
331{
332 RT_NOREF(argc, argv);
333 RTPrintf("VBoxAutostartSvc: The \"disable\" action is not implemented.\n");
334 return RTEXITCODE_FAILURE;
335}
336
337static RTEXITCODE autostartSvcWinEnable(int argc, char **argv)
338{
339 RT_NOREF(argc, argv);
340 RTPrintf("VBoxAutostartSvc: The \"enable\" action is not implemented.\n");
341 return RTEXITCODE_FAILURE;
342}
343
344
345/**
346 * Handle the 'delete' action.
347 *
348 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE.
349 * @param argc The action argument count.
350 * @param argv The action argument vector.
351 */
352static int autostartSvcWinDelete(int argc, char **argv)
353{
354 /*
355 * Parse the arguments.
356 */
357 bool fVerbose = false;
358 static const RTGETOPTDEF s_aOptions[] =
359 {
360 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
361 };
362 int ch;
363 unsigned iArg = 0;
364 RTGETOPTUNION Value;
365 RTGETOPTSTATE GetState;
366 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
367 while ((ch = RTGetOpt(&GetState, &Value)))
368 {
369 switch (ch)
370 {
371 case 'v':
372 fVerbose = true;
373 break;
374 case VINF_GETOPT_NOT_OPTION:
375 return autostartSvcDisplayTooManyArgsError("delete", argc, argv, iArg);
376 default:
377 return autostartSvcDisplayGetOptError("delete", ch, argc, argv, iArg, &Value);
378 }
379
380 iArg++;
381 }
382
383 /*
384 * Create the service.
385 */
386 int rc = RTEXITCODE_FAILURE;
387 SC_HANDLE hSvc = autostartSvcWinOpenService("delete", SERVICE_CHANGE_CONFIG, DELETE,
388 1, ERROR_SERVICE_DOES_NOT_EXIST);
389 if (hSvc)
390 {
391 if (DeleteService(hSvc))
392 {
393 RTPrintf("Successfully deleted the %s service.\n", AUTOSTART_SERVICE_NAME);
394 rc = RTEXITCODE_SUCCESS;
395 }
396 else
397 autostartSvcDisplayError("delete - DeleteService failed, err=%d.\n", GetLastError());
398 CloseServiceHandle(hSvc);
399 }
400 else if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
401 {
402
403 if (fVerbose)
404 RTPrintf("The service %s was not installed, nothing to be done.", AUTOSTART_SERVICE_NAME);
405 else
406 RTPrintf("Successfully deleted the %s service.\n", AUTOSTART_SERVICE_NAME);
407 rc = RTEXITCODE_SUCCESS;
408 }
409 return rc;
410}
411
412
413/**
414 * Handle the 'create' action.
415 *
416 * @returns 0 or 1.
417 * @param argc The action argument count.
418 * @param argv The action argument vector.
419 */
420static RTEXITCODE autostartSvcWinCreate(int argc, char **argv)
421{
422 /*
423 * Parse the arguments.
424 */
425 bool fVerbose = false;
426 const char *pszUser = NULL;
427 const char *pszPwd = NULL;
428 static const RTGETOPTDEF s_aOptions[] =
429 {
430 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
431 { "--user", 'u', RTGETOPT_REQ_STRING },
432 { "--password", 'p', RTGETOPT_REQ_STRING }
433 };
434 int iArg = 0;
435 int ch;
436 RTGETOPTUNION Value;
437 RTGETOPTSTATE GetState;
438 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
439 while ((ch = RTGetOpt(&GetState, &Value)))
440 {
441 switch (ch)
442 {
443 case 'v':
444 fVerbose = true;
445 break;
446 case 'u':
447 pszUser = Value.psz;
448 break;
449 case 'p':
450 pszPwd = Value.psz;
451 break;
452 default:
453 return autostartSvcDisplayGetOptError("create", ch, argc, argv, iArg, &Value);
454 }
455 iArg++;
456 }
457 if (iArg != argc)
458 return autostartSvcDisplayTooManyArgsError("create", argc, argv, iArg);
459
460 /*
461 * Create the service.
462 */
463 RTEXITCODE rc = RTEXITCODE_FAILURE;
464 SC_HANDLE hSCM = autostartSvcWinOpenSCManager("create", SC_MANAGER_CREATE_SERVICE); /*SC_MANAGER_ALL_ACCESS*/
465 if (hSCM)
466 {
467 char szExecPath[MAX_PATH];
468 if (GetModuleFileNameA(NULL /* the executable */, szExecPath, sizeof(szExecPath)))
469 {
470 if (fVerbose)
471 RTPrintf("Creating the %s service, binary \"%s\"...\n",
472 AUTOSTART_SERVICE_NAME, szExecPath); /* yea, the binary name isn't UTF-8, but wtf. */
473
474 SC_HANDLE hSvc = CreateServiceA(hSCM, /* hSCManager */
475 AUTOSTART_SERVICE_NAME, /* lpServiceName */
476 AUTOSTART_SERVICE_DISPLAY_NAME, /* lpDisplayName */
477 SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG, /* dwDesiredAccess */
478 SERVICE_WIN32_OWN_PROCESS, /* dwServiceType ( | SERVICE_INTERACTIVE_PROCESS? ) */
479 SERVICE_AUTO_START, /* dwStartType */
480 SERVICE_ERROR_NORMAL, /* dwErrorControl */
481 szExecPath, /* lpBinaryPathName */
482 NULL, /* lpLoadOrderGroup */
483 NULL, /* lpdwTagId */
484 NULL, /* lpDependencies */
485 pszUser, /* lpServiceStartName (NULL => LocalSystem) */
486 pszPwd); /* lpPassword */
487 if (hSvc)
488 {
489 RTPrintf("Successfully created the %s service.\n", AUTOSTART_SERVICE_NAME);
490 /** @todo Set the service description or it'll look weird in the vista service manager.
491 * Anything else that should be configured? Start access or something? */
492 rc = RTEXITCODE_SUCCESS;
493 CloseServiceHandle(hSvc);
494 }
495 else
496 {
497 DWORD err = GetLastError();
498 switch (err)
499 {
500 case ERROR_SERVICE_EXISTS:
501 autostartSvcDisplayError("create - The service already exists.\n");
502 break;
503 default:
504 autostartSvcDisplayError("create - CreateService failed, err=%d.\n", GetLastError());
505 break;
506 }
507 }
508 CloseServiceHandle(hSvc);
509 }
510 else
511 autostartSvcDisplayError("create - Failed to obtain the executable path: %d\n", GetLastError());
512 }
513 return rc;
514}
515
516
517/**
518 * Sets the service status, just a SetServiceStatus Wrapper.
519 *
520 * @returns See SetServiceStatus.
521 * @param dwStatus The current status.
522 * @param iWaitHint The wait hint, if < 0 then supply a default.
523 * @param dwExitCode The service exit code.
524 */
525static bool autostartSvcWinSetServiceStatus(DWORD dwStatus, int iWaitHint, DWORD dwExitCode)
526{
527 SERVICE_STATUS SvcStatus;
528 SvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
529 SvcStatus.dwWin32ExitCode = dwExitCode;
530 SvcStatus.dwServiceSpecificExitCode = 0;
531 SvcStatus.dwWaitHint = iWaitHint >= 0 ? iWaitHint : 3000;
532 SvcStatus.dwCurrentState = dwStatus;
533 LogFlow(("autostartSvcWinSetServiceStatus: %d -> %d\n", g_u32SupSvcWinStatus, dwStatus));
534 g_u32SupSvcWinStatus = dwStatus;
535 switch (dwStatus)
536 {
537 case SERVICE_START_PENDING:
538 SvcStatus.dwControlsAccepted = 0;
539 break;
540 default:
541 SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
542 break;
543 }
544
545 static DWORD dwCheckPoint = 0;
546 switch (dwStatus)
547 {
548 case SERVICE_RUNNING:
549 case SERVICE_STOPPED:
550 SvcStatus.dwCheckPoint = 0;
551 default:
552 SvcStatus.dwCheckPoint = ++dwCheckPoint;
553 break;
554 }
555 return SetServiceStatus(g_hSupSvcWinCtrlHandler, &SvcStatus) != FALSE;
556}
557
558
559/**
560 * Service control handler (extended).
561 *
562 * @returns Windows status (see HandlerEx).
563 * @retval NO_ERROR if handled.
564 * @retval ERROR_CALL_NOT_IMPLEMENTED if not handled.
565 *
566 * @param dwControl The control code.
567 * @param dwEventType Event type. (specific to the control?)
568 * @param pvEventData Event data, specific to the event.
569 * @param pvContext The context pointer registered with the handler.
570 * Currently not used.
571 */
572static DWORD WINAPI autostartSvcWinServiceCtrlHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID pvEventData, LPVOID pvContext)
573{
574 LogFlow(("autostartSvcWinServiceCtrlHandlerEx: dwControl=%#x dwEventType=%#x pvEventData=%p\n",
575 dwControl, dwEventType, pvEventData));
576
577 switch (dwControl)
578 {
579 /*
580 * Interrogate the service about it's current status.
581 * MSDN says that this should just return NO_ERROR and does
582 * not need to set the status again.
583 */
584 case SERVICE_CONTROL_INTERROGATE:
585 return NO_ERROR;
586
587 /*
588 * Request to stop the service.
589 */
590 case SERVICE_CONTROL_STOP:
591 {
592 /*
593 * Check if the real services can be stopped and then tell them to stop.
594 */
595 autostartSvcWinSetServiceStatus(SERVICE_STOP_PENDING, 3000, NO_ERROR);
596 /*
597 * Notify the main thread that we're done, it will wait for the
598 * VMs to stop, and set the windows service status to SERVICE_STOPPED
599 * and return.
600 */
601 int rc = RTSemEventMultiSignal(g_hSupSvcWinEvent);
602 if (RT_FAILURE(rc))
603 autostartSvcLogError("SERVICE_CONTROL_STOP: RTSemEventMultiSignal failed, %Rrc\n", rc);
604
605 return NO_ERROR;
606 }
607
608 case SERVICE_CONTROL_PAUSE:
609 case SERVICE_CONTROL_CONTINUE:
610 case SERVICE_CONTROL_SHUTDOWN:
611 case SERVICE_CONTROL_PARAMCHANGE:
612 case SERVICE_CONTROL_NETBINDADD:
613 case SERVICE_CONTROL_NETBINDREMOVE:
614 case SERVICE_CONTROL_NETBINDENABLE:
615 case SERVICE_CONTROL_NETBINDDISABLE:
616 case SERVICE_CONTROL_DEVICEEVENT:
617 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
618 case SERVICE_CONTROL_POWEREVENT:
619 case SERVICE_CONTROL_SESSIONCHANGE:
620#ifdef SERVICE_CONTROL_PRESHUTDOWN /* vista */
621 case SERVICE_CONTROL_PRESHUTDOWN:
622#endif
623 default:
624 return ERROR_CALL_NOT_IMPLEMENTED;
625 }
626
627 NOREF(dwEventType);
628 NOREF(pvEventData);
629 NOREF(pvContext);
630 /* not reached */
631}
632
633static DECLCALLBACK(int) autostartWorkerThread(RTTHREAD hThreadSelf, void *pvUser)
634{
635 RT_NOREF(hThreadSelf, pvUser);
636 int rc = autostartSetup();
637
638 /** @todo Implement config options. */
639 rc = autostartStartMain(NULL);
640 if (RT_FAILURE(rc))
641 autostartSvcLogError("Starting VMs failed, rc=%Rrc", rc);
642
643 return rc;
644}
645
646/**
647 * Windows Service Main.
648 *
649 * This is invoked when the service is started and should not return until
650 * the service has been stopped.
651 *
652 * @param cArgs Argument count.
653 * @param papszArgs Argument vector.
654 */
655static VOID WINAPI autostartSvcWinServiceMain(DWORD cArgs, LPTSTR *papszArgs)
656{
657 RT_NOREF(papszArgs);
658 LogFlowFuncEnter();
659
660 /*
661 * Register the control handler function for the service and report to SCM.
662 */
663 Assert(g_u32SupSvcWinStatus == SERVICE_STOPPED);
664 g_hSupSvcWinCtrlHandler = RegisterServiceCtrlHandlerExA(AUTOSTART_SERVICE_NAME, autostartSvcWinServiceCtrlHandlerEx, NULL);
665 if (g_hSupSvcWinCtrlHandler)
666 {
667 DWORD err = ERROR_GEN_FAILURE;
668 if (autostartSvcWinSetServiceStatus(SERVICE_START_PENDING, 3000, NO_ERROR))
669 {
670 if (cArgs == 1)
671 {
672 /*
673 * Create the event semaphore we'll be waiting on and
674 * then instantiate the actual services.
675 */
676 int rc = RTSemEventMultiCreate(&g_hSupSvcWinEvent);
677 if (RT_SUCCESS(rc))
678 {
679 /*
680 * Update the status and enter the work loop.
681 */
682 if (autostartSvcWinSetServiceStatus(SERVICE_RUNNING, 0, 0))
683 {
684 LogFlow(("autostartSvcWinServiceMain: calling RTSemEventMultiWait\n"));
685 RTTHREAD hWorker;
686 RTThreadCreate(&hWorker, autostartWorkerThread, NULL, 0, RTTHREADTYPE_DEFAULT, 0, "WorkerThread");
687
688 LogFlow(("autostartSvcWinServiceMain: woke up\n"));
689 err = NO_ERROR;
690 rc = RTSemEventMultiWait(g_hSupSvcWinEvent, RT_INDEFINITE_WAIT);
691 if (RT_SUCCESS(rc))
692 {
693 LogFlow(("autostartSvcWinServiceMain: woke up\n"));
694 /** @todo Autostop part. */
695 err = NO_ERROR;
696 }
697 else
698 autostartSvcLogError("RTSemEventWait failed, rc=%Rrc", rc);
699
700 autostartShutdown();
701 }
702 else
703 {
704 err = GetLastError();
705 autostartSvcLogError("SetServiceStatus failed, err=%d", err);
706 }
707
708 RTSemEventMultiDestroy(g_hSupSvcWinEvent);
709 g_hSupSvcWinEvent = NIL_RTSEMEVENTMULTI;
710 }
711 else
712 autostartSvcLogError("RTSemEventMultiCreate failed, rc=%Rrc", rc);
713 }
714 else
715 autostartSvcLogTooManyArgsError("main", cArgs, NULL, 0);
716 }
717 else
718 {
719 err = GetLastError();
720 autostartSvcLogError("SetServiceStatus failed, err=%d", err);
721 }
722 autostartSvcWinSetServiceStatus(SERVICE_STOPPED, 0, err);
723 }
724 else
725 autostartSvcLogError("RegisterServiceCtrlHandlerEx failed, err=%d", GetLastError());
726
727 LogFlowFuncLeave();
728}
729
730
731/**
732 * Handle the 'create' action.
733 *
734 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE.
735 * @param argc The action argument count.
736 * @param argv The action argument vector.
737 */
738static int autostartSvcWinRunIt(int argc, char **argv)
739{
740 LogFlowFuncEnter();
741
742 /*
743 * Initialize release logging.
744 */
745 /** @todo release logging of the system-wide service. */
746
747 /*
748 * Parse the arguments.
749 */
750 static const RTGETOPTDEF s_aOptions[] =
751 {
752 { "--dummy", 'd', RTGETOPT_REQ_NOTHING }
753 };
754 int iArg = 0;
755 int ch;
756 RTGETOPTUNION Value;
757 RTGETOPTSTATE GetState;
758 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
759 while ((ch = RTGetOpt(&GetState, &Value)))
760 switch (ch)
761 {
762 default: return autostartSvcDisplayGetOptError("runit", ch, argc, argv, iArg, &Value);
763 }
764 if (iArg != argc)
765 return autostartSvcDisplayTooManyArgsError("runit", argc, argv, iArg);
766
767 /*
768 * Register the service with the service control manager
769 * and start dispatching requests from it (all done by the API).
770 */
771 static SERVICE_TABLE_ENTRY const s_aServiceStartTable[] =
772 {
773 { _T(AUTOSTART_SERVICE_NAME), autostartSvcWinServiceMain },
774 { NULL, NULL}
775 };
776 if (StartServiceCtrlDispatcher(&s_aServiceStartTable[0]))
777 {
778 LogFlowFuncLeave();
779 return RTEXITCODE_SUCCESS; /* told to quit, so quit. */
780 }
781
782 DWORD err = GetLastError();
783 switch (err)
784 {
785 case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
786 autostartSvcWinServiceMain(0, NULL);//autostartSvcDisplayError("Cannot run a service from the command line. Use the 'start' action to start it the right way.\n");
787 break;
788 default:
789 autostartSvcLogError("StartServiceCtrlDispatcher failed, err=%d", err);
790 break;
791 }
792 return RTEXITCODE_FAILURE;
793}
794
795
796/**
797 * Show the version info.
798 *
799 * @returns RTEXITCODE_SUCCESS.
800 */
801static RTEXITCODE autostartSvcWinShowVersion(int argc, char **argv)
802{
803 /*
804 * Parse the arguments.
805 */
806 bool fBrief = false;
807 static const RTGETOPTDEF s_aOptions[] =
808 {
809 { "--brief", 'b', RTGETOPT_REQ_NOTHING }
810 };
811 int iArg = 0;
812 int ch;
813 RTGETOPTUNION Value;
814 RTGETOPTSTATE GetState;
815 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
816 while ((ch = RTGetOpt(&GetState, &Value)))
817 switch (ch)
818 {
819 case 'b': fBrief = true; break;
820 default: return autostartSvcDisplayGetOptError("version", ch, argc, argv, iArg, &Value);
821
822 }
823 if (iArg != argc)
824 return autostartSvcDisplayTooManyArgsError("version", argc, argv, iArg);
825
826 /*
827 * Do the printing.
828 */
829 if (fBrief)
830 RTPrintf("%s\n", VBOX_VERSION_STRING);
831 else
832 RTPrintf("VirtualBox Autostart Service Version %s\n"
833 "(C) 2012 Oracle Corporation\n"
834 "All rights reserved.\n",
835 VBOX_VERSION_STRING);
836 return RTEXITCODE_SUCCESS;
837}
838
839
840/**
841 * Show the usage help screen.
842 *
843 * @returns RTEXITCODE_SUCCESS.
844 */
845static RTEXITCODE autostartSvcWinShowHelp(void)
846{
847 RTPrintf("VirtualBox Autostart Service Version %s\n"
848 "(C) 2012 Oracle Corporation\n"
849 "All rights reserved.\n"
850 "\n",
851 VBOX_VERSION_STRING);
852 RTPrintf("Usage:\n"
853 "\n"
854 "VBoxAutostartSvc\n"
855 " Runs the service.\n"
856 "VBoxAutostartSvc <version|-v|--version> [-brief]\n"
857 " Displays the version.\n"
858 "VBoxAutostartSvc <help|-?|-h|--help> [...]\n"
859 " Displays this help screen.\n"
860 "\n"
861 "VBoxAutostartSvc <install|/RegServer|/i>\n"
862 " Installs the service.\n"
863 "VBoxAutostartSvc <uninstall|delete|/UnregServer|/u>\n"
864 " Uninstalls the service.\n"
865 );
866 return RTEXITCODE_SUCCESS;
867}
868
869
870/**
871 * VBoxAutostart main(), Windows edition.
872 *
873 *
874 * @returns 0 on success.
875 *
876 * @param argc Number of arguments in argv.
877 * @param argv Argument vector.
878 */
879int main(int argc, char **argv)
880{
881 /*
882 * Initialize the IPRT first of all.
883 */
884 int rc = RTR3InitExe(argc, &argv, 0);
885 if (RT_FAILURE(rc))
886 {
887 autostartSvcLogError("RTR3InitExe failed with rc=%Rrc", rc);
888 return RTEXITCODE_FAILURE;
889 }
890
891 RTThreadSleep(10 * 1000);
892
893 /*
894 * Parse the initial arguments to determine the desired action.
895 */
896 enum
897 {
898 kAutoSvcAction_RunIt,
899
900 kAutoSvcAction_Create,
901 kAutoSvcAction_Delete,
902
903 kAutoSvcAction_Enable,
904 kAutoSvcAction_Disable,
905 kAutoSvcAction_QueryConfig,
906 kAutoSvcAction_QueryDescription,
907
908 kAutoSvcAction_Start,
909 kAutoSvcAction_Pause,
910 kAutoSvcAction_Continue,
911 kAutoSvcAction_Stop,
912 kAutoSvcAction_Interrogate,
913
914 kAutoSvcAction_End
915 } enmAction = kAutoSvcAction_RunIt;
916 int iArg = 1;
917 if (argc > 1)
918 {
919 if ( !stricmp(argv[iArg], "/RegServer")
920 || !stricmp(argv[iArg], "install")
921 || !stricmp(argv[iArg], "/i"))
922 enmAction = kAutoSvcAction_Create;
923 else if ( !stricmp(argv[iArg], "/UnregServer")
924 || !stricmp(argv[iArg], "/u")
925 || !stricmp(argv[iArg], "uninstall")
926 || !stricmp(argv[iArg], "delete"))
927 enmAction = kAutoSvcAction_Delete;
928
929 else if (!stricmp(argv[iArg], "enable"))
930 enmAction = kAutoSvcAction_Enable;
931 else if (!stricmp(argv[iArg], "disable"))
932 enmAction = kAutoSvcAction_Disable;
933 else if (!stricmp(argv[iArg], "qconfig"))
934 enmAction = kAutoSvcAction_QueryConfig;
935 else if (!stricmp(argv[iArg], "qdescription"))
936 enmAction = kAutoSvcAction_QueryDescription;
937
938 else if ( !stricmp(argv[iArg], "start")
939 || !stricmp(argv[iArg], "/t"))
940 enmAction = kAutoSvcAction_Start;
941 else if (!stricmp(argv[iArg], "pause"))
942 enmAction = kAutoSvcAction_Start;
943 else if (!stricmp(argv[iArg], "continue"))
944 enmAction = kAutoSvcAction_Continue;
945 else if (!stricmp(argv[iArg], "stop"))
946 enmAction = kAutoSvcAction_Stop;
947 else if (!stricmp(argv[iArg], "interrogate"))
948 enmAction = kAutoSvcAction_Interrogate;
949 else if ( !stricmp(argv[iArg], "help")
950 || !stricmp(argv[iArg], "?")
951 || !stricmp(argv[iArg], "/?")
952 || !stricmp(argv[iArg], "-?")
953 || !stricmp(argv[iArg], "/h")
954 || !stricmp(argv[iArg], "-h")
955 || !stricmp(argv[iArg], "/help")
956 || !stricmp(argv[iArg], "-help")
957 || !stricmp(argv[iArg], "--help"))
958 return autostartSvcWinShowHelp();
959 else if ( !stricmp(argv[iArg], "version")
960 || !stricmp(argv[iArg], "/v")
961 || !stricmp(argv[iArg], "-v")
962 || !stricmp(argv[iArg], "/version")
963 || !stricmp(argv[iArg], "-version")
964 || !stricmp(argv[iArg], "--version"))
965 return autostartSvcWinShowVersion(argc - iArg - 1, argv + iArg + 1);
966 else
967 iArg--;
968 iArg++;
969 }
970
971 /*
972 * Dispatch it.
973 */
974 switch (enmAction)
975 {
976 case kAutoSvcAction_RunIt:
977 return autostartSvcWinRunIt(argc - iArg, argv + iArg);
978
979 case kAutoSvcAction_Create:
980 return autostartSvcWinCreate(argc - iArg, argv + iArg);
981 case kAutoSvcAction_Delete:
982 return autostartSvcWinDelete(argc - iArg, argv + iArg);
983
984 case kAutoSvcAction_Enable:
985 return autostartSvcWinEnable(argc - iArg, argv + iArg);
986 case kAutoSvcAction_Disable:
987 return autostartSvcWinDisable(argc - iArg, argv + iArg);
988 case kAutoSvcAction_QueryConfig:
989 return autostartSvcWinQueryConfig(argc - iArg, argv + iArg);
990 case kAutoSvcAction_QueryDescription:
991 return autostartSvcWinQueryDescription(argc - iArg, argv + iArg);
992
993 case kAutoSvcAction_Start:
994 return autostartSvcWinStart(argc - iArg, argv + iArg);
995 case kAutoSvcAction_Pause:
996 return autostartSvcWinPause(argc - iArg, argv + iArg);
997 case kAutoSvcAction_Continue:
998 return autostartSvcWinContinue(argc - iArg, argv + iArg);
999 case kAutoSvcAction_Stop:
1000 return autostartSvcWinStop(argc - iArg, argv + iArg);
1001 case kAutoSvcAction_Interrogate:
1002 return autostartSvcWinInterrogate(argc - iArg, argv + iArg);
1003
1004 default:
1005 AssertMsgFailed(("enmAction=%d\n", enmAction));
1006 return RTEXITCODE_FAILURE;
1007 }
1008}
1009
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use